summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/activate/activate.c135
-rw-r--r--lib/activate/activate.h4
-rw-r--r--lib/activate/dev_manager.c2118
-rw-r--r--lib/activate/dev_manager.h1
-rw-r--r--lib/activate/targets.h3
-rw-r--r--lib/error/errseg.c29
-rw-r--r--lib/log/log.h4
-rw-r--r--lib/metadata/mirror.c6
-rw-r--r--lib/metadata/segtype.h13
-rw-r--r--lib/mirror/mirrored.c212
-rw-r--r--lib/misc/lvm-string.c20
-rw-r--r--lib/report/report.c18
-rw-r--r--lib/snapshot/snapshot.c4
-rw-r--r--lib/striped/striped.c47
-rw-r--r--lib/zero/zero.c23
-rw-r--r--man/lvs.83
-rw-r--r--tools/lvcreate.c3
-rw-r--r--tools/lvremove.c11
18 files changed, 656 insertions, 1998 deletions
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index f15123d7..6f1af347 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 bf5b8b08..c05f667d 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 a41c18cc..65527f56 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 <limits.h>
#include <dirent.h>
-/*
- * 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,492 +378,6 @@ 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)
-{
- 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);
-
- if (!(dmt = _setup_task(dl->name, NULL, 0, DM_DEVICE_RENAME))) {
- stack;
- return 0;
- }
-
- if (!dm_task_set_newname(dmt, newname)) {
- stack;
- r = 0;
- goto out;
- }
-
- if (!dm_task_no_open_count(dmt))
- log_error("Failed to disable open_count");
-
- if (!(r = dm_task_run(dmt))) {
- log_error("Couldn't rename device '%s'.", dl->name);
- goto out;
- }
-
- 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))) {
- stack;
- return 0;
- }
-
- if (!dm_task_no_open_count(dmt))
- log_error("Failed to disable open_count");
-
- if (!(r = dm_task_run(dmt)))
- log_error("Couldn't %s device '%s'", sus ? "suspend" : "resume",
- name);
-
- dm_task_destroy(dmt);
- return r;
-}
-
-static int _suspend(struct dev_layer *dl)
-{
- if (!dl->info.exists || dl->info.suspended)
- return 1;
-
- if (!_suspend_or_resume(dl->name, SUSPEND)) {
- stack;
- return 0;
- }
-
- dl->info.suspended = 1;
- return 1;
-}
-
-static int _resume(struct dev_layer *dl)
-{
- if (!dl->info.exists || !dl->info.suspended)
- return 1;
-
- if (!_suspend_or_resume(dl->name, RESUME)) {
- stack;
- return 0;
- }
-
- dl->info.suspended = 0;
- return 1;
-}
-
-static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
-{
- 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;
- }
-
- /*
- * Do we want a specific device number ?
- */
- 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 (!dm_task_no_open_count(dmt))
- log_error("Failed to disable open_count");
-
- 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 (!dm_task_get_info(dmt, &dl->info)) {
- stack;
- r = 0;
- goto out;
- }
-
- if (!dl->info.exists || !dl->info.live_table) {
- stack;
- r = 0;
- goto out;
- }
-
- if (_get_flag(dl, RESUME_IMMEDIATE) && dl->info.suspended &&
- !_resume(dl)) {
- stack;
- r = 0;
- goto out;
- }
-
- 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;
- }
-
- if (!dm_task_no_open_count(dmt))
- log_error("Failed to disable open_count");
-
- /* Suppress error message if it's still in use - we'll log it later */
- log_suppress(1);
-
- if ((r = dm_task_run(dmt)))
- dl->info.exists = 0;
-
- 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.
*/
@@ -1013,16 +412,6 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
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;
@@ -1034,10 +423,14 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
void dev_manager_destroy(struct dev_manager *dm)
{
- dm_hash_destroy(dm->layers);
dm_pool_destroy(dm->mem);
}
+void dev_manager_exit(void)
+{
+ dm_lib_exit();
+}
+
int dev_manager_snapshot_percent(struct dev_manager *dm,
struct logical_volume *lv, float *percent)
{
@@ -1047,15 +440,11 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
/*
* Build a name for the top layer.
*/
- 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, NULL)))
+ return_0;
- if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
- stack;
- return 0;
- }
+ if (!(dlid = build_dlid(dm, lv->lvid.s, NULL)))
+ return_0;
/*
* Try and get some info on this device.
@@ -1085,14 +474,12 @@ int dev_manager_mirror_percent(struct dev_manager *dm,
/*
* Build a name for the top layer.
*/
- 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, NULL)))
+ return_0;
/* FIXME dm_pool_free ? */
- if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
+ if (!(dlid = build_dlid(dm, lv->lvid.s, NULL))) {
log_error("dlid build failed for %s", lv->name);
return 0;
}
@@ -1107,446 +494,191 @@ int dev_manager_mirror_percent(struct dev_manager *dm,
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 0
+ log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name);
- if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, layer))) {
- stack;
- return NULL;
- }
+ 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 (!(dl = dm_hash_lookup(dm->layers, dlid)) &&
- !(dl = _create_dev(dm, name, dlid))) {
- stack;
- return NULL;
- }
+ if (_get_flag(dl, VISIBLE))
+ log_verbose("Removing %s", dl->name);
+ else
+ log_very_verbose("Removing %s", dl->name);
- dl->lv = lv;
+ log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
+ extent_size * seg->le, extent_size * seg->len, target, params);
- if (!_read_only_lv(lv))
- _set_flag(dl, READWRITE);
+ 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);
- return dl;
-}
+ /* Rename? */
+ if ((suffix = rindex(dl->dlid + sizeof(UUID_PREFIX) - 1, '-')))
+ suffix++;
+ newname = build_dm_name(dm->mem, dm->vg_name, dl->lv->name,
+ suffix);
-static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
- int was_origin)
+static int _belong_to_vg(const char *vgname, const char *name)
{
- /*
- * 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);
+ const char *v = vgname, *n = name;
- /* 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;
+ while (*v) {
+ if ((*v != *n) || (*v == '-' && *(++n) != '-'))
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)
- }
+ v++, n++;
}
- if (!was_origin)
+ if (*n == '-' && *(n + 1) != '-')
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;
+ else
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;
-}
+ if (!(snap_seg = find_cow(lv)))
+ 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;
+ old_origin = snap_seg->origin;
- /*
- * 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) {
+ /* Was this the last active snapshot with this origin? */
+ list_iterate_items(lvl, active_head) {
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;
+ if ((snap_seg = find_cow(active)) &&
+ snap_seg->origin == old_origin) {
+ return 1;
+ }
}
- /* 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;
- }
+#endif
- return 1;
-}
+/*************************/
+/* NEW CODE STARTS HERE */
+/*************************/
-/*
- * Inserts the appropriate dev_layers for a logical volume.
- */
-static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv)
+int dev_manager_lv_mknodes(const struct logical_volume *lv)
{
- struct lv_segment *snap_seg;
+ char *name;
- /*
- * 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);
- }
+ if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name,
+ lv->name, NULL)))
+ return_0;
- return _expand_vanilla(dm, lv, 0);
+ return fs_add_lv(lv, name);
}
-/*
- * Clears the mark bit on all layers.
- */
-static void _clear_marks(struct dev_manager *dm, int flag)
+int dev_manager_lv_rmnodes(const struct logical_volume *lv)
{
- 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);
- }
+ return fs_del_lv(lv);
}
-/*
- * Propogates marks via the pre_create dependency list.
- */
-static int _trace_layer_marks(struct dev_manager *dm, struct dev_layer *dl,
- int flag)
+static int _add_dev_to_deptree(struct dev_manager *dm, struct deptree *dtree,
+ struct logical_volume *lv, const char *layer)
{
- 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;
- }
+ char *dlid, *name;
+ struct dm_info info;
- if (_get_flag(dep, flag))
- continue;
+ if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
+ return_0;
- /* FIXME Only propagate LV ACTIVE dependencies for now */
- if ((flag != ACTIVE) && _get_flag(dl, NOPROPAGATE))
- continue;
+ if (!(dlid = build_dlid(dm, lv->lvid.s, layer)))
+ return_0;
- _set_flag(dep, flag);
+ 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 (!_trace_layer_marks(dm, dep, flag)) {
- stack;
- 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;
}
return 1;
}
/*
- * Calls _trace_single for every marked layer.
+ * Add LV and any known dependencies
*/
-static int _trace_all_marks(struct dev_manager *dm, int flag)
+static int _add_lv_to_deptree(struct dev_manager *dm, struct deptree *dtree, struct logical_volume *lv)
{
- struct dm_hash_node *hn;
- struct dev_layer *dl;
+ if (!_add_dev_to_deptree(dm, dtree, lv, NULL))
+ return_0;
- 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;
- }
- }
+ /* 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;
}
-/*
- * Finds the specified layer.
- */
-static struct dev_layer *_lookup(struct dev_manager *dm,
- const char *lvid, const char *layer)
+static struct deptree *_create_partial_deptree(struct dev_manager *dm, struct logical_volume *lv)
{
- char *dlid;
- struct dev_layer *dl;
+ struct deptree *dtree;
+ struct list *snh, *snht;
- if (!(dlid = _build_dlid(dm->mem, lvid, layer))) {
- stack;
+ if (!(dtree = dm_deptree_create())) {
+ log_error("Partial deptree creation failed for %s.", lv->name);
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 (!_add_lv_to_deptree(dm, dtree, lv)) {
+ stack;
+ goto fail;
+ }
- if (!(dl = _lookup(dm, lvl->lv->lvid.s, NULL))) {
+ /* 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;
- return 0;
+ goto fail;
}
- _set_flag(dl, flag);
- }
-
- if (!_trace_all_marks(dm, flag)) {
- stack;
- return 0;
- }
+ return dtree;
- return 1;
+fail:
+ dm_deptree_free(dtree);
+ return NULL;
}
-static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl)
+int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
+ struct deptree_node *node, int start_area, int areas)
{
- 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;
- }
+ uint64_t extent_size = seg->lv->vg->extent_size;
+ uint32_t s;
+ char *dlid;
- if (dep->info.exists & !_suspend(dep)) {
- 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;
}
}
@@ -1554,789 +686,305 @@ static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl)
return 1;
}
-static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl)
+static int _add_origin_target_to_deptree(struct dev_manager *dm,
+ struct deptree *dtree,
+ struct deptree_node *dnode,
+ struct logical_volume *lv)
{
- 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;
- }
+ const char *real_dlid;
- if (!_resume_with_deps(dm, dep)) {
- stack;
- return 0;
- }
- }
+ if (!(real_dlid = build_dlid(dm, lv->lvid.s, "real")))
+ return_0;
- if (dl->info.exists & !_get_flag(dl, SUSPENDED) && !_resume(dl)) {
- stack;
- return 0;
- }
+ if (!dm_deptree_node_add_snapshot_origin_target(dnode, lv->size, real_dlid))
+ 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)
+static int _add_snapshot_target_to_deptree(struct dev_manager *dm,
+ struct deptree *dtree,
+ struct deptree_node *dnode,
+ struct logical_volume *lv)
{
- struct str_list *strl;
- struct dev_layer *dep;
- const char *dlid;
- char *newname, *suffix;
+ const char *origin_dlid;
+ const char *cow_dlid;
+ struct lv_segment *snap_seg;
+ uint64_t size;
- /* Suspend? */
- if (_get_flag(dl, SUSPENDED) &&
- (!_suspend_parents(dm, dl) || !_suspend(dl))) {
- stack;
+ if (!(snap_seg = find_cow(lv))) {
+ log_error("Couldn't find snapshot for '%s'.", lv->name);
return 0;
}
- list_iterate_items(strl, &dl->pre_create) {
- dlid = strl->str;
+ if (!(origin_dlid = build_dlid(dm, snap_seg->origin->lvid.s, "real")))
+ return_0;
- if (!(dep = dm_hash_lookup(dm->layers, dlid))) {
- log_error("Couldn't find device layer '%s'.", dlid);
- return 0;
- }
+ if (!(cow_dlid = build_dlid(dm, snap_seg->cow->lvid.s, "cow")))
+ 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;
- }
+ size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size;
- /* Reload? */
- if (_get_flag(dl, RELOAD) &&
- (!_suspend_parents(dm, dl) || !_suspend(dl) ||
- !_load(dm, dl, DM_DEVICE_RELOAD))) {
- 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;
}
-static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
+static int _add_target_to_deptree(struct dev_manager *dm,
+ struct deptree *dtree,
+ struct deptree_node *dnode,
+ struct lv_segment *seg)
{
- struct lv_list *lvl;
+ uint64_t extent_size = seg->lv->vg->extent_size;
- /*
- * 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;
- }
+ 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 1;
+ 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);
}
-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);
- }
- }
+static int _add_new_lv_to_deptree(struct dev_manager *dm, struct deptree *dtree,
+ struct logical_volume *lv, const char *layer);
- return 1;
-}
-
-static int _populate_pre_suspend_lists(struct dev_manager *dm)
+static int _add_segment_to_deptree(struct dev_manager *dm,
+ struct deptree *dtree,
+ struct deptree_node *dnode,
+ struct lv_segment *seg,
+ const char *layer)
{
- 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;
- }
+ uint32_t s;
+ struct list *snh;
- if (!str_list_add(dm->mem, &dep->pre_suspend, dl->dlid)) {
- stack;
- return 0;
- }
- }
+ /* 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 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;
- }
+ /* Add mirror log */
+ if (seg->log_lv &&
+ !_add_new_lv_to_deptree(dm, dtree, seg->log_lv, NULL))
+ return_0;
- if (_remove(dl)) {
- change = 1;
- list_del(rh);
- }
+ /* 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;
}
-
- } 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;
- }
+ 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;
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)
+static int _add_new_lv_to_deptree(struct dev_manager *dm, struct deptree *dtree,
+ struct logical_volume *lv, const char *layer)
{
- struct dm_hash_node *hn;
- struct dev_layer *dl;
+ struct lv_segment *seg;
+ struct lv_layer *lvlayer;
+ struct deptree_node *dnode;
+ char *name, *dlid;
- if (!_build_all_layers(dm, vg)) {
- stack;
- return 0;
- }
+ if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
+ return_0;
- /*
- * Mark all layer that need reloading.
- */
- _clear_marks(dm, RELOAD);
- if (!_mark_lvs(dm, &dm->reload_list, RELOAD)) {
- stack;
- return 0;
- }
+ if (!(dlid = build_dlid(dm, lv->lvid.s, layer)))
+ return_0;
- /*
- * Mark all layers that should be active.
- */
- _clear_marks(dm, ACTIVE);
- if (!_mark_lvs(dm, &dm->active_list, ACTIVE)) {
- 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;
- /*
- * Mark all layers that should be left suspended.
- */
- _clear_marks(dm, SUSPENDED);
- if (!_mark_lvs(dm, &dm->suspend_list, SUSPENDED)) {
- stack;
+ /* 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;
}
- if (!_fill_in_remove_list(dm)) {
- stack;
- return 0;
- }
-
- if (!_populate_pre_suspend_lists(dm)) {
- stack;
- return 0;
- }
+ lvlayer->lv = lv;
/*
- * Now only top level devices will be unmarked.
+ * 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.
*/
- 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;
+ 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;
}
/*
- * ATM we decide which vg a layer belongs to by
- * looking at the beginning of the device
- * name.
+ * Create LV symlinks for children of supplied root node.
*/
-static int _belong_to_vg(const char *vgname, const char *name)
+static int _create_lv_symlinks(struct dev_manager *dm, struct deptree_node *root)
{
- 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;
+ void *handle = NULL;
+ struct deptree_node *child;
+ struct lv_layer *lvlayer;
+ char *vgname, *lvname, *layer;
+ const char *name;
+ int r = 1;
- if (!dm_task_run(dmt))
- goto out;
+ while ((child = dm_deptree_next_child(&handle, root, 0))) {
+ if (!(lvlayer = (struct lv_layer *) dm_deptree_node_get_context(child)))
+ continue;
- if (!(names = dm_task_get_names(dmt)))
- goto out;
+ /* Detect rename */
+ name = dm_deptree_node_get_name(child);
- 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;
+ 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;
- 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;
+ return r;
}
-static int _add_lvs(struct dm_pool *mem,
- struct list *head, struct logical_volume *origin)
+static int _clean_tree(struct dev_manager *dm, struct logical_volume *lv, struct deptree_node *root)
{
- struct lv_segment *snap_seg;
- struct lv_list *lvl;
+ void *handle = NULL;
+ struct deptree_node *child;
+ char *vgname, *lvname, *layer;
+ const char *name, *uuid;
- list_iterate_items(lvl, &origin->vg->lvs) {
- if (lvl->lv->status & SNAPSHOT)
+ while ((child = dm_deptree_next_child(&handle, root, 0))) {
+ if (!(name = dm_deptree_node_get_name(child)))
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);
- }
- }
-
- _remove_lv(active_head, lv);
- if (!(snap_seg = find_cow(lv)))
- return 1;
-
- old_origin = snap_seg->origin;
-
- /* Was this the last active snapshot with this origin? */
- list_iterate_items(lvl, active_head) {
- active = lvl->lv;
- if ((snap_seg = find_cow(active)) &&
- snap_seg->origin == old_origin) {
- return 1;
- }
- }
-
- return _add_lvs(dm->mem, &dm->reload_list, old_origin);
-}
-
-static int _remove_suspended_lvs(struct dev_manager *dm,
- struct logical_volume *lv)
-{
- struct logical_volume *suspended;
- struct lv_segment *snap_seg;
- struct list *suspend_head;
- struct lv_list *lvl;
-
- suspend_head = &dm->suspend_list;
-
- /* 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);
- }
- }
-
- _remove_lv(suspend_head, lv);
-
- return 1;
-}
-
-static int _targets_present(struct dev_manager *dm, struct list *lvs)
-{
- 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;
- }
- }
- }
- }
-
- 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 (!segtype->ops->target_present ||
- !segtype->ops->target_present()) {
- log_error("Can't expand LV: Mirror support missing "
- "from kernel?");
- return 0;
- }
- }
-
- if (snapshots) {
- if (!(segtype = get_segtype_from_string(dm->cmd, "snapshot"))) {
- log_error("Can't expand LV: Snapshot support "
- "missing from tools?");
- return 0;
- }
-
- if (!segtype->ops->target_present ||
- !segtype->ops->target_present()) {
- log_error("Can't expand LV: Snapshot support missing "
- "from kernel?");
- return 0;
- }
- }
-
- return 1;
-}
-
-static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
-{
- char *dlid;
- struct lv_list *lvl;
- struct dev_layer *dl;
-
- list_iterate_items(lvl, &vg->lvs) {
- if (lvl->lv->status & SNAPSHOT)
+ if (!(uuid = dm_deptree_node_get_uuid(child)))
continue;
- if (!(dlid = _build_dlid(dm->mem, lvl->lv->lvid.s, NULL))) {
- stack;
- return 0;
- }
-
- dl = dm_hash_lookup(dm->layers, dlid);
- dm_pool_free(dm->mem, dlid);
-
- if (dl) {
- log_debug("Found active lv %s%s", lvl->lv->name,
- dl->info.suspended ? " (suspended)" : "");
-
- if (!_add_lv(dm->mem, &dm->active_list, lvl->lv)) {
- stack;
- return 0;
- }
-
- if (dl->info.suspended) {
- if (!_add_lv(dm->mem, &dm->suspend_list, lvl->lv)) {
- stack;
- return 0;
- }
- }
- }
- }
-
- return 1;
-}
-
-static int _action_activate(struct dev_manager *dm, 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;
- }
-
- /* Get into known state - remove from active list if present */
- if (!_remove_lvs(dm, lv)) {
- stack;
- 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;
- }
-
- /* Get into known state - remove from suspend list if present */
- if (!_remove_suspended_lvs(dm, lv)) {
- stack;
- return 0;
- }
-
- if (!_targets_present(dm, &dm->active_list) ||
- !_targets_present(dm, &dm->reload_list)) {
- stack;
- return 0;
- }
-
- if (!_execute(dm, lv->vg)) {
- stack;
- return 0;
- }
-
- return 1;
-}
-
-int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv)
-{
- return _action_activate(dm, lv);
-}
-
-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))) {
- stack;
- return 0;
- }
-
- return fs_add_lv(lv, name);
-}
-
-int dev_manager_lv_rmnodes(const struct logical_volume *lv)
-{
- return fs_del_lv(lv);
-}
-
-void dev_manager_exit(void)
-{
- dm_lib_exit();
-}
-
-/*
- * New deactivation code
- */
-static int _add_lv_to_deptree(struct dev_manager *dm, struct deptree *dtree, struct logical_volume *lv)
-{
- char *dlid, *name;
- struct dm_info info;
-
- 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;
- }
+ if (!split_dm_name(dm->mem, name, &vgname, &lvname, &layer)) {
+ log_error("_clean_tree: Couldn't split up device name %s.", name);
+ 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;
- }
+ /* Not meant to be top level? */
+ if (!*layer)
+ continue;
- 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;
+ if (!dm_deptree_deactivate_children(root, uuid, strlen(uuid)))
+ return_0;
}
- /* FIXME Check for any related nodes left behind e.g. -real */
-
return 1;
}
-static struct deptree *_create_partial_deptree(struct dev_manager *dm, struct logical_volume *lv)
-{
- struct deptree *dtree;
- struct list *snh, *snht;
-
- if (!(dtree = dm_deptree_create())) {
- log_error("partial deptree creation failed");
- return NULL;
- }
-
- if (!_add_lv_to_deptree(dm, dtree, lv)) {
- stack;
- goto fail;
- }
-
- /* 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;
- }
- }
-
- return dtree;
-
-fail:
- dm_deptree_free(dtree);
- return NULL;
-}
-
-/*
- * 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 6a7519fe..19b6572c 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 c51079b6..8a8b8ac7 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 906d1df1..a41619af 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 4c590559..36eed30f 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 9e03a6bb..b6b5e4e2 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 7ac0887e..415feb0b 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 dcd97364..e3a7e262 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 a1f91125..e620e49c 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)
/*
* <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
*/
-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 ef9fbc72..855f1970 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 a19d6794..d918f4ef 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 84da3a0a..e23da877 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 f1439b60..6c3ccf06 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 eb8018ef..57051eb6 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 4977397d..31a8405b 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 003c727c..e29af6f3 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;
}