From 5f4b2acfe538ce25b248b215f9abddf35ab18e98 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Tue, 8 Nov 2005 22:52:26 +0000 Subject: [PATCH] Replacement activation code. [Don't use this yet!] --- lib/activate/activate.c | 135 ++- lib/activate/activate.h | 4 +- lib/activate/dev_manager.c | 2312 ++++++++---------------------------- lib/activate/dev_manager.h | 1 + lib/activate/targets.h | 3 + lib/error/errseg.c | 29 +- lib/log/log.h | 4 + lib/metadata/mirror.c | 6 +- lib/metadata/segtype.h | 13 +- lib/mirror/mirrored.c | 212 ++-- lib/misc/lvm-string.c | 20 +- lib/report/report.c | 18 +- lib/snapshot/snapshot.c | 4 +- lib/striped/striped.c | 47 +- lib/zero/zero.c | 23 +- man/lvs.8 | 3 +- tools/lvcreate.c | 3 +- tools/lvremove.c | 11 + 18 files changed, 753 insertions(+), 2095 deletions(-) diff --git a/lib/activate/activate.c b/lib/activate/activate.c index f15123d74..6f1af3473 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -284,10 +284,8 @@ static int _target_present(const char *target_name) struct dm_versions *target, *last_target; log_very_verbose("Getting target version for %s", target_name); - if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) { - stack; - return 0; - } + if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) + return_0; if (!dm_task_run(dmt)) { log_debug("Failed to get %s target version", target_name); @@ -314,7 +312,7 @@ static int _target_present(const char *target_name) return r; } -int target_present(const char *target_name) +int target_present(const char *target_name, int use_modprobe) { #ifdef MODPROBE_CMD char module[128]; @@ -324,17 +322,19 @@ int target_present(const char *target_name) return 0; #ifdef MODPROBE_CMD - if (_target_present(target_name)) - return 1; + if (use_modprobe) { + if (_target_present(target_name)) + return 1; - if (lvm_snprintf(module, sizeof(module), "dm-%s", target_name) < 0) { - log_error("target_present module name too long: %s", target_name); - return 0; - } + if (lvm_snprintf(module, sizeof(module), "dm-%s", target_name) + < 0) { + log_error("target_present module name too long: %s", + target_name); + return 0; + } - if (!exec_cmd(MODPROBE_CMD, module, "", "")) { - stack; - return 0; + if (!exec_cmd(MODPROBE_CMD, module, "", "")) + return_0; } #endif @@ -353,17 +353,14 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, in if (!activation()) return 0; - if (!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL))) { - stack; - return 0; - } + if (!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL))) + return_0; log_debug("Getting device info for %s", name); if (!dev_manager_info(lv->vg->cmd->mem, name, lv, with_mknodes, with_open_count, &dminfo)) { dm_pool_free(cmd->mem, name); - stack; - return 0; + return_0; } info->exists = dminfo.exists; @@ -372,6 +369,8 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, in info->major = dminfo.major; info->minor = dminfo.minor; info->read_only = dminfo.read_only; + info->live_table = dminfo.live_table; + info->inactive_table = dminfo.inactive_table; dm_pool_free(cmd->mem, name); return 1; @@ -405,10 +404,8 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent) if (!activation()) return 0; - if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { - stack; - return 0; - } + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) + return_0; if (!(r = dev_manager_snapshot_percent(dm, lv, percent))) stack; @@ -429,18 +426,14 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, int wa if (!activation()) return 0; - if (!lv_info(cmd, lv, &info, 0)) { - stack; - return 0; - } + if (!lv_info(cmd, lv, &info, 0)) + return_0; if (!info.exists) return 0; - if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { - stack; - return 0; - } + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) + return_0; if (!(r = dev_manager_mirror_percent(dm, lv, wait, percent, event_nr))) stack; @@ -474,16 +467,13 @@ static int _lv_open_count(struct cmd_context *cmd, struct logical_volume *lv) return info.open_count; } -/* FIXME Need to detect and handle an lv rename */ static int _lv_activate_lv(struct logical_volume *lv) { int r; struct dev_manager *dm; - if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { - stack; - return 0; - } + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) + return_0; if (!(r = dev_manager_activate(dm, lv))) stack; @@ -492,15 +482,28 @@ static int _lv_activate_lv(struct logical_volume *lv) return r; } -static int _lv_deactivate(struct logical_volume *lv) +static int _lv_preload(struct logical_volume *lv) { int r; struct dev_manager *dm; - if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) + return_0; + + if (!(r = dev_manager_preload(dm, lv))) stack; - return 0; - } + + dev_manager_destroy(dm); + return r; +} + +static int _lv_deactivate(struct logical_volume *lv) +{ + int r; + struct dev_manager *dm; + + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) + return_0; if (!(r = dev_manager_deactivate(dm, lv))) stack; @@ -514,10 +517,8 @@ static int _lv_suspend_lv(struct logical_volume *lv) int r; struct dev_manager *dm; - if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { - stack; - return 0; - } + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) + return_0; if (!(r = dev_manager_suspend(dm, lv))) stack; @@ -580,14 +581,20 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s, return 1; } - if (!lv_info(cmd, lv, &info, 0)) { - stack; - return 0; - } + if (!lv_info(cmd, lv, &info, 0)) + return_0; if (!info.exists || info.suspended) return error_if_not_suspended ? 0 : 1; + /* If VG was precommitted, preload devices for the LV */ + if ((lv->vg->status & PRECOMMITTED)) { + if (!_lv_preload(lv)) { + /* FIXME Revert preloading */ + return_0; + } + } + memlock_inc(); if (!_lv_suspend_lv(lv)) { memlock_dec(); @@ -626,10 +633,8 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s, return 1; } - if (!lv_info(cmd, lv, &info, 0)) { - stack; - return 0; - } + if (!lv_info(cmd, lv, &info, 0)) + return_0; if (!info.exists || !info.suspended) return error_if_not_active ? 0 : 1; @@ -671,16 +676,14 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s) return 1; } - if (!lv_info(cmd, lv, &info, 1)) { - stack; - return 0; - } + if (!lv_info(cmd, lv, &info, 1)) + return_0; if (!info.exists) return 1; if (info.open_count && (lv->status & VISIBLE_LV)) { - log_error("LV %s/%s in use: not removing", lv->vg->name, + log_error("LV %s/%s in use: not deactivating", lv->vg->name, lv->name); return 0; } @@ -741,12 +744,10 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, return 1; } - if (!lv_info(cmd, lv, &info, 0)) { - stack; - return 0; - } + if (!lv_info(cmd, lv, &info, 0)) + return_0; - if (info.exists && !info.suspended) + if (info.exists && !info.suspended && info.live_table) return 1; if (exclusive) @@ -783,10 +784,8 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv) return r; } - if (!_lv_info(cmd, lv, 1, &info, 0)) { - stack; - return 0; - } + if (!_lv_info(cmd, lv, 1, &info, 0)) + return_0; if (info.exists) r = dev_manager_lv_mknodes(lv); diff --git a/lib/activate/activate.h b/lib/activate/activate.h index bf5b8b089..c05f667da 100644 --- a/lib/activate/activate.h +++ b/lib/activate/activate.h @@ -25,6 +25,8 @@ struct lvinfo { int major; int minor; int read_only; + int live_table; + int inactive_table; }; void set_activation(int activation); @@ -34,7 +36,7 @@ int driver_version(char *version, size_t size); int library_version(char *version, size_t size); int lvm1_present(struct cmd_context *cmd); -int target_present(const char *target_name); +int target_present(const char *target_name, int use_modprobe); void activation_exit(void); diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index a41c18cc8..65527f562 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -29,88 +29,17 @@ #include #include -/* - * Algorithm - * --------- - * - * 1) Examine dm directory, and store details of active mapped devices - * in the VG. Indexed by lvid-layer. (_scan_existing_devices) - * - * 2) Build lists of visible devices that need to be left in each state: - * active, reloaded, suspended. - * - * 3) Run through these lists and set the appropriate marks on each device - * and its dependencies. - * - * 4) Add layers not marked active to remove_list for removal at the end. - * - * 5) Remove unmarked layers from core. - * - * 6) Activate remaining layers, recursing to handle dependedncies and - * skipping any that already exist unless they are marked as needing - * reloading. - * - * 7) Remove layers in the remove_list. (_remove_old_layers) - * - */ - #define MAX_TARGET_PARAMSIZE 50000 #define UUID_PREFIX "LVM-" -enum { - ACTIVE = 0, - RELOAD = 1, - VISIBLE = 2, - READWRITE = 3, - SUSPENDED = 4, - NOPROPAGATE = 5, - TOPLEVEL = 6, - REMOVE = 7, - RESUME_IMMEDIATE = 8 -}; - typedef enum { + PRELOAD, ACTIVATE, DEACTIVATE, SUSPEND, - RESUME + CLEAN } action_t; -struct dev_layer { - char *name; - - int flags; - - /* - * Setup the dm_task. - */ - int (*populate) (struct dev_manager * dm, - struct dm_task * dmt, struct dev_layer * dl); - struct dm_info info; - - /* lvid plus layer */ - char *dlid; - - struct logical_volume *lv; - - /* - * Devices that must be created before this one can be created. - * Reloads get propagated to this list. Holds str_lists. - */ - struct list pre_create; - - /* Inverse of pre_create */ - struct list pre_suspend; - -}; - -struct dl_list { - struct list list; - struct dev_layer *dl; -}; - -static const char *stripe_filler = NULL; - struct dev_manager { struct dm_pool *mem; @@ -121,48 +50,14 @@ struct dev_manager { uint32_t pvmove_mirror_count; char *vg_name; - - /* - * list of struct lv_list, contains lvs that we wish to - * be active after execution. - */ - struct list active_list; - - /* - * Layers that need reloading. - */ - struct list reload_list; - - /* - * Layers that need suspending. - */ - struct list suspend_list; - - /* - * Layers that will need removing after activation. - */ - struct list remove_list; - - struct dm_hash_table *layers; }; -/* - * Functions to manage the flags. - */ -static inline int _get_flag(struct dev_layer *dl, int bit) -{ - return (dl->flags & (1 << bit)) ? 1 : 0; -} - -static inline void _set_flag(struct dev_layer *dl, int bit) -{ - dl->flags |= (1 << bit); -} +struct lv_layer { + struct logical_volume *lv; + const char *old_name; +}; -static inline void _clear_flag(struct dev_layer *dl, int bit) -{ - dl->flags &= ~(1 << bit); -} +static const char *stripe_filler = NULL; static char *_build_dlid(struct dm_pool *mem, const char *lvid, const char *layer) { @@ -175,7 +70,8 @@ static char *_build_dlid(struct dm_pool *mem, const char *lvid, const char *laye len = sizeof(UUID_PREFIX) + sizeof(union lvid) + strlen(layer); if (!(dlid = dm_pool_alloc(mem, len))) { - stack; + log_error("_build_dlid: pool allocation failed for %" PRIsize_t + " %s %s.", len, lvid, layer); return NULL; } @@ -189,6 +85,11 @@ char *build_dlid(struct dev_manager *dm, const char *lvid, const char *layer) return _build_dlid(dm->mem, lvid, layer); } +static inline int _read_only_lv(struct logical_volume *lv) +{ + return (!(lv->vg->status & LVM_WRITE) || !(lv->status & LVM_WRITE)); +} + /* * Low level device-layer operations. */ @@ -234,21 +135,15 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info, if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); - if (!dm_task_run(dmt)) { - stack; - goto out; - } + if (!dm_task_run(dmt)) + goto_out; - if (!dm_task_get_info(dmt, info)) { - stack; - goto out; - } + if (!dm_task_get_info(dmt, info)) + goto_out; if (info->exists && uuid_out) { - if (!(u = dm_task_get_uuid(dmt))) { - stack; - goto out; - } + if (!(u = dm_task_get_uuid(dmt))) + goto_out; *uuid_out = dm_pool_strdup(mem, u); } r = 1; @@ -316,15 +211,11 @@ static int _status_run(const char *name, const char *uuid, if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); - if (!dm_task_run(dmt)) { - stack; - goto out; - } + if (!dm_task_run(dmt)) + goto_out; - if (!dm_task_get_info(dmt, &info) || !info.exists) { - stack; - goto out; - } + if (!dm_task_get_info(dmt, &info) || !info.exists) + goto_out; do { next = dm_get_next_target(dmt, next, &start, &length, @@ -409,15 +300,11 @@ static int _percent_run(struct dev_manager *dm, const char *name, if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); - if (!dm_task_run(dmt)) { - stack; - goto out; - } + if (!dm_task_run(dmt)) + goto_out; - if (!dm_task_get_info(dmt, &info) || !info.exists) { - stack; - goto out; - } + if (!dm_task_get_info(dmt, &info) || !info.exists) + goto_out; if (event_nr) *event_nr = info.event_nr; @@ -445,10 +332,8 @@ static int _percent_run(struct dev_manager *dm, const char *name, dm->cmd->cft, seg, params, &total_numerator, &total_denominator, - percent)) { - stack; - goto out; - } + percent)) + goto_out; } while (next); @@ -493,1528 +378,164 @@ static int _percent(struct dev_manager *dm, const char *name, const char *dlid, return 0; } -static int _rename(struct dev_manager *dm, struct dev_layer *dl, char *newname) +/* + * dev_manager implementation. + */ +struct dev_manager *dev_manager_create(struct cmd_context *cmd, + const char *vg_name) { - int r = 1; - struct dm_task *dmt; - char *vgname, *lvname, *layer; - - if (!split_dm_name(dm->mem, dl->name, &vgname, &lvname, &layer)) { - log_error("Couldn't split up dm layer name %s", dl->name); - return 0; - } - - log_verbose("Renaming %s to %s", dl->name, newname); + struct dm_pool *mem; + struct dev_manager *dm; - if (!(dmt = _setup_task(dl->name, NULL, 0, DM_DEVICE_RENAME))) { + if (!(mem = dm_pool_create("dev_manager", 16 * 1024))) { stack; - return 0; + return NULL; } - if (!dm_task_set_newname(dmt, newname)) { + if (!(dm = dm_pool_alloc(mem, sizeof(*dm)))) { stack; - r = 0; - goto out; + goto bad; } - if (!dm_task_no_open_count(dmt)) - log_error("Failed to disable open_count"); + dm->cmd = cmd; + dm->mem = mem; - if (!(r = dm_task_run(dmt))) { - log_error("Couldn't rename device '%s'.", dl->name); - goto out; + if (!stripe_filler) { + stripe_filler = find_config_str(cmd->cft->root, + "activation/missing_stripe_filler", + DEFAULT_STRIPE_FILLER); } + dm->stripe_filler = stripe_filler; - if (r && _get_flag(dl, VISIBLE)) - fs_rename_lv(dl->lv, newname, lvname); - - dl->name = newname; - - out: - dm_task_destroy(dmt); - return r; -} - -static int _suspend_or_resume(const char *name, action_t suspend) -{ - int r; - struct dm_task *dmt; - int sus = (suspend == SUSPEND) ? 1 : 0; - int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME; - - log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name); - if (!(dmt = _setup_task(name, NULL, 0, task))) { + if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name))) { stack; - return 0; + goto bad; } - if (!dm_task_no_open_count(dmt)) - log_error("Failed to disable open_count"); + dm->target_state = NULL; - if (!(r = dm_task_run(dmt))) - log_error("Couldn't %s device '%s'", sus ? "suspend" : "resume", - name); + return dm; - dm_task_destroy(dmt); - return r; + bad: + dm_pool_destroy(mem); + return NULL; } -static int _suspend(struct dev_layer *dl) +void dev_manager_destroy(struct dev_manager *dm) { - if (!dl->info.exists || dl->info.suspended) - return 1; - - if (!_suspend_or_resume(dl->name, SUSPEND)) { - stack; - return 0; - } + dm_pool_destroy(dm->mem); +} - dl->info.suspended = 1; - return 1; +void dev_manager_exit(void) +{ + dm_lib_exit(); } -static int _resume(struct dev_layer *dl) +int dev_manager_snapshot_percent(struct dev_manager *dm, + struct logical_volume *lv, float *percent) { - if (!dl->info.exists || !dl->info.suspended) - return 1; + char *name; + const char *dlid; + + /* + * Build a name for the top layer. + */ + if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) + return_0; + + if (!(dlid = build_dlid(dm, lv->lvid.s, NULL))) + return_0; - if (!_suspend_or_resume(dl->name, RESUME)) { + /* + * Try and get some info on this device. + */ + log_debug("Getting device status percentage for %s", name); + if (!(_percent(dm, name, dlid, "snapshot", 0, NULL, percent, + NULL))) { stack; return 0; } - dl->info.suspended = 0; + /* FIXME dm_pool_free ? */ + + /* If the snapshot isn't available, percent will be -1 */ return 1; } -static int _load(struct dev_manager *dm, struct dev_layer *dl, int task) +/* FIXME Merge with snapshot_percent, auto-detecting target type */ +/* FIXME Cope with more than one target */ +int dev_manager_mirror_percent(struct dev_manager *dm, + struct logical_volume *lv, int wait, + float *percent, uint32_t *event_nr) { - int r = 1; - struct dm_task *dmt; - - log_verbose("Loading %s", dl->name); - if (!(dmt = _setup_task(task == DM_DEVICE_CREATE ? dl->name : NULL, - dl->dlid, 0, task))) { - stack; - return 0; - } - - /* - * Populate the table. - */ - if (!dl->populate(dm, dmt, dl)) { - log_error("Couldn't populate device '%s'.", dl->name); - r = 0; - goto out; - } + char *name; + const char *dlid; /* - * Do we want a specific device number ? + * Build a name for the top layer. */ - if (dl->lv->major >= 0 && _get_flag(dl, VISIBLE)) { - if (!dm_task_set_major(dmt, dl->lv->major)) { - log_error("Failed to set major number for %s to %d " - "during activation.", dl->name, - dl->lv->major); - goto out; - } else - log_very_verbose("Set major number for %s to %d.", - dl->name, dl->lv->major); - } - - if (dl->lv->minor >= 0 && _get_flag(dl, VISIBLE)) { - if (!dm_task_set_minor(dmt, dl->lv->minor)) { - log_error("Failed to set minor number for %s to %d " - "during activation.", dl->name, - dl->lv->minor); - goto out; - } else - log_very_verbose("Set minor number for %s to %d.", - dl->name, dl->lv->minor); - } - - if (!_get_flag(dl, READWRITE)) { - if (!dm_task_set_ro(dmt)) { - log_error("Failed to set %s read-only during " - "activation.", dl->name); - goto out; - } else - log_very_verbose("Activating %s read-only", dl->name); - } + if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) + return_0; - if (!dm_task_no_open_count(dmt)) - log_error("Failed to disable open_count"); + /* FIXME dm_pool_free ? */ - if (!(r = dm_task_run(dmt))) { - log_error("Couldn't load device '%s'.", dl->name); - if ((dl->lv->minor >= 0 || dl->lv->major >= 0) && - _get_flag(dl, VISIBLE)) - log_error("Perhaps the persistent device number " - "%d:%d is already in use?", - dl->lv->major, dl->lv->minor); + if (!(dlid = build_dlid(dm, lv->lvid.s, NULL))) { + log_error("dlid build failed for %s", lv->name); + return 0; } - if (!dm_task_get_info(dmt, &dl->info)) { + log_debug("Getting device mirror status percentage for %s", name); + if (!(_percent(dm, name, dlid, "mirror", wait, lv, percent, + event_nr))) { stack; - r = 0; - goto out; + return 0; } - if (!dl->info.exists || !dl->info.live_table) { - stack; - r = 0; - goto out; - } + return 1; +} - if (_get_flag(dl, RESUME_IMMEDIATE) && dl->info.suspended && - !_resume(dl)) { - stack; - r = 0; - goto out; - } +#if 0 + log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name); + log_verbose("Loading %s", dl->name); + log_very_verbose("Activating %s read-only", dl->name); log_very_verbose("Activated %s %s %03u:%03u", dl->name, dl->dlid, dl->info.major, dl->info.minor); - if (r && _get_flag(dl, VISIBLE)) - fs_add_lv(dl->lv, dl->name); - - _clear_flag(dl, RELOAD); - - out: - dm_task_destroy(dmt); - return r; -} - -static int _remove(struct dev_layer *dl) -{ - int r; - struct dm_task *dmt; - if (_get_flag(dl, VISIBLE)) log_verbose("Removing %s", dl->name); else log_very_verbose("Removing %s", dl->name); - if (!(dmt = _setup_task(dl->name, NULL, 0, DM_DEVICE_REMOVE))) { - stack; - return 0; - } + log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s", + extent_size * seg->le, extent_size * seg->len, target, params); - if (!dm_task_no_open_count(dmt)) - log_error("Failed to disable open_count"); + log_debug("Adding target: 0 %" PRIu64 " snapshot-origin %s", + dl->lv->size, params); + log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params); + log_debug("Getting device info for %s", dl->name); - /* Suppress error message if it's still in use - we'll log it later */ - log_suppress(1); + /* Rename? */ + if ((suffix = rindex(dl->dlid + sizeof(UUID_PREFIX) - 1, '-'))) + suffix++; + newname = build_dm_name(dm->mem, dm->vg_name, dl->lv->name, + suffix); - if ((r = dm_task_run(dmt))) - dl->info.exists = 0; +static int _belong_to_vg(const char *vgname, const char *name) +{ + const char *v = vgname, *n = name; - log_suppress(0); - - dm_task_destroy(dmt); - - if (r && _get_flag(dl, VISIBLE)) - fs_del_lv(dl->lv); - - _clear_flag(dl, ACTIVE); - - return r; -} - -/* - * The functions that populate the table in a dm_task as part of - * a create/reload. - */ - -/* - * Emit a target for a given segment. - * FIXME: tidy this function. - */ -static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt, - struct lv_segment *seg, char *params, - size_t paramsize) -{ - uint64_t esize = seg->lv->vg->extent_size; - int w = 0; - const char *target = NULL; - int r; - - if (!seg->segtype->ops->compose_target_line) { - log_error("_emit_target: Internal error: Can't handle " - "segment type %s", seg->segtype->name); - return 0; - } - - if ((r = seg->segtype->ops->compose_target_line(dm, dm->mem, - dm->cmd->cft, - &dm->target_state, seg, - params, paramsize, - &target, &w, - &dm-> - pvmove_mirror_count)) <= - 0) { - stack; - return r; - } - - log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s", - esize * seg->le, esize * seg->len, target, params); - - if (!dm_task_add_target(dmt, esize * seg->le, esize * seg->len, - target, params)) { - stack; - return 0; - } - - return 1; -} - -int build_dev_string(struct dev_manager *dm, char *dlid, char *devbuf, - size_t bufsize, const char *desc) -{ - struct dev_layer *dl; - - if (!(dl = dm_hash_lookup(dm->layers, dlid))) { - log_error("%s device layer %s missing from hash", - desc, dlid); - return 0; - } - - if (!dm_format_dev(devbuf, bufsize, dl->info.major, - dl->info.minor)) { - log_error("Failed to format %s device number for %s as dm " - "target (%u,%u)", - desc, dlid, dl->info.major, dl->info.minor); - return 0; - } - - return 1; -} - -int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, - char *params, size_t paramsize, int *pos, int start_area, - int areas) -{ - uint32_t s; - int tw = 0; - const char *trailing_space; - uint64_t esize = seg->lv->vg->extent_size; - char devbuf[10]; - char *dlid; - - for (s = start_area; s < areas; s++, *pos += tw) { - trailing_space = (areas - s - 1) ? " " : ""; - if ((seg_type(seg, s) == AREA_PV && - (!seg_pvseg(seg, s) || - !seg_pv(seg, s) || - !seg_dev(seg, s))) || - (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s))) - tw = lvm_snprintf(params + *pos, paramsize - *pos, - "%s 0%s", dm->stripe_filler, - trailing_space); - else if (seg_type(seg, s) == AREA_PV) - tw = lvm_snprintf(params + *pos, paramsize - *pos, - "%s %" PRIu64 "%s", - dev_name(seg_dev(seg, s)), - (seg_pv(seg, s)->pe_start + - (esize * seg_pe(seg, s))), - trailing_space); - else if (seg_type(seg, s) == AREA_LV) { - if (!(dlid = _build_dlid(dm->mem, - seg_lv(seg, s)->lvid.s, NULL))) { - stack; - return 0; - } - if (!build_dev_string(dm, dlid, - devbuf,sizeof(devbuf), "LV")) { - stack; - return 0; - } - tw = lvm_snprintf(params + *pos, paramsize - *pos, - "%s %" PRIu64 "%s", devbuf, - esize * seg_le(seg, s), - trailing_space); - } else { - log_error("Internal error: Unassigned area found in LV %s.", - seg->lv->name); - return 0; - } - - if (tw < 0) { - stack; - return -1; - } - } - - return 1; -} - -static int _emit_target(struct dev_manager *dm, struct dm_task *dmt, - struct lv_segment *seg) -{ - char *params; - size_t paramsize = 4096; - int ret; - - do { - if (!(params = dm_malloc(paramsize))) { - log_error("Insufficient space for target parameters."); - return 0; - } - - ret = _emit_target_line(dm, dmt, seg, params, paramsize); - dm_free(params); - - if (!ret) - stack; - - if (ret >= 0) - return ret; - - log_debug("Insufficient space in params[%" PRIsize_t - "] for target parameters.", paramsize); - - paramsize *= 2; - } while (paramsize < MAX_TARGET_PARAMSIZE); - - log_error("Target parameter size too big. Aborting."); - return 0; -} - -static int _populate_vanilla(struct dev_manager *dm, - struct dm_task *dmt, struct dev_layer *dl) -{ - struct lv_segment *seg; - struct logical_volume *lv = dl->lv; - - dm->pvmove_mirror_count = 0u; - - list_iterate_items(seg, &lv->segments) { - if (!_emit_target(dm, dmt, seg)) { - log_error("Unable to build table for '%s'", lv->name); - return 0; - } - } - - return 1; -} - -static int _populate_origin(struct dev_manager *dm, - struct dm_task *dmt, struct dev_layer *dl) -{ - char *real; - char params[PATH_MAX + 32]; - - if (!(real = _build_dlid(dm->mem, dl->lv->lvid.s, "real"))) { - stack; - return 0; - } - - if (!build_dev_string(dm, real, params, sizeof(params), "origin")) { - stack; - return 0; - } - - log_debug("Adding target: 0 %" PRIu64 " snapshot-origin %s", - dl->lv->size, params); - if (!dm_task_add_target(dmt, UINT64_C(0), dl->lv->size, - "snapshot-origin", params)) { - stack; - return 0; - } - - return 1; -} - -static int _populate_snapshot(struct dev_manager *dm, - struct dm_task *dmt, struct dev_layer *dl) -{ - char *origin, *cow; - char params[PATH_MAX * 2 + 32]; - struct lv_segment *snap_seg; - char devbufo[10], devbufc[10]; - uint64_t size; - - if (!(snap_seg = find_cow(dl->lv))) { - log_error("Couldn't find snapshot for '%s'.", dl->lv->name); - return 0; - } - - if (!(origin = _build_dlid(dm->mem, snap_seg->origin->lvid.s, - "real"))) { - stack; - return 0; - } - - if (!(cow = _build_dlid(dm->mem, snap_seg->cow->lvid.s, "cow"))) { - stack; - return 0; - } - - if (!build_dev_string(dm, origin, devbufo, sizeof(devbufo), "origin")) { - stack; - return 0; - } - - if (!build_dev_string(dm, cow, devbufc, sizeof(devbufc), "cow")) { - stack; - return 0; - } - - if (lvm_snprintf(params, sizeof(params), "%s %s P %d", - devbufo, devbufc, snap_seg->chunk_size) == -1) { - stack; - return 0; - } - - size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size; - - log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params); - if (!dm_task_add_target(dmt, UINT64_C(0), size, "snapshot", params)) { - stack; - return 0; - } - - return 1; -} - -/* - * dev_manager implementation. - */ -struct dev_manager *dev_manager_create(struct cmd_context *cmd, - const char *vg_name) -{ - struct dm_pool *mem; - struct dev_manager *dm; - - if (!(mem = dm_pool_create("dev_manager", 16 * 1024))) { - stack; - return NULL; - } - - if (!(dm = dm_pool_alloc(mem, sizeof(*dm)))) { - stack; - goto bad; - } - - dm->cmd = cmd; - dm->mem = mem; - - if (!stripe_filler) { - stripe_filler = find_config_str(cmd->cft->root, - "activation/missing_stripe_filler", - DEFAULT_STRIPE_FILLER); - } - dm->stripe_filler = stripe_filler; - - if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name))) { - stack; - goto bad; - } - - if (!(dm->layers = dm_hash_create(32))) { - stack; - goto bad; - } - - list_init(&dm->active_list); - list_init(&dm->reload_list); - list_init(&dm->remove_list); - list_init(&dm->suspend_list); - - dm->target_state = NULL; - - return dm; - - bad: - dm_pool_destroy(mem); - return NULL; -} - -void dev_manager_destroy(struct dev_manager *dm) -{ - dm_hash_destroy(dm->layers); - dm_pool_destroy(dm->mem); -} - -int dev_manager_snapshot_percent(struct dev_manager *dm, - struct logical_volume *lv, float *percent) -{ - char *name; - const char *dlid; - - /* - * Build a name for the top layer. - */ - if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) { - stack; - return 0; - } - - if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) { - stack; - return 0; - } - - /* - * Try and get some info on this device. - */ - log_debug("Getting device status percentage for %s", name); - if (!(_percent(dm, name, dlid, "snapshot", 0, NULL, percent, - NULL))) { - stack; - return 0; - } - - /* FIXME dm_pool_free ? */ - - /* If the snapshot isn't available, percent will be -1 */ - return 1; -} - -/* FIXME Merge with snapshot_percent, auto-detecting target type */ -/* FIXME Cope with more than one target */ -int dev_manager_mirror_percent(struct dev_manager *dm, - struct logical_volume *lv, int wait, - float *percent, uint32_t *event_nr) -{ - char *name; - const char *dlid; - - /* - * Build a name for the top layer. - */ - if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) { - stack; - return 0; - } - - /* FIXME dm_pool_free ? */ - - if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) { - log_error("dlid build failed for %s", lv->name); - return 0; - } - - log_debug("Getting device mirror status percentage for %s", name); - if (!(_percent(dm, name, dlid, "mirror", wait, lv, percent, - event_nr))) { - stack; - return 0; - } - - return 1; -} - -static struct dev_layer *_create_dev(struct dev_manager *dm, char *name, - char *dlid) -{ - struct dev_layer *dl; - char *uuid; - - if (!(dl = dm_pool_zalloc(dm->mem, sizeof(*dl)))) { - stack; - return NULL; - } - - dl->name = name; - - log_debug("Getting device info for %s", dl->name); - if (!_info(dl->name, dlid, 0, 0, &dl->info, dm->mem, &uuid)) { - stack; - return NULL; - } - - if (dl->info.exists) { - /* If old-style UUID found, convert it. */ - if (strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1)) { - if (!(dl->dlid = dm_pool_alloc(dm->mem, sizeof(UUID_PREFIX) + strlen(uuid)))) { - stack; - return NULL; - } - memcpy(dl->dlid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1); - memcpy(dl->dlid + sizeof(UUID_PREFIX) - 1, uuid, strlen(uuid)); - } else - dl->dlid = uuid; - } else - dl->dlid = dlid; - - list_init(&dl->pre_create); - list_init(&dl->pre_suspend); - - if (!dm_hash_insert(dm->layers, dl->dlid, dl)) { - stack; - return NULL; - } - - return dl; -} - -static inline int _read_only_lv(struct logical_volume *lv) -{ - return (!(lv->vg->status & LVM_WRITE) || !(lv->status & LVM_WRITE)); -} - -static struct dev_layer *_create_layer(struct dev_manager *dm, - const char *layer, - struct logical_volume *lv) -{ - char *name, *dlid; - struct dev_layer *dl; - - if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) { - stack; - return NULL; - } - - if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, layer))) { - stack; - return NULL; - } - - if (!(dl = dm_hash_lookup(dm->layers, dlid)) && - !(dl = _create_dev(dm, name, dlid))) { - stack; - return NULL; - } - - dl->lv = lv; - - if (!_read_only_lv(lv)) - _set_flag(dl, READWRITE); - - return dl; -} - -static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv, - int was_origin) -{ - /* - * only one layer. - */ - struct dev_layer *dl, *dlr; - struct lv_segment *seg; - uint32_t s; - - if (!(dl = _create_layer(dm, NULL, lv))) { - stack; - return 0; - } - dl->populate = _populate_vanilla; - if (lv->status & VISIBLE_LV) { - _set_flag(dl, VISIBLE); - _set_flag(dl, TOPLEVEL); - } - - if (lv->status & PVMOVE) - _set_flag(dl, TOPLEVEL); - - /* Add dependencies for any LVs that segments refer to */ - list_iterate_items(seg, &lv->segments) { - // When do we need? _set_flag(dl, REMOVE) on the log? - if (seg->log_lv && - !str_list_add(dm->mem, &dl->pre_create, - _build_dlid(dm->mem, seg->log_lv->lvid.s, - NULL))) { - stack; - return 0; - } - - for (s = 0; s < seg->area_count; s++) { - if (seg_type(seg, s) != AREA_LV) - continue; - if (!str_list_add(dm->mem, &dl->pre_create, - _build_dlid(dm->mem, - seg_lv(seg, s)-> - lvid.s, NULL))) { - stack; - return 0; - } - - // ? if (seg_lv(seg, s)->status & PVMOVE) - _set_flag(dl, NOPROPAGATE); - // When do we need? _set_flag(dl, REMOVE) - } - } - - if (!was_origin) - return 1; - - /* Deactivating the last snapshot */ - if (!(dlr = _create_layer(dm, "real", lv))) { - stack; - return 0; - } - - dlr->populate = _populate_vanilla; - _clear_flag(dlr, VISIBLE); - _clear_flag(dlr, TOPLEVEL); - _set_flag(dlr, REMOVE); - - /* add the dependency on the real device */ - if (!str_list_add(dm->mem, &dl->pre_create, - dm_pool_strdup(dm->mem, dlr->dlid))) { - stack; - return 0; - } - - return 1; -} - -static int _expand_origin_real(struct dev_manager *dm, - struct logical_volume *lv) -{ - struct dev_layer *dl; - const char *real_dlid; - - if (!(dl = _create_layer(dm, "real", lv))) { - stack; - return 0; - } - dl->populate = _populate_vanilla; - _clear_flag(dl, VISIBLE); - _clear_flag(dl, TOPLEVEL); - - /* Size changes must take effect before tables using it are reloaded */ - _set_flag(dl, RESUME_IMMEDIATE); - - real_dlid = dl->dlid; - - if (!(dl = _create_layer(dm, NULL, lv))) { - stack; - return 0; - } - dl->populate = _populate_origin; - _set_flag(dl, VISIBLE); - _set_flag(dl, TOPLEVEL); - - /* add the dependency on the real device */ - if (!str_list_add(dm->mem, &dl->pre_create, - dm_pool_strdup(dm->mem, real_dlid))) { - stack; - return 0; - } - - return 1; -} - -static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv) -{ - struct logical_volume *active; - struct lv_segment *snap_seg; - struct lv_list *lvl; - - /* - * We only need to create an origin layer if one of our - * snapshots is in the active list - */ - list_iterate_items(lvl, &dm->active_list) { - active = lvl->lv; - if ((snap_seg = find_cow(active)) && (snap_seg->origin == lv)) - return _expand_origin_real(dm, lv); - } - - /* - * We're deactivating the last snapshot - */ - return _expand_vanilla(dm, lv, 1); -} - -static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv, - struct lv_segment *snap_seg) -{ - /* - * snapshot(org, cow) - * cow - */ - struct dev_layer *dl; - const char *cow_dlid; - - if (!(dl = _create_layer(dm, "cow", lv))) { - stack; - return 0; - } - dl->populate = _populate_vanilla; - _clear_flag(dl, VISIBLE); - _clear_flag(dl, TOPLEVEL); - _set_flag(dl, READWRITE); - - cow_dlid = dl->dlid; - - if (!(dl = _create_layer(dm, NULL, lv))) { - stack; - return 0; - } - dl->populate = _populate_snapshot; - _set_flag(dl, VISIBLE); - _set_flag(dl, TOPLEVEL); - - /* add the dependency on the cow device */ - if (!str_list_add(dm->mem, &dl->pre_create, - dm_pool_strdup(dm->mem, cow_dlid))) { - stack; - return 0; - } - - /* add the dependency on the real origin device */ - if (!str_list_add(dm->mem, &dl->pre_create, - _build_dlid(dm->mem, snap_seg->origin->lvid.s, - "real"))) { - stack; - return 0; - } - - /* add the dependency on the visible origin device */ - if (!str_list_add(dm->mem, &dl->pre_suspend, - _build_dlid(dm->mem, snap_seg->origin->lvid.s, - NULL))) { - stack; - return 0; - } - - return 1; -} - -/* - * Inserts the appropriate dev_layers for a logical volume. - */ -static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv) -{ - struct lv_segment *snap_seg; - - /* - * FIXME: this doesn't cope with recursive snapshots yet. - */ - if ((snap_seg = find_cow(lv))) { - if (lv->vg->status & CLUSTERED) { - log_error("Clustered snapshots are not yet supported"); - return 0; - } - return _expand_snapshot(dm, lv, snap_seg); - } else if (lv_is_origin(lv)) { - if (lv->vg->status & CLUSTERED) { - log_error("Clustered snapshots are not yet supported"); - return 0; - } - return _expand_origin(dm, lv); - } - - return _expand_vanilla(dm, lv, 0); -} - -/* - * Clears the mark bit on all layers. - */ -static void _clear_marks(struct dev_manager *dm, int flag) -{ - struct dm_hash_node *hn; - struct dev_layer *dl; - - dm_hash_iterate(hn, dm->layers) { - dl = dm_hash_get_data(dm->layers, hn); - _clear_flag(dl, flag); - } -} - -/* - * Propogates marks via the pre_create dependency list. - */ -static int _trace_layer_marks(struct dev_manager *dm, struct dev_layer *dl, - int flag) -{ - struct str_list *strl; - const char *dlid; - struct dev_layer *dep; - - list_iterate_items(strl, &dl->pre_create) { - dlid = strl->str; - - if (!(dep = dm_hash_lookup(dm->layers, dlid))) { - log_error("Couldn't find device layer '%s'.", dlid); - return 0; - } - - if (_get_flag(dep, flag)) - continue; - - /* FIXME Only propagate LV ACTIVE dependencies for now */ - if ((flag != ACTIVE) && _get_flag(dl, NOPROPAGATE)) - continue; - - _set_flag(dep, flag); - - if (!_trace_layer_marks(dm, dep, flag)) { - stack; - return 0; - } - } - - return 1; -} - -/* - * Calls _trace_single for every marked layer. - */ -static int _trace_all_marks(struct dev_manager *dm, int flag) -{ - struct dm_hash_node *hn; - struct dev_layer *dl; - - dm_hash_iterate(hn, dm->layers) { - dl = dm_hash_get_data(dm->layers, hn); - if (_get_flag(dl, flag) && !_trace_layer_marks(dm, dl, flag)) { - stack; - return 0; - } - } - - return 1; -} - -/* - * Finds the specified layer. - */ -static struct dev_layer *_lookup(struct dev_manager *dm, - const char *lvid, const char *layer) -{ - char *dlid; - struct dev_layer *dl; - - if (!(dlid = _build_dlid(dm->mem, lvid, layer))) { - stack; - return NULL; - } - - dl = dm_hash_lookup(dm->layers, dlid); - dm_pool_free(dm->mem, dlid); - return dl; -} - -/* - * Marks the top layers, then traces these through the - * dependencies. - */ -static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag) -{ - struct lv_list *lvl; - struct dev_layer *dl; - - list_iterate_items(lvl, lvs) { - if (lvl->lv->status & SNAPSHOT) - continue; - - if (!(dl = _lookup(dm, lvl->lv->lvid.s, NULL))) { - stack; - return 0; - } - - _set_flag(dl, flag); - } - - if (!_trace_all_marks(dm, flag)) { - stack; - return 0; - } - - return 1; -} - -static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl) -{ - struct str_list *strl; - struct dev_layer *dep; - const char *dlid; - - list_iterate_items(strl, &dl->pre_suspend) { - dlid = strl->str; - - if (!(dep = dm_hash_lookup(dm->layers, dlid))) { - log_debug("_suspend_parents couldn't find device " - "layer '%s' - skipping.", dlid); - continue; - } - - if (!strcmp(dep->dlid, dl->dlid)) { - log_error("BUG: pre-suspend loop detected (%s)", dlid); - return 0; - } - - if (!_suspend_parents(dm, dep)) { - stack; - return 0; - } - - if (dep->info.exists & !_suspend(dep)) { - stack; - return 0; - } - } - - return 1; -} - -static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl) -{ - struct str_list *strl; - struct dev_layer *dep; - const char *dlid; - - list_iterate_items(strl, &dl->pre_create) { - dlid = strl->str; - - if (!(dep = dm_hash_lookup(dm->layers, dlid))) { - log_debug("_resume_with_deps couldn't find device " - "layer '%s' - skipping.", dlid); - continue; - } - - if (!strcmp(dep->dlid, dl->dlid)) { - log_error("BUG: pre-create loop detected (%s)", dlid); - return 0; - } - - if (!_resume_with_deps(dm, dep)) { - stack; - return 0; - } - } - - if (dl->info.exists & !_get_flag(dl, SUSPENDED) && !_resume(dl)) { - stack; - return 0; - } - - return 1; -} - -/* - * Recurses through the tree, ensuring that devices are created - * in correct order. - */ -static int _create_rec(struct dev_manager *dm, struct dev_layer *dl) -{ - struct str_list *strl; - struct dev_layer *dep; - const char *dlid; - char *newname, *suffix; - - /* Suspend? */ - if (_get_flag(dl, SUSPENDED) && - (!_suspend_parents(dm, dl) || !_suspend(dl))) { - stack; - return 0; - } - - list_iterate_items(strl, &dl->pre_create) { - dlid = strl->str; - - if (!(dep = dm_hash_lookup(dm->layers, dlid))) { - log_error("Couldn't find device layer '%s'.", dlid); - return 0; - } - - if (!strcmp(dep->dlid, dl->dlid)) { - log_error("BUG: pre-create loop detected (%s)", dlid); - return 0; - } - - if (!_create_rec(dm, dep)) { - stack; - return 0; - } - } - - /* Rename? */ - if (dl->info.exists) { - if ((suffix = rindex(dl->dlid + sizeof(UUID_PREFIX) - 1, '-'))) - suffix++; - newname = build_dm_name(dm->mem, dm->vg_name, dl->lv->name, - suffix); - if (strcmp(newname, dl->name)) { - if (!_suspend_parents(dm, dl) || - !_suspend(dl) || !_rename(dm, dl, newname)) { - stack; - return 0; - } - } - } - - /* Create? */ - if (!dl->info.exists) { - if (!_suspend_parents(dm, dl) || - !_load(dm, dl, DM_DEVICE_CREATE)) { - stack; - return 0; - } - return 1; - } - - /* Reload? */ - if (_get_flag(dl, RELOAD) && - (!_suspend_parents(dm, dl) || !_suspend(dl) || - !_load(dm, dl, DM_DEVICE_RELOAD))) { - stack; - return 0; - } - - return 1; -} - -static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg) -{ - struct lv_list *lvl; - - /* - * Build layers for complete vg. - */ - list_iterate_items(lvl, &vg->lvs) { - if (lvl->lv->status & SNAPSHOT) - continue; - if (!_expand_lv(dm, lvl->lv)) { - stack; - return 0; - } - } - - return 1; -} - -static int _fill_in_remove_list(struct dev_manager *dm) -{ - struct dm_hash_node *hn; - struct dev_layer *dl; - struct dl_list *dll; - - dm_hash_iterate(hn, dm->layers) { - dl = dm_hash_get_data(dm->layers, hn); - - if (_get_flag(dl, REMOVE)) - _clear_flag(dl, ACTIVE); - - if (!_get_flag(dl, ACTIVE)) { - dll = dm_pool_alloc(dm->mem, sizeof(*dll)); - if (!dll) { - stack; - return 0; - } - - dll->dl = dl; - list_add(&dm->remove_list, &dll->list); - } - } - - return 1; -} - -static int _populate_pre_suspend_lists(struct dev_manager *dm) -{ - struct dm_hash_node *hn; - struct dev_layer *dl; - struct str_list *strl; - const char *dlid; - struct dev_layer *dep; - - dm_hash_iterate(hn, dm->layers) { - dl = dm_hash_get_data(dm->layers, hn); - - list_iterate_items(strl, &dl->pre_suspend) { - dlid = strl->str; - - if (!(dep = dm_hash_lookup(dm->layers, dlid))) { - log_debug("_populate_pre_suspend_lists: " - "Couldn't find device layer '%s' - " - "skipping.", dlid); - continue; - } - - if (!str_list_add(dm->mem, &dep->pre_create, dl->dlid)) { - stack; - return 0; - } - } - - list_iterate_items(strl, &dl->pre_create) { - dlid = strl->str; - - if (!(dep = dm_hash_lookup(dm->layers, dlid))) { - log_debug("_populate_pre_suspend_lists: " - "Couldn't find device layer '%s' - " - "skipping.", dlid); - continue; - } - - if (!str_list_add(dm->mem, &dep->pre_suspend, dl->dlid)) { - stack; - return 0; - } - } - } - - return 1; -} - -/* - * Layers are removed in a top-down manner. - */ -static int _remove_old_layers(struct dev_manager *dm) -{ - int change; - struct dl_list *dll; - struct list *rh, *n; - struct dev_layer *dl; - - do { - change = 0; - list_iterate_safe(rh, n, &dm->remove_list) { - dl = list_item(rh, struct dl_list)->dl; - - if (!dl->info.exists) { - list_del(rh); - continue; - } - - if (_remove(dl)) { - change = 1; - list_del(rh); - } - } - - } while (change); - - if (!list_empty(&dm->remove_list)) { - list_iterate_items(dll, &dm->remove_list) - log_error("Couldn't deactivate device %s", dll->dl->name); - return 0; - } - - return 1; -} - -/* - * The guts of the activation unit, this examines the device - * layers in the manager, and tries to issue the correct - * instructions to activate them in order. - */ -static int _execute(struct dev_manager *dm, struct volume_group *vg) -{ - struct dm_hash_node *hn; - struct dev_layer *dl; - - if (!_build_all_layers(dm, vg)) { - stack; - return 0; - } - - /* - * Mark all layer that need reloading. - */ - _clear_marks(dm, RELOAD); - if (!_mark_lvs(dm, &dm->reload_list, RELOAD)) { - stack; - return 0; - } - - /* - * Mark all layers that should be active. - */ - _clear_marks(dm, ACTIVE); - if (!_mark_lvs(dm, &dm->active_list, ACTIVE)) { - stack; - return 0; - } - - /* - * Mark all layers that should be left suspended. - */ - _clear_marks(dm, SUSPENDED); - if (!_mark_lvs(dm, &dm->suspend_list, SUSPENDED)) { - stack; - return 0; - } - - if (!_fill_in_remove_list(dm)) { - stack; - return 0; - } - - if (!_populate_pre_suspend_lists(dm)) { - stack; - return 0; - } - - /* - * Now only top level devices will be unmarked. - */ - dm_hash_iterate(hn, dm->layers) { - dl = dm_hash_get_data(dm->layers, hn); - - if (_get_flag(dl, ACTIVE) && _get_flag(dl, TOPLEVEL)) - if (!_create_rec(dm, dl)) { - stack; - return 0; - } - } - - /* Resume devices */ - dm_hash_iterate(hn, dm->layers) { - dl = dm_hash_get_data(dm->layers, hn); - - if (!_resume_with_deps(dm, dl)) { - stack; - return 0; - } - } - - if (!_remove_old_layers(dm)) { - stack; - return 0; - } - - return 1; -} - -/* - * ATM we decide which vg a layer belongs to by - * looking at the beginning of the device - * name. - */ -static int _belong_to_vg(const char *vgname, const char *name) -{ - const char *v = vgname, *n = name; - - while (*v) { - if ((*v != *n) || (*v == '-' && *(++n) != '-')) - return 0; - v++, n++; - } - - if (*n == '-' && *(n + 1) != '-') - return 1; - else - return 0; -} - -static int _add_existing_layer(struct dev_manager *dm, const char *name) -{ - struct dev_layer *dl; - char *copy; - - log_debug("Found existing layer '%s'", name); - - if (!(copy = dm_pool_strdup(dm->mem, name))) { - stack; - return 0; - } - - if (!(dl = _create_dev(dm, copy, (char *)""))) { - stack; - return 0; - } - - return 1; -} - -static int _scan_existing_devices(struct dev_manager *dm) -{ - int r = 0; - struct dm_names *names; - unsigned next = 0; - - struct dm_task *dmt; - - if (!(dmt = dm_task_create(DM_DEVICE_LIST))) - return 0; - - if (!dm_task_run(dmt)) - goto out; - - if (!(names = dm_task_get_names(dmt))) - goto out; - - r = 1; - if (!names->dev) - goto out; - - do { - names = (void *) names + next; - if (_belong_to_vg(dm->vg_name, names->name) && - !_add_existing_layer(dm, names->name)) { - stack; - r = 0; - break; - } - next = names->next; - } while (next); - - out: - dm_task_destroy(dmt); - return r; -} - -static int _add_lv(struct dm_pool *mem, - struct list *head, struct logical_volume *lv) -{ - struct lv_list *lvl; - - if (!(lvl = dm_pool_alloc(mem, sizeof(*lvl)))) { - stack; - return 0; - } - - lvl->lv = lv; - list_add(head, &lvl->list); - - return 1; -} - -static int _add_lvs(struct dm_pool *mem, - struct list *head, struct logical_volume *origin) -{ - struct lv_segment *snap_seg; - struct lv_list *lvl; - - list_iterate_items(lvl, &origin->vg->lvs) { - if (lvl->lv->status & SNAPSHOT) - continue; - if ((snap_seg = find_cow(lvl->lv)) && snap_seg->origin == origin) - if (!_add_lv(mem, head, lvl->lv)) - return 0; - } - - return _add_lv(mem, head, origin); -} - -static void _remove_lv(struct list *head, struct logical_volume *lv) -{ - struct lv_list *lvl; - - list_iterate_items(lvl, head) { - if (lvl->lv == lv) { - list_del(&lvl->list); - break; - } - } -} - -static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv) -{ - struct logical_volume *active, *old_origin; - struct lv_segment *snap_seg; - struct list *active_head; - struct lv_list *lvl; - - active_head = &dm->active_list; - - /* Remove any snapshots with given origin */ - list_iterate_items(lvl, active_head) { - active = lvl->lv; - if ((snap_seg = find_cow(active)) && snap_seg->origin == lv) { - _remove_lv(active_head, active); - } + while (*v) { + if ((*v != *n) || (*v == '-' && *(++n) != '-')) + return 0; + v++, n++; } - _remove_lv(active_head, lv); + if (*n == '-' && *(n + 1) != '-') + return 1; + else + return 0; +} if (!(snap_seg = find_cow(lv))) return 1; @@ -2030,313 +551,440 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv) } } - return _add_lvs(dm->mem, &dm->reload_list, old_origin); +#endif + +/*************************/ +/* NEW CODE STARTS HERE */ +/*************************/ + +int dev_manager_lv_mknodes(const struct logical_volume *lv) +{ + char *name; + + if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name, + lv->name, NULL))) + return_0; + + return fs_add_lv(lv, name); } -static int _remove_suspended_lvs(struct dev_manager *dm, - struct logical_volume *lv) +int dev_manager_lv_rmnodes(const struct logical_volume *lv) { - struct logical_volume *suspended; - struct lv_segment *snap_seg; - struct list *suspend_head; - struct lv_list *lvl; + return fs_del_lv(lv); +} + +static int _add_dev_to_deptree(struct dev_manager *dm, struct deptree *dtree, + struct logical_volume *lv, const char *layer) +{ + char *dlid, *name; + struct dm_info info; - suspend_head = &dm->suspend_list; + if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) + return_0; - /* Remove from list any snapshots with given origin */ - list_iterate_items(lvl, suspend_head) { - suspended = lvl->lv; - if ((snap_seg = find_cow(suspended)) && - snap_seg->origin == lv) { - _remove_lv(suspend_head, suspended); - } + if (!(dlid = build_dlid(dm, lv->lvid.s, layer))) + return_0; + + log_debug("Getting device info for %s [%s]", name, dlid); + if (!_info(name, dlid, 0, 1, &info, dm->mem, NULL)) { + log_error("Failed to get info for %s [%s].", name, dlid); + return 0; + } + + if (info.exists && !dm_deptree_add_dev(dtree, info.major, info.minor)) { + log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to deptree", + info.major, info.minor); + return 0; } - _remove_lv(suspend_head, lv); + return 1; +} + +/* + * Add LV and any known dependencies + */ +static int _add_lv_to_deptree(struct dev_manager *dm, struct deptree *dtree, struct logical_volume *lv) +{ + if (!_add_dev_to_deptree(dm, dtree, lv, NULL)) + return_0; + + /* FIXME Can we avoid doing this every time? */ + if (!_add_dev_to_deptree(dm, dtree, lv, "real")) + return_0; + + if (!_add_dev_to_deptree(dm, dtree, lv, "cow")) + return_0; return 1; } -static int _targets_present(struct dev_manager *dm, struct list *lvs) +static struct deptree *_create_partial_deptree(struct dev_manager *dm, struct logical_volume *lv) { - struct logical_volume *lv; - struct lv_list *lvl; - struct segment_type *segtype; - struct lv_segment *seg; - int snapshots = 0, mirrors = 0; - - list_iterate_items(lvl, lvs) { - lv = lvl->lv; - - if (!snapshots) - if (lv_is_cow(lv) || lv_is_origin(lv)) - snapshots = 1; - - if (!mirrors) - if (lv->status & PVMOVE) - mirrors = 1; - - if (lv->status & VIRTUAL) { - list_iterate_items(seg, &lv->segments) { - if (seg->segtype->ops->target_present && - !seg->segtype->ops->target_present()) { - log_error("Can't expand LV: %s target " - "support missing " - "from kernel?", - seg->segtype->name); - return 0; - } - } - } - } + struct deptree *dtree; + struct list *snh, *snht; - if (mirrors) { - if (!(segtype = get_segtype_from_string(dm->cmd, "mirror"))) { - log_error("Can't expand LV: Mirror support " - "missing from tools?"); - return 0; - } + if (!(dtree = dm_deptree_create())) { + log_error("Partial deptree creation failed for %s.", lv->name); + return NULL; + } - if (!segtype->ops->target_present || - !segtype->ops->target_present()) { - log_error("Can't expand LV: Mirror support missing " - "from kernel?"); - return 0; - } + if (!_add_lv_to_deptree(dm, dtree, lv)) { + stack; + goto fail; } - if (snapshots) { - if (!(segtype = get_segtype_from_string(dm->cmd, "snapshot"))) { - log_error("Can't expand LV: Snapshot support " - "missing from tools?"); - return 0; + /* Add any snapshots of this LV */ + list_iterate_safe(snh, snht, &lv->snapshot_segs) + if (!_add_lv_to_deptree(dm, dtree, list_struct_base(snh, struct lv_segment, origin_list)->cow)) { + stack; + goto fail; } - if (!segtype->ops->target_present || - !segtype->ops->target_present()) { - log_error("Can't expand LV: Snapshot support missing " - "from kernel?"); - return 0; - } - } + return dtree; - return 1; +fail: + dm_deptree_free(dtree); + return NULL; } -static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg) +int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, + struct deptree_node *node, int start_area, int areas) { + uint64_t extent_size = seg->lv->vg->extent_size; + uint32_t s; char *dlid; - struct lv_list *lvl; - struct dev_layer *dl; - - list_iterate_items(lvl, &vg->lvs) { - if (lvl->lv->status & SNAPSHOT) - continue; - if (!(dlid = _build_dlid(dm->mem, lvl->lv->lvid.s, NULL))) { - stack; + for (s = start_area; s < areas; s++) { + if ((seg_type(seg, s) == AREA_PV && + (!seg_pvseg(seg, s) || + !seg_pv(seg, s) || + !seg_dev(seg, s))) || + (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s))) + dm_deptree_node_add_target_area(node, + dm->stripe_filler, + NULL, 0); + else if (seg_type(seg, s) == AREA_PV) + dm_deptree_node_add_target_area(node, + dev_name(seg_dev(seg, s)), + NULL, + (seg_pv(seg, s)->pe_start + + (extent_size * seg_pe(seg, s)))); + else if (seg_type(seg, s) == AREA_LV) { + if (!(dlid = build_dlid(dm, + seg_lv(seg, s)->lvid.s, + NULL))) + return_0; + dm_deptree_node_add_target_area(node, NULL, dlid, + extent_size * seg_le(seg, s)); + } else { + log_error("Internal error: Unassigned area found in LV %s.", + seg->lv->name); return 0; } + } - dl = dm_hash_lookup(dm->layers, dlid); - dm_pool_free(dm->mem, dlid); + return 1; +} - if (dl) { - log_debug("Found active lv %s%s", lvl->lv->name, - dl->info.suspended ? " (suspended)" : ""); +static int _add_origin_target_to_deptree(struct dev_manager *dm, + struct deptree *dtree, + struct deptree_node *dnode, + struct logical_volume *lv) +{ + const char *real_dlid; - if (!_add_lv(dm->mem, &dm->active_list, lvl->lv)) { - stack; - return 0; - } + if (!(real_dlid = build_dlid(dm, lv->lvid.s, "real"))) + return_0; - if (dl->info.suspended) { - if (!_add_lv(dm->mem, &dm->suspend_list, lvl->lv)) { - stack; - return 0; - } - } - } - } + if (!dm_deptree_node_add_snapshot_origin_target(dnode, lv->size, real_dlid)) + return_0; return 1; } -static int _action_activate(struct dev_manager *dm, struct logical_volume *lv) +static int _add_snapshot_target_to_deptree(struct dev_manager *dm, + struct deptree *dtree, + struct deptree_node *dnode, + struct logical_volume *lv) { - // Replace with deptree code for lv + known deps only. - if (!_scan_existing_devices(dm)) { - stack; - return 0; - } - - if (!_fill_in_active_list(dm, lv->vg)) { - stack; - return 0; - } + const char *origin_dlid; + const char *cow_dlid; + struct lv_segment *snap_seg; + uint64_t size; - /* Get into known state - remove from active list if present */ - if (!_remove_lvs(dm, lv)) { - stack; + if (!(snap_seg = find_cow(lv))) { + log_error("Couldn't find snapshot for '%s'.", lv->name); return 0; } - /* Add to active & reload lists */ - if (!_add_lvs(dm->mem, &dm->reload_list, lv) || - !_add_lvs(dm->mem, &dm->active_list, lv)) { - stack; - return 0; - } + if (!(origin_dlid = build_dlid(dm, snap_seg->origin->lvid.s, "real"))) + return_0; - /* Get into known state - remove from suspend list if present */ - if (!_remove_suspended_lvs(dm, lv)) { - stack; - return 0; - } + if (!(cow_dlid = build_dlid(dm, snap_seg->cow->lvid.s, "cow"))) + return_0; - if (!_targets_present(dm, &dm->active_list) || - !_targets_present(dm, &dm->reload_list)) { - stack; - return 0; - } + size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size; - if (!_execute(dm, lv->vg)) { - stack; - return 0; - } + if (!dm_deptree_node_add_snapshot_target(dnode, size, origin_dlid, cow_dlid, 1, snap_seg->chunk_size)) + return_0; return 1; } -int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv) +static int _add_target_to_deptree(struct dev_manager *dm, + struct deptree *dtree, + struct deptree_node *dnode, + struct lv_segment *seg) { - return _action_activate(dm, lv); + uint64_t extent_size = seg->lv->vg->extent_size; + + if (!seg->segtype->ops->add_target_line) { + log_error("_emit_target: Internal error: Can't handle " + "segment type %s", seg->segtype->name); + return 0; + } + + return seg->segtype->ops->add_target_line(dm, dm->mem, dm->cmd->cft, + &dm->target_state, seg, + dnode, + extent_size * seg->len, + &dm-> pvmove_mirror_count); } -int dev_manager_lv_mknodes(const struct logical_volume *lv) +static int _add_new_lv_to_deptree(struct dev_manager *dm, struct deptree *dtree, + struct logical_volume *lv, const char *layer); + +static int _add_segment_to_deptree(struct dev_manager *dm, + struct deptree *dtree, + struct deptree_node *dnode, + struct lv_segment *seg, + const char *layer) { - char *name; + uint32_t s; + struct list *snh; - if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name, - lv->name, NULL))) { - stack; + /* Ensure required device-mapper targets are loaded */ + if (seg->segtype->ops->target_present && + !seg->segtype->ops->target_present()) { + log_error("Can't expand LV %s: %s target support missing " + "from kernel?", seg->lv->name, seg->segtype->name); return 0; } - return fs_add_lv(lv, name); -} + /* Add mirror log */ + if (seg->log_lv && + !_add_new_lv_to_deptree(dm, dtree, seg->log_lv, NULL)) + return_0; -int dev_manager_lv_rmnodes(const struct logical_volume *lv) -{ - return fs_del_lv(lv); -} + /* If this is a snapshot origin, add real LV */ + if (lv_is_origin(seg->lv) && !layer) { + if (seg->lv->vg->status & CLUSTERED) { + log_error("Clustered snapshots are not yet supported"); + return 0; + } + if (!_add_new_lv_to_deptree(dm, dtree, seg->lv, "real")) + return_0; + } else if (lv_is_cow(seg->lv) && !layer) { + if (!_add_new_lv_to_deptree(dm, dtree, seg->lv, "cow")) + return_0; + } else { + /* Add any LVs used by this segment */ + for (s = 0; s < seg->area_count; s++) + if ((seg_type(seg, s) == AREA_LV) && + (!_add_new_lv_to_deptree(dm, dtree, seg_lv(seg, s), NULL))) + return_0; + } + + /* Now we've added its dependencies, we can add the target itself */ + if (lv_is_origin(seg->lv) && !layer) { + if (!_add_origin_target_to_deptree(dm, dtree, dnode, seg->lv)) + return_0; + } else if (lv_is_cow(seg->lv) && !layer) { + if (!_add_snapshot_target_to_deptree(dm, dtree, dnode, seg->lv)) + return_0; + } else if (!_add_target_to_deptree(dm, dtree, dnode, seg)) + return_0; + + if (lv_is_origin(seg->lv) && !layer) + /* Add any snapshots of this LV */ + list_iterate(snh, &seg->lv->snapshot_segs) + if (!_add_new_lv_to_deptree(dm, dtree, list_struct_base(snh, struct lv_segment, origin_list)->cow, NULL)) + return_0; -void dev_manager_exit(void) -{ - dm_lib_exit(); + return 1; } -/* - * New deactivation code - */ -static int _add_lv_to_deptree(struct dev_manager *dm, struct deptree *dtree, struct logical_volume *lv) +static int _add_new_lv_to_deptree(struct dev_manager *dm, struct deptree *dtree, + struct logical_volume *lv, const char *layer) { - char *dlid, *name; - struct dm_info info; + struct lv_segment *seg; + struct lv_layer *lvlayer; + struct deptree_node *dnode; + char *name, *dlid; - if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) { - stack; - return 0; - } + if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) + return_0; - if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) { - stack; - return 0; - } + if (!(dlid = build_dlid(dm, lv->lvid.s, layer))) + return_0; - log_debug("Getting device info for %s [%s]", name, dlid); - if (!_info(name, dlid, 0, 1, &info, dm->mem, NULL)) { - stack; - return 0; - } + /* We've already processed this node if it already has a context ptr */ + if ((dnode = dm_deptree_find_node_by_uuid(dtree, dlid)) && + dm_deptree_node_get_context(dnode)) + return 1; - if (info.exists && !dm_deptree_add_dev(dtree, info.major, info.minor)) { - log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to deptree", - info.major, info.minor); + /* FIXME How do we determine whether a pre-existing node need reloading or not? */ + if (!(lvlayer = dm_pool_alloc(dm->mem, sizeof(*lvlayer)))) { + log_error("_add_new_lv_to_deptree: pool alloc failed for %s %s.", lv->name, layer); return 0; } - /* FIXME Check for any related nodes left behind e.g. -real */ + lvlayer->lv = lv; + + /* + * Add LV to deptree. + * If we're working with precommitted metadata, clear any + * existing inactive table left behind. + * Major/minor settings only apply to the visible layer. + */ + if (!(dnode = dm_deptree_add_new_dev(dtree, name, dlid, + layer ? lv->major : 0, + layer ? lv->minor : 0, + _read_only_lv(lv), + lv->vg->status & PRECOMMITTED, + lvlayer))) + return_0; + + /* Store existing name so we can do rename later */ + lvlayer->old_name = dm_deptree_node_get_name(dnode); + + /* Create table */ + dm->pvmove_mirror_count = 0u; + list_iterate_items(seg, &lv->segments) { + if (!_add_segment_to_deptree(dm, dtree, dnode, seg, layer)) + return_0; + /* These aren't real segments in the LVM2 metadata */ + if (lv_is_origin(lv) && !layer) + break; + if (lv_is_cow(lv) && !layer) + break; + } return 1; } -static struct deptree *_create_partial_deptree(struct dev_manager *dm, struct logical_volume *lv) +/* + * Create LV symlinks for children of supplied root node. + */ +static int _create_lv_symlinks(struct dev_manager *dm, struct deptree_node *root) { - struct deptree *dtree; - struct list *snh, *snht; + void *handle = NULL; + struct deptree_node *child; + struct lv_layer *lvlayer; + char *vgname, *lvname, *layer; + const char *name; + int r = 1; - if (!(dtree = dm_deptree_create())) { - log_error("partial deptree creation failed"); - return NULL; - } + while ((child = dm_deptree_next_child(&handle, root, 0))) { + if (!(lvlayer = (struct lv_layer *) dm_deptree_node_get_context(child))) + continue; - if (!_add_lv_to_deptree(dm, dtree, lv)) { - stack; - goto fail; - } + /* Detect rename */ + name = dm_deptree_node_get_name(child); - /* Add any snapshots of this LV */ - list_iterate_safe(snh, snht, &lv->snapshot_segs) { - if (!_add_lv_to_deptree(dm, dtree, list_struct_base(snh, struct lv_segment, origin_list)->cow)) { - stack; - goto fail; - } + if (name && lvlayer->old_name && *lvlayer->old_name && strcmp(name, lvlayer->old_name)) { + if (!split_dm_name(dm->mem, lvlayer->old_name, &vgname, &lvname, &layer)) { + log_error("_create_lv_symlinks: Couldn't split up old device name %s", lvlayer->old_name); + return 0; + } + fs_rename_lv(lvlayer->lv, name, lvname); + } else if (!dev_manager_lv_mknodes(lvlayer->lv)) + r = 0; } - return dtree; + return r; +} -fail: - dm_deptree_free(dtree); - return NULL; +static int _clean_tree(struct dev_manager *dm, struct logical_volume *lv, struct deptree_node *root) +{ + void *handle = NULL; + struct deptree_node *child; + char *vgname, *lvname, *layer; + const char *name, *uuid; + + while ((child = dm_deptree_next_child(&handle, root, 0))) { + if (!(name = dm_deptree_node_get_name(child))) + continue; + + if (!(uuid = dm_deptree_node_get_uuid(child))) + continue; + + if (!split_dm_name(dm->mem, name, &vgname, &lvname, &layer)) { + log_error("_clean_tree: Couldn't split up device name %s.", name); + return 0; + } + + /* Not meant to be top level? */ + if (!*layer) + continue; + + if (!dm_deptree_deactivate_children(root, uuid, strlen(uuid))) + return_0; + } + + return 1; } -/* - * Deactivate LV and all devices it references that nothing else has open. - */ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, action_t action) { struct deptree *dtree; - struct deptree_node *dnode; + struct deptree_node *root; char *dlid; int r = 0; - if (!(dtree = _create_partial_deptree(dm, lv))) { - stack; - return 0; - } + if (!(dtree = _create_partial_deptree(dm, lv))) + return_0; - if (!(dnode = dm_deptree_find_node(dtree, 0, 0))) { + if (!(root = dm_deptree_find_node(dtree, 0, 0))) { log_error("Lost dependency tree root node"); goto out; } - if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) { - log_error("dlid build failed for %s", lv->name); - goto out; - } + if (!(dlid = build_dlid(dm, lv->lvid.s, NULL))) + goto_out; /* Only process nodes with uuid of "LVM-" plus VG id. */ switch(action) { + case CLEAN: + /* Deactivate any unused non-toplevel nodes */ + if (!_clean_tree(dm, lv, root)) + goto_out; + break; case DEACTIVATE: - if (!dm_deptree_deactivate_children(dnode, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1)) { - stack; - goto out; - } + /* Deactivate LV and all devices it references that nothing else has open. */ + if (!dm_deptree_deactivate_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1)) + goto_out; break; case SUSPEND: - if (!dm_deptree_suspend_children(dnode, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1)) { - stack; + if (!dm_deptree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1)) + goto_out; + break; + case PRELOAD: + case ACTIVATE: + /* Add all required new devices to tree */ + if (!_add_new_lv_to_deptree(dm, dtree, lv, NULL)) + goto_out; + + /* Preload any devices required before any suspensions */ + if (!dm_deptree_preload_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1)) + goto_out; + + if ((action == ACTIVATE) && + !dm_deptree_activate_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1)) + goto_out; + + if (!_create_lv_symlinks(dm, root)) { + log_error("Failed to create symlinks for %s.", lv->name); goto out; } break; @@ -2353,6 +1001,18 @@ out: return r; } +int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv) +{ + if (!_tree_action(dm, lv, ACTIVATE)) + return_0; + + return _tree_action(dm, lv, CLEAN); +} + +int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv) +{ + return _tree_action(dm, lv, PRELOAD); +} int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv) { @@ -2378,7 +1038,7 @@ int dev_manager_device_uses_vg(struct dev_manager *dm, struct device *dev, struct volume_group *vg) { struct deptree *dtree; - struct deptree_node *dnode; + struct deptree_node *root; char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1]; int r = 1; @@ -2396,15 +1056,13 @@ int dev_manager_device_uses_vg(struct dev_manager *dm, struct device *dev, memcpy(dlid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1); memcpy(dlid + sizeof(UUID_PREFIX) - 1, &vg->id.uuid[0], sizeof(vg->id)); - if (!(dnode = dm_deptree_find_node(dtree, 0, 0))) { + if (!(root = dm_deptree_find_node(dtree, 0, 0))) { log_error("Lost dependency tree root node"); goto out; } - if (dm_deptree_children_use_uuid(dnode, dlid, sizeof(UUID_PREFIX) + sizeof(vg->id) - 1)) { - stack; - goto out; - } + if (dm_deptree_children_use_uuid(root, dlid, sizeof(UUID_PREFIX) + sizeof(vg->id) - 1)) + goto_out; r = 0; diff --git a/lib/activate/dev_manager.h b/lib/activate/dev_manager.h index 6a7519feb..19b6572c2 100644 --- a/lib/activate/dev_manager.h +++ b/lib/activate/dev_manager.h @@ -47,6 +47,7 @@ int dev_manager_mirror_percent(struct dev_manager *dm, float *percent, uint32_t *event_nr); int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv); int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv); +int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv); int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv); int dev_manager_lv_mknodes(const struct logical_volume *lv); diff --git a/lib/activate/targets.h b/lib/activate/targets.h index c51079b64..8a8b8ac7e 100644 --- a/lib/activate/targets.h +++ b/lib/activate/targets.h @@ -23,6 +23,9 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, char *params, size_t paramsize, int *pos, int start_area, int areas); +int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, + struct deptree_node *node, int start_area, int areas); + int build_dev_string(struct dev_manager *dm, char *dlid, char *devbuf, size_t bufsize, const char *desc); diff --git a/lib/error/errseg.c b/lib/error/errseg.c index 906d1df17..a41619af9 100644 --- a/lib/error/errseg.c +++ b/lib/error/errseg.c @@ -38,18 +38,13 @@ static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2) } #ifdef DEVMAPPER_SUPPORT -static int _compose_target_line(struct dev_manager *dm, struct dm_pool *mem, +static int _add_target_line(struct dev_manager *dm, struct dm_pool *mem, struct config_tree *cft, void **target_state, - struct lv_segment *seg, char *params, - size_t paramsize, const char **target, int *pos, + struct lv_segment *seg, + struct deptree_node *node, uint64_t len, uint32_t *pvmove_mirror_count) { - /* error */ - - *target = "error"; - *params = '\0'; - - return 1; + return dm_deptree_node_add_error_target(node, len); } static int _target_present(void) @@ -57,8 +52,10 @@ static int _target_present(void) static int checked = 0; static int present = 0; - if (!checked) - present = target_present("error"); + /* Reported truncated in older kernels */ + if (!checked && + (target_present("error", 0) || target_present("erro", 0))) + present = 1; checked = 1; return present; @@ -74,7 +71,7 @@ static struct segtype_handler _error_ops = { name:_name, merge_segments:_merge_segments, #ifdef DEVMAPPER_SUPPORT - compose_target_line:_compose_target_line, + add_target_line:_add_target_line, target_present:_target_present, #endif destroy:_destroy, @@ -84,16 +81,14 @@ struct segment_type *init_error_segtype(struct cmd_context *cmd) { struct segment_type *segtype = dm_malloc(sizeof(*segtype)); - if (!segtype) { - stack; - return NULL; - } + if (!segtype) + return_NULL; segtype->cmd = cmd; segtype->ops = &_error_ops; segtype->name = "error"; segtype->private = NULL; - segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL; + segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED; log_very_verbose("Initialised segtype: %s", segtype->name); diff --git a/lib/log/log.h b/lib/log/log.h index 4c5905598..36eed30fd 100644 --- a/lib/log/log.h +++ b/lib/log/log.h @@ -124,4 +124,8 @@ void print_log(int level, const char *file, int line, const char *format, ...) #define log_sys_debug(x, y) \ log_debug("%s: %s failed: %s", y, x, strerror(errno)) +#define return_0 do { stack; return 0; } while (0) +#define return_NULL do { stack; return NULL; } while (0) +#define goto_out do { stack; goto out; } while (0) + #endif diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c index 9e03a6bb2..b6b5e4e21 100644 --- a/lib/metadata/mirror.c +++ b/lib/metadata/mirror.c @@ -204,10 +204,8 @@ int create_mirror_layers(struct alloc_handle *ah, MIRROR_IMAGE); /* Already got a non-mirrored area to be converted? */ - if (!first_area) { + if (first_area) _move_lv_segments(img_lvs[0], lv); - lv->status |= MIRRORED; - } if (!lv_add_mirror_segment(ah, lv, img_lvs, num_mirrors, segtype, 0, region_size, log_lv)) { @@ -216,6 +214,8 @@ int create_mirror_layers(struct alloc_handle *ah, return 0; } + lv->status |= MIRRORED; + return 1; } diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h index 7ac0887ed..415feb0b7 100644 --- a/lib/metadata/segtype.h +++ b/lib/metadata/segtype.h @@ -31,12 +31,14 @@ struct dev_manager; #define SEG_SNAPSHOT 0x00000008 #define SEG_FORMAT1_SUPPORT 0x00000010 #define SEG_VIRTUAL 0x00000020 +#define SEG_CANNOT_BE_ZEROED 0x00000040 #define seg_is_mirrored(seg) ((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0) #define seg_is_striped(seg) ((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0) #define seg_is_snapshot(seg) ((seg)->segtype->flags & SEG_SNAPSHOT ? 1 : 0) #define seg_is_virtual(seg) ((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0) #define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0) +#define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0) #define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0) #define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0) @@ -64,12 +66,11 @@ struct segtype_handler { struct dm_hash_table * pv_hash); int (*merge_segments) (struct lv_segment * seg1, struct lv_segment * seg2); - int (*compose_target_line) (struct dev_manager * dm, struct dm_pool * mem, - struct config_tree * cft, - void **target_state, - struct lv_segment * seg, char *params, - size_t paramsize, const char **target, - int *pos, uint32_t *pvmove_mirror_count); + int (*add_target_line) (struct dev_manager *dm, struct dm_pool *mem, + struct config_tree *cft, void **target_state, + struct lv_segment *seg, + struct deptree_node *node, uint64_t len, + uint32_t *pvmove_mirror_count); int (*target_percent) (void **target_state, struct dm_pool * mem, struct config_tree * cft, struct lv_segment * seg, char *params, diff --git a/lib/mirror/mirrored.c b/lib/mirror/mirrored.c index dcd973647..e3a7e2623 100644 --- a/lib/mirror/mirrored.c +++ b/lib/mirror/mirrored.c @@ -165,118 +165,6 @@ static struct mirror_state *_init_target(struct dm_pool *mem, return mirr_state; } -static int _compose_log_line(struct dev_manager *dm, struct lv_segment *seg, - char *params, size_t paramsize, int *pos, - int areas, uint32_t region_size) -{ - int tw; - char devbuf[10]; - const char *clustered = ""; - char *dlid; - - /* - * Use clustered mirror log for non-exclusive activation - * in clustered VG. - */ - if ((!(seg->lv->status & ACTIVATE_EXCL) && - (seg->lv->vg->status & CLUSTERED))) - clustered = "cluster "; - - if (!seg->log_lv) - tw = lvm_snprintf(params, paramsize, "%score 1 %u %u ", - clustered, region_size, areas); - else { - if (!(dlid = build_dlid(dm, seg->log_lv->lvid.s, NULL))) { - stack; - return 0; - } - if (!build_dev_string(dm, dlid, devbuf, - sizeof(devbuf), "log")) { - stack; - return 0; - } - - /* FIXME add sync parm? */ - tw = lvm_snprintf(params, paramsize, "%sdisk 2 %s %u %u ", - clustered, devbuf, region_size, areas); - } - - if (tw < 0) { - stack; - return -1; - } - - *pos += tw; - - return 1; -} - -static int _compose_target_line(struct dev_manager *dm, struct dm_pool *mem, - struct config_tree *cft, void **target_state, - struct lv_segment *seg, char *params, - size_t paramsize, const char **target, int *pos, - uint32_t *pvmove_mirror_count) -{ - struct mirror_state *mirr_state; - int mirror_status = MIRR_RUNNING; - int areas = seg->area_count; - int start_area = 0u; - uint32_t region_size, region_max; - int ret; - - if (!*target_state) - *target_state = _init_target(mem, cft); - - mirr_state = *target_state; - - /* mirror log_type #log_params [log_params]* - * #mirrors [device offset]+ - */ - if (seg->status & PVMOVE) { - if (seg->extents_copied == seg->area_len) { - mirror_status = MIRR_COMPLETED; - start_area = 1; - } else if ((*pvmove_mirror_count)++) { - mirror_status = MIRR_DISABLED; - areas = 1; - } - } - - if (mirror_status != MIRR_RUNNING) { - *target = "linear"; - } else { - *target = "mirror"; - - if (!(seg->status & PVMOVE)) { - if (!seg->region_size) { - log_error("Missing region size for mirror segment."); - return 0; - } - region_size = seg->region_size; - } else { - /* Find largest power of 2 region size unit we can use */ - region_max = (1 << (ffs(seg->area_len) - 1)) * - seg->lv->vg->extent_size; - - region_size = mirr_state->default_region_size; - if (region_max < region_size) { - region_size = region_max; - log_verbose("Using reduced mirror region size of %u sectors", - region_size); - } - } - - if ((ret = _compose_log_line(dm, seg, params, paramsize, pos, - areas, region_size)) <= 0) { - stack; - return ret; - } - } - - return compose_areas_line(dm, seg, params, paramsize, pos, start_area, - areas); -} - static int _target_percent(void **target_state, struct dm_pool *mem, struct config_tree *cft, struct lv_segment *seg, char *params, uint64_t *total_numerator, @@ -328,13 +216,109 @@ static int _target_percent(void **target_state, struct dm_pool *mem, return 1; } +static int _add_log(struct dev_manager *dm, struct lv_segment *seg, + struct deptree_node *node, uint32_t area_count, uint32_t region_size) +{ + unsigned clustered = 0; + char *log_dlid = NULL; + + /* + * Use clustered mirror log for non-exclusive activation + * in clustered VG. + */ + if ((!(seg->lv->status & ACTIVATE_EXCL) && + (seg->lv->vg->status & CLUSTERED))) + clustered = 1; + + if (seg->log_lv && + !(log_dlid = build_dlid(dm, seg->log_lv->lvid.s, NULL))) { + log_error("Failed to build uuid for log LV %s.", + seg->log_lv->name); + return 0; + } + + /* FIXME Add sync parm? */ + return dm_deptree_node_add_mirror_target_log(node, region_size, clustered, log_dlid, area_count); +} + +static int _add_target_line(struct dev_manager *dm, struct dm_pool *mem, + struct config_tree *cft, void **target_state, + struct lv_segment *seg, + struct deptree_node *node, uint64_t len, + uint32_t *pvmove_mirror_count) +{ + struct mirror_state *mirr_state; + uint32_t area_count = seg->area_count; + int start_area = 0u; + int mirror_status = MIRR_RUNNING; + uint32_t region_size, region_max; + int r; + + if (!*target_state) + *target_state = _init_target(mem, cft); + + mirr_state = *target_state; + + /* + * For pvmove, only have one mirror segment RUNNING at once. + * Segments before this are COMPLETED and use 2nd area. + * Segments after this are DISABLED and use 1st area. + */ + if (seg->status & PVMOVE) { + if (seg->extents_copied == seg->area_len) { + mirror_status = MIRR_COMPLETED; + start_area = 1; + } else if ((*pvmove_mirror_count)++) { + mirror_status = MIRR_DISABLED; + area_count = 1; + } + /* else MIRR_RUNNING */ + } + + if (mirror_status != MIRR_RUNNING) { + if (!dm_deptree_node_add_linear_target(node, len)) + return_0; + goto done; + } + + if (!(seg->status & PVMOVE)) { + if (!seg->region_size) { + log_error("Missing region size for mirror segment."); + return 0; + } + region_size = seg->region_size; + } else { + /* Find largest power of 2 region size unit we can use */ + region_max = (1 << (ffs(seg->area_len) - 1)) * + seg->lv->vg->extent_size; + + region_size = mirr_state->default_region_size; + if (region_max < region_size) { + region_size = region_max; + log_verbose("Using reduced mirror region size of %u sectors", + region_size); + } + } + + if (!dm_deptree_node_add_mirror_target(node, len)) + return_0; + + if ((r = _add_log(dm, seg, node, area_count, region_size)) <= 0) { + stack; + return r; + } + + done: + return add_areas_line(dm, seg, node, start_area, seg->area_count); +} + static int _target_present(void) { static int checked = 0; static int present = 0; if (!checked) - present = target_present("mirror"); + present = target_present("mirror", 1); checked = 1; @@ -354,7 +338,7 @@ static struct segtype_handler _mirrored_ops = { text_import:_text_import, text_export:_text_export, #ifdef DEVMAPPER_SUPPORT - compose_target_line:_compose_target_line, + add_target_line:_add_target_line, target_percent:_target_percent, target_present:_target_present, #endif diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c index a1f91125c..e620e49c5 100644 --- a/lib/misc/lvm-string.c +++ b/lib/misc/lvm-string.c @@ -130,15 +130,15 @@ static void _quote_hyphens(char **out, const char *src) /* * -- or if !layer just -. */ -char *build_dm_name(struct dm_pool *mem, const char *vg, - const char *lv, const char *layer) +char *build_dm_name(struct dm_pool *mem, const char *vgname, + const char *lvname, const char *layer) { size_t len = 1; int hyphens = 1; char *r, *out; - _count_hyphens(vg, &len, &hyphens); - _count_hyphens(lv, &len, &hyphens); + _count_hyphens(vgname, &len, &hyphens); + _count_hyphens(lvname, &len, &hyphens); if (layer && *layer) { _count_hyphens(layer, &len, &hyphens); @@ -148,14 +148,15 @@ char *build_dm_name(struct dm_pool *mem, const char *vg, len += hyphens; if (!(r = dm_pool_alloc(mem, len))) { - stack; + log_error("build_dm_name: Allocation failed for %" PRIsize_t + " for %s %s %s.", len, vgname, lvname, layer); return NULL; } out = r; - _quote_hyphens(&out, vg); + _quote_hyphens(&out, vgname); *out++ = '-'; - _quote_hyphens(&out, lv); + _quote_hyphens(&out, lvname); if (layer && *layer) { *out++ = '-'; @@ -174,6 +175,7 @@ static char *_unquote(char *component) { char *c = component; char *o = c; + char *r; while (*c) { if (*(c + 1)) { @@ -189,8 +191,10 @@ static char *_unquote(char *component) c++; } + r = (*c) ? c + 1 : c; *o = '\0'; - return (c + 1); + + return r; } int split_dm_name(struct dm_pool *mem, const char *dmname, diff --git a/lib/report/report.c b/lib/report/report.c index ef9fbc729..855f19700 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -369,24 +369,28 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field, if (lv_info(lv->vg->cmd, lv, &info, 1) && info.exists) { if (info.suspended) repstr[4] = 's'; /* Suspended */ - else + else if (info.live_table) repstr[4] = 'a'; /* Active */ - if (info.open_count) - repstr[5] = 'o'; /* Open */ + else if (info.inactive_table) + repstr[4] = 'i'; /* Inactive with table */ else - repstr[5] = '-'; + repstr[4] = 'd'; /* Inactive without table */ /* Snapshot dropped? */ - if ((snap_seg = find_cow(lv)) && + if (info.live_table && (snap_seg = find_cow(lv)) && (!lv_snapshot_percent(snap_seg->cow, &snap_percent) || snap_percent < 0 || snap_percent >= 100)) { repstr[0] = toupper(repstr[0]); if (info.suspended) - repstr[4] = 'S'; + repstr[4] = 'S'; /* Susp Inv snapshot */ else - repstr[4] = 'I'; + repstr[4] = 'I'; /* Invalid snapshot */ } + if (info.open_count) + repstr[5] = 'o'; /* Open */ + else + repstr[5] = '-'; } else { repstr[4] = '-'; repstr[5] = '-'; diff --git a/lib/snapshot/snapshot.c b/lib/snapshot/snapshot.c index a19d6794f..d918f4ef4 100644 --- a/lib/snapshot/snapshot.c +++ b/lib/snapshot/snapshot.c @@ -115,8 +115,8 @@ static int _target_present(void) static int present = 0; if (!checked) - present = target_present("snapshot") && - target_present("snapshot-origin"); + present = target_present("snapshot", 1) && + target_present("snapshot-origin", 0); checked = 1; diff --git a/lib/striped/striped.c b/lib/striped/striped.c index 84da3a0aa..e23da877b 100644 --- a/lib/striped/striped.c +++ b/lib/striped/striped.c @@ -106,7 +106,8 @@ static int _segments_compatible(struct lv_segment *first, unsigned s; if ((first->area_count != second->area_count) || - (first->stripe_size != second->stripe_size)) return 0; + (first->stripe_size != second->stripe_size)) + return 0; for (s = 0; s < first->area_count; s++) { @@ -150,32 +151,25 @@ static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2) } #ifdef DEVMAPPER_SUPPORT -static int _compose_target_line(struct dev_manager *dm, struct dm_pool *mem, - struct config_tree *cft, void **target_state, - struct lv_segment *seg, char *params, - size_t paramsize, const char **target, int *pos, - uint32_t *pvmove_mirror_count) +static int _add_target_line(struct dev_manager *dm, struct dm_pool *mem, + struct config_tree *cft, void **target_state, + struct lv_segment *seg, + struct deptree_node *node, uint64_t len, + uint32_t *pvmove_mirror_count) { - /* linear [device offset]+ - * striped #stripes stripe_size [device offset]+ */ - - if (seg->area_count == 1) - *target = "linear"; - else if (seg->area_count > 1) { - *target = "striped"; - if ((*pos = lvm_snprintf(params, paramsize, "%u %u ", - seg->area_count, - seg->stripe_size)) < 0) { - stack; - return -1; - } - } else { - log_error("Internal error: striped target with no stripes"); + if (!seg->area_count) { + log_error("Internal error: striped add_target_line called " + "with no areas for %s.", seg->lv->name); return 0; } - - return compose_areas_line(dm, seg, params, paramsize, pos, 0u, - seg->area_count); + if (seg->area_count == 1) { + if (!dm_deptree_node_add_linear_target(node, len)) + return_0; + } else if (!dm_deptree_node_add_striped_target(node, len, + seg->stripe_size)) + return_0; + + return add_areas_line(dm, seg, node, 0u, seg->area_count); } static int _target_present(void) @@ -184,7 +178,8 @@ static int _target_present(void) static int present = 0; if (!checked) - present = target_present("linear") && target_present("striped"); + present = target_present("linear", 0) && + target_present("striped", 0); checked = 1; return present; @@ -204,7 +199,7 @@ static struct segtype_handler _striped_ops = { text_export:_text_export, merge_segments:_merge_segments, #ifdef DEVMAPPER_SUPPORT - compose_target_line:_compose_target_line, + add_target_line:_add_target_line, target_present:_target_present, #endif destroy:_destroy, diff --git a/lib/zero/zero.c b/lib/zero/zero.c index f1439b607..6c3ccf064 100644 --- a/lib/zero/zero.c +++ b/lib/zero/zero.c @@ -38,18 +38,13 @@ static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2) } #ifdef DEVMAPPER_SUPPORT -static int _compose_target_line(struct dev_manager *dm, struct dm_pool *mem, - struct config_tree *cft, void **target_state, - struct lv_segment *seg, char *params, - size_t paramsize, const char **target, int *pos, - uint32_t *pvmove_mirror_count) +static int _add_target_line(struct dev_manager *dm, struct dm_pool *mem, + struct config_tree *cft, void **target_state, + struct lv_segment *seg, + struct deptree_node *node, uint64_t len, + uint32_t *pvmove_mirror_count) { - /* zero */ - - *target = "zero"; - *params = '\0'; - - return 1; + return dm_deptree_node_add_zero_target(node, len); } static int _target_present(void) @@ -58,7 +53,7 @@ static int _target_present(void) static int present = 0; if (!checked) - present = target_present("zero"); + present = target_present("zero", 0); checked = 1; return present; @@ -74,7 +69,7 @@ static struct segtype_handler _zero_ops = { name:_name, merge_segments:_merge_segments, #ifdef DEVMAPPER_SUPPORT - compose_target_line:_compose_target_line, + add_target_line:_add_target_line, target_present:_target_present, #endif destroy:_destroy, @@ -93,7 +88,7 @@ struct segment_type *init_zero_segtype(struct cmd_context *cmd) segtype->ops = &_zero_ops; segtype->name = "zero"; segtype->private = NULL; - segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL; + segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED; log_very_verbose("Initialised segtype: %s", segtype->name); diff --git a/man/lvs.8 b/man/lvs.8 index eb8018ef0..57051eb69 100644 --- a/man/lvs.8 +++ b/man/lvs.8 @@ -55,7 +55,8 @@ changes, for example during \fBpvmove\fP (8). .IP 4 3 fixed (m)inor .IP 5 3 -State: (a)ctive, (s)uspended, (I)nvalid snapshot, invalid (S)uspended snapshot +State: (a)ctive, (s)uspended, (I)nvalid snapshot, invalid (S)uspended snapshot, +mapped (d)evice present without tables, mapped device present with (i)nactive table .IP 6 3 device (o)pen .RE diff --git a/tools/lvcreate.c b/tools/lvcreate.c index 4977397da..31a8405b1 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -359,7 +359,8 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd, /* * Should we zero the lv. */ - lp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n"); + lp->zero = strcmp(arg_str_value(cmd, zero_ARG, + (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n"); /* * Alloc policy diff --git a/tools/lvremove.c b/tools/lvremove.c index 003c727c5..e29af6f38 100644 --- a/tools/lvremove.c +++ b/tools/lvremove.c @@ -20,6 +20,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, { struct volume_group *vg; struct lvinfo info; + struct logical_volume *origin = NULL; vg = lv->vg; @@ -74,6 +75,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, if (!archive(vg)) return ECMD_FAILED; + /* FIXME Snapshot commit out of sequence if it fails after here? */ if (!deactivate_lv(cmd, lv)) { log_error("Unable to deactivate logical volume \"%s\"", lv->name); @@ -81,6 +83,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, } if (lv_is_cow(lv)) { + origin = find_cow(lv)->origin; log_verbose("Removing snapshot %s", lv->name); if (!vg_remove_snapshot(lv)) { stack; @@ -103,6 +106,14 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, if (!vg_commit(vg)) return ECMD_FAILED; + /* If no snapshots left, reload without -real. */ + if (origin && !lv_is_origin(origin)) { + if (!suspend_lv(cmd, origin)) + log_error("Failed to refresh %s without snapshot.", origin->name); + else if (!resume_lv(cmd, origin)) + log_error("Failed to resume %s.", origin->name); + } + log_print("Logical volume \"%s\" successfully removed", lv->name); return ECMD_PROCESSED; } -- 2.43.5