[lvm-devel] [PATCH 4/6] thin: lvchange spare lv manipulation

Zdenek Kabelac zkabelac at redhat.com
Tue Jun 25 11:56:04 UTC 2013


Allow lvchange of spare flag for an LV.

Signed-off-by: Zdenek Kabelac <zkabelac at redhat.com>
---
 tools/args.h     |  1 +
 tools/commands.h |  5 ++--
 tools/lvchange.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/tools/args.h b/tools/args.h
index 2fed97e..b8d0ad6 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -76,6 +76,7 @@ arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0)
 arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0)
 arg(discards_ARG, '\0', "discards", discards_arg, 0)
 arg(force_long_ARG, '\0', "force", NULL, ARG_COUNTABLE)
+arg(spare_ARG, '\0', "spare", yes_no_arg, 0)
 arg(stripes_long_ARG, '\0', "stripes", int_arg, 0)
 arg(sysinit_ARG, '\0', "sysinit", NULL, 0)
 arg(thinpool_ARG, '\0', "thinpool", string_arg, 0)
diff --git a/tools/commands.h b/tools/commands.h
index 2d99d5a..ca29b81 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -92,6 +92,7 @@ xx(lvchange,
    "\t[-r|--readahead ReadAheadSectors|auto|none]\n"
    "\t[--refresh]\n"
    "\t[--resync]\n"
+   "\t[--spare {y|n}]\n"
    "\t[--syncaction {check|repair}\n"
    "\t[--sysinit]\n"
    "\t[-t|--test]\n"
@@ -106,8 +107,8 @@ xx(lvchange,
    alloc_ARG, autobackup_ARG, activate_ARG, available_ARG, contiguous_ARG,
    discards_ARG, force_ARG, ignorelockingfailure_ARG, ignoremonitoring_ARG,
    major_ARG, minor_ARG, monitor_ARG, minrecoveryrate_ARG, maxrecoveryrate_ARG,
-   noudevsync_ARG, partial_ARG,
-   permission_ARG, persistent_ARG, poll_ARG, readahead_ARG, resync_ARG,
+   noudevsync_ARG, partial_ARG, permission_ARG, persistent_ARG,
+   poll_ARG, readahead_ARG, resync_ARG, spare_ARG,
    refresh_ARG, addtag_ARG, deltag_ARG, syncaction_ARG, sysinit_ARG, test_ARG,
    writebehind_ARG, writemostly_ARG, zero_ARG)
 
diff --git a/tools/lvchange.c b/tools/lvchange.c
index c88d8ef..f7fcf44 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -101,6 +101,77 @@ out:
 	return r;
 }
 
+static int lvchange_spare(struct cmd_context *cmd,
+			  struct logical_volume *lv)
+{
+	struct lv_list *lvl;
+	uint64_t max_size = 0;
+	unsigned spare = arg_uint_value(cmd, spare_ARG, 0);
+
+	if (lv_is_active(lv)) {
+		log_error("Cannot change spare for active logical volume \"%s\".",
+			  lv->name);
+		return 0;
+	}
+
+	if (spare) {
+		if (lv_is_spare(lv)) {
+			log_error("Logical volume \"%s\" is already spare volume.",
+				  lv->name);
+			return 0;
+		}
+
+		if (!(lv->status & LVM_WRITE)) {
+			log_error("Cannot use read-only logical volume \"%s\" for spare.",
+				  lv->name);
+			return 0;
+		}
+
+		if (!lv_is_visible(lv)) {
+			log_error("Cannot use invisible logical volume \"%s\" for spare.",
+				  lv->name);
+			return 0;
+		}
+
+		/* FIXME: validate size */
+		dm_list_iterate_items(lvl, &lv->vg->lvs)
+			if (lv_is_thin_pool_metadata(lvl->lv) &&
+			    (max_size < lvl->lv->size))
+				max_size = lvl->lv->size;
+
+		if (lv->size < max_size) {
+			log_error("Logical volume \"%s\" must have at least %s for spare.",
+				  lv->name, display_size(lv->vg->cmd, max_size));
+			return 0;
+		}
+
+		if (lv->vg->spare) {
+			log_print_unless_silent("Replacing spare logical volume \"%s\".",
+						lv->vg->spare->name);
+			lv->vg->spare->status &= ~SPARE_LV;
+		}
+
+		lv->vg->spare = lv;
+		lv->status |= SPARE_LV;
+	} else {
+		if (!lv_is_spare(lv)) {
+			log_error("Logical volume \"%s\" is not a spare volume.",
+				  lv->name);
+			return 0;
+		}
+
+		lv->vg->spare = NULL;
+		lv->status &= ~SPARE_LV;
+	}
+
+	log_very_verbose("Updating spare logical volume \"%s\" on disk(s).", lv->name);
+	if (!vg_write(lv->vg) || !vg_commit(lv->vg))
+		return_0;
+
+	backup(lv->vg);
+	return 1;
+}
+
 static int lvchange_pool_update(struct cmd_context *cmd,
 				struct logical_volume *lv)
 {
@@ -930,7 +1001,9 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
 	    lv_is_virtual_origin(origin = origin_from_cow(lv)))
 		lv = origin;
 
-	if (!(lv_is_visible(lv)) && !lv_is_virtual_origin(lv)) {
+	if (!lv_is_visible(lv) &&
+	    !lv_is_spare(lv) &&
+	    !lv_is_virtual_origin(lv)) {
 		log_error("Unable to change internal LV %s directly",
 			  lv->name);
 		return ECMD_FAILED;
@@ -997,6 +1070,16 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
 		}
 	}
 
+	if (arg_count(cmd, spare_ARG)) {
+		if (!archived && !archive(lv->vg)) {
+			stack;
+			return ECMD_FAILED;
+		}
+		archived = 1;
+		doit += lvchange_spare(cmd, lv);
+		docmds++;
+	}
+
 	if (arg_count(cmd, discards_ARG) ||
 	    arg_count(cmd, zero_ARG)) {
 		if (!archived && !archive(lv->vg)) {
@@ -1120,6 +1203,7 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
 		arg_count(cmd, contiguous_ARG) ||
 		arg_count(cmd, permission_ARG) ||
 		arg_count(cmd, readahead_ARG) ||
+		arg_count(cmd, spare_ARG) ||
 		arg_count(cmd, persistent_ARG) ||
 		arg_count(cmd, addtag_ARG) ||
 		arg_count(cmd, deltag_ARG);
-- 
1.8.2.1




More information about the lvm-devel mailing list