Skip to contentSkip to conversation

spare LV support

PATCH New Zdenek Kabelac 1 participant 7 messages Jun 25, 2013

lore
Share & tools
lore
#0 lore raw

cover spare LV support

Initial preparation for handling spare LVs within LV. Spare LV is going to be used for thin pool recovery. There is one spare LV per pool always sized as the largest thin pool metadata LV in the VG.

Zdenek Kabelac (6):
thin: add spare lv support
thin: report spare as 'e' volume type
thin: removal of spare disables recovery
thin: lvchange spare lv manipulation
thin: add spare lvcreate support
thin: unfinished lvconvert

 lib/format_text/flags.c          |  1 +
 lib/format_text/import_vsn1.c    | 10 +++++
 lib/metadata/lv.c                |  1 +
 lib/metadata/lv_manip.c          | 19 +++++++++
 lib/metadata/metadata-exported.h |  4 ++
 lib/metadata/metadata.c          | 24 +++++++----
 lib/metadata/snapshot_manip.c    |  3 +-
 lib/metadata/vg.h                |  2 +
 tools/args.h                     |  1 +
 tools/commands.h                 | 18 +++++----
 tools/lvchange.c                 | 86 +++++++++++++++++++++++++++++++++++++++-
 tools/lvconvert.c                |  2 +
 tools/lvcreate.c                 | 83 +++++++++++++++++++++++++++++++++++++-
 13 files changed, 235 insertions(+), 19 deletions(-)
Signature · 1 line
1.8.2.1
#1 lore raw

PATCH 1/6 thin: add spare lv support

Add support for SPARE volume.

---
 lib/format_text/flags.c          |  1 +
 lib/format_text/import_vsn1.c    | 10 ++++++++++
 lib/metadata/metadata-exported.h |  3 +++
 lib/metadata/metadata.c          | 24 ++++++++++++++++--------
 lib/metadata/snapshot_manip.c    |  3 ++-
 lib/metadata/vg.h                |  2 ++
 6 files changed, 34 insertions(+), 9 deletions(-)
lib/format_text/flags.c +1 -0
index 28a7dc4..6d15d20 100644
@@ -59,6 +59,7 @@ static const struct flag _lv_flags[] = {
 	{LV_NOTSYNCED, "NOTSYNCED", STATUS_FLAG},
 	{LV_REBUILD, "REBUILD", STATUS_FLAG},
 	{LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG},
+	{SPARE_LV, "SPARE", STATUS_FLAG},
 	{RAID, NULL, 0},
 	{RAID_META, NULL, 0},
 	{RAID_IMAGE, NULL, 0},
lib/format_text/import_vsn1.c +10 -0
index 852f2c5..d9f05c9 100644
@@ -605,6 +605,16 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
 	if (timestamp && !lv_set_creation(lv, hostname, timestamp))
 		return_0;
 
+	if (lv_is_spare(lv)) {
+		if (lv->vg->spare) {
+			/* CHECKME: maybe just ignore all others ? */
+			log_error("VG with multiple spare LVs is not supported.");
+			return 0;
+		}
+		log_debug_metadata("Logical volume %s is spare.", lv->name);
+		lv->vg->spare = lv;
+	}
+
 	return 1;
 }
 
lib/metadata/metadata-exported.h +3 -0
index 10aea9e..453b98b 100644
@@ -92,6 +92,8 @@
 
 #define LV_WRITEMOSTLY		UINT64_C(0x0000010000000000)	/* LV (RAID1) */
 
+#define SPARE_LV		UINT64_C(0x0000020000000000)	/* LV internal use */
+
 #define LVM_READ		UINT64_C(0x00000100)	/* LV, VG */
 #define LVM_WRITE		UINT64_C(0x00000200)	/* LV, VG */
 
@@ -153,6 +155,7 @@
 #define lv_is_raid_type(lv)	(((lv)->status & (RAID | RAID_IMAGE | RAID_META)) ? 1 : 0)
 
 #define lv_is_virtual(lv)	(((lv)->status & VIRTUAL) ? 1 : 0)
+#define lv_is_spare(lv)		(((lv)->status & SPARE_LV) ? 1 : 0)
 
 /* Ordered list - see lv_manip.c */
 typedef enum {
lib/metadata/metadata.c +16 -8
index 8a98aa6..ecedbdc 100644
@@ -2290,9 +2290,10 @@ int vg_validate(struct volume_group *vg)
 	struct str_list *sl;
 	char uuid[64] __attribute__((aligned(8)));
 	int r = 1;
-	uint32_t hidden_lv_count = 0, lv_count = 0, lv_visible_count = 0;
-	uint32_t pv_count = 0;
-	uint32_t num_snapshots = 0;
+	unsigned hidden_lv_count = 0, lv_count = 0, lv_visible_count = 0;
+	unsigned pv_count = 0;
+	unsigned num_snapshots = 0;
+	unsigned spare_count = 0;
 	struct validate_hash vhash = { NULL };
 
 	if (vg->alloc == ALLOC_CLING_BY_TAGS) {
@@ -2404,6 +2405,12 @@ int vg_validate(struct volume_group *vg)
 				r = 0;
 			}
 
+		if (lv_is_spare(lvl->lv) && ++spare_count > 1) {
+			log_error(INTERNAL_ERROR "LV %s is %d. spare (allowed is one).",
+				  lvl->lv->name, spare_count);
+			r = 0;
+		}
+
 		if (lvl->lv->status & VISIBLE_LV)
 			continue;
 
@@ -2429,11 +2436,12 @@ int vg_validate(struct volume_group *vg)
 	/*
 	 * all volumes = visible LVs + snapshot_cows + invisible LVs
 	 */
-	if (lv_count != lv_visible_count + num_snapshots + hidden_lv_count) {
-		log_error(INTERNAL_ERROR "#internal LVs (%u) != #LVs (%"
-			  PRIu32 ") + #snapshots (%" PRIu32 ") + #internal LVs (%u) in VG %s",
-			  lv_count, lv_visible_count,
-			  num_snapshots, hidden_lv_count, vg->name);
+	if (lv_count != lv_visible_count + num_snapshots + hidden_lv_count + spare_count) {
+		log_error(INTERNAL_ERROR "#LVs (%u) != #visible LVs (%u) "
+			  "+ #snapshots (%u) + #internal LVs (%u) "
+			  "+ #spare LV (%u) in VG %s",
+			  lv_count, lv_visible_count, num_snapshots,
+			  hidden_lv_count, spare_count, vg->name);
 		r = 0;
 	}
 
lib/metadata/snapshot_manip.c +2 -1
index e0d2f5b..6da592e 100644
@@ -75,7 +75,8 @@ int lv_is_cow_covering_origin(const struct logical_volume *lv)
 
 int lv_is_visible(const struct logical_volume *lv)
 {
-	if (lv->status & SNAPSHOT)
+	/* spare LV is implicitely invisible */
+	if (lv->status & (SNAPSHOT | SPARE_LV))
 		return 0;
 
 	if (lv_is_cow(lv)) {
lib/metadata/vg.h +2 -0
index 0dc3ba7..dc5bb12 100644
@@ -20,6 +20,7 @@ struct dm_pool;
 struct format_instance;
 struct dm_list;
 struct id;
+struct logical_volume;
 
 typedef enum {
 	ALLOC_INVALID,
@@ -120,6 +121,7 @@ struct volume_group {
 	uint32_t mda_copies; /* target number of mdas for this VG */
 
 	struct dm_hash_table *hostnames; /* map of creation hostnames */
+	struct logical_volume *spare; /* pointer for spare LV in this VG */
 };
 
 struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd,
Signature · 1 line
1.8.2.1
#2 lore raw

PATCH 2/6 thin: report spare as 'e' volume type

In reply to Zdenek Kabelac

Reuse m'e'tadata volume type as spar'e'
since essentially they are related and there is no big reason to introduce new flag - but of course we may use some other letters.

---
 lib/metadata/lv.c | 1 +
 1 file changed, 1 insertion(+)
lib/metadata/lv.c +1 -0
index 6215e1a..b95d0a3 100644
@@ -547,6 +547,7 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
 	else if (lv_is_origin(lv) || lv_is_external_origin(lv))
 		repstr[0] = (lv_is_merging_origin(lv)) ? 'O' : 'o';
 	else if (lv_is_thin_pool_metadata(lv) ||
+		 lv_is_spare(lv) ||
 		 (lv->status & RAID_META))
 		repstr[0] = 'e';
 	else if (lv->status & RAID)
Signature · 1 line
1.8.2.1
#3 lore raw

PATCH 3/6 thin: removal of spare disables recovery

In reply to Zdenek Kabelac

Warn user when removing spare LV.

---
 lib/metadata/lv_manip.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
lib/metadata/lv_manip.c +19 -0
index 8acca49..f0fad05 100644
@@ -3623,6 +3623,7 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
 {
 	percent_t snap_percent;
 	struct dm_list *snh, *snht;
+	struct lv_list *lvl;
 	struct lvinfo info;
 
 	if (lv_is_cow(lv)) {
@@ -3681,6 +3682,24 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
 	    !_lv_remove_segs_using_this_lv(cmd, lv, force, level, "pool"))
 		return_0;
 
+	if (lv_is_thin_pool(lv) && lv->vg->spare) {
+		dm_list_iterate_items(lvl, &lv->vg->lvs)
+			if (lv_is_thin_pool(lvl->lv) && lvl->lv != lv)
+				break;
+
+		if ((!lv_is_thin_pool(lvl->lv) || lvl->lv == lv) &&
+		    !lv_remove_with_dependencies(cmd, lv->vg->spare, force, level + 1))
+			return_0;
+	}
+
+	if (lv_is_spare(lv) &&
+	    (force == PROMPT) &&
+	    (yes_no_prompt("Removal of spare logical volume \"%s\" disables thin pool recovery. "
+			   "Proceed? [y/n]: ", lv->name) == 'n')) {
+		log_error("Logical volume \"%s\" not removed.", lv->name);
+		return 0;
+	}
+
 	return lv_remove_single(cmd, lv, force);
 }
 
Signature · 1 line
1.8.2.1
#4 lore raw

PATCH 4/6 thin: lvchange spare lv manipulation

In reply to Zdenek Kabelac

Allow lvchange of spare flag for an LV.

---
 tools/args.h     |  1 +
 tools/commands.h |  5 ++--
 tools/lvchange.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 89 insertions(+), 3 deletions(-)
tools/args.h +1 -0
index 2fed97e..b8d0ad6 100644
@@ -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)
tools/commands.h +3 -2
index 2d99d5a..ca29b81 100644
@@ -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)
 
tools/lvchange.c +85 -1

110 lines not on this page · raw message

Signature · 1 line
1.8.2.1
#5 lore raw

PATCH 5/6 thin: add spare lvcreate support

In reply to Zdenek Kabelac

Add --spare option and create and hanle spare lv
when thin pool is created.

---
 lib/metadata/metadata-exported.h |  1 +
 tools/commands.h                 | 10 +++--
 tools/lvcreate.c                 | 83 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 88 insertions(+), 6 deletions(-)
lib/metadata/metadata-exported.h +1 -0
index 453b98b..a368dca 100644
@@ -615,6 +615,7 @@ struct lvcreate_params {
 	int minor; /* all */
 	int log_count; /* mirror */
 	int nosync; /* mirror */
+	int spare; /* thin pool */
 	activation_change_t activate; /* non-snapshot, non-mirror */
 	thin_discards_t discards;     /* thin */
 
tools/commands.h +6 -4
index ca29b81..d1cef36 100644
@@ -208,6 +208,7 @@ xx(lvcreate,
    "\t[-T|--thin  [-c|--chunksize  ChunkSize]\n"
    "\t  [--discards {ignore|nopassdown|passdown}]\n"
    "\t  [--poolmetadatasize MetadataSize[bBsSkKmMgG]]]\n"
+   "\t  [--spare {y|n}]\n"
    "\t[--thinpool ThinPoolLogicalVolume{Name|Path}]\n"
    "\t[-t|--test]\n"
    "\t[--type VolumeType]\n"
@@ -251,10 +252,11 @@ xx(lvcreate,
    chunksize_ARG, contiguous_ARG, corelog_ARG, discards_ARG, extents_ARG,
    ignoremonitoring_ARG, major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG,
    monitor_ARG, minrecoveryrate_ARG, maxrecoveryrate_ARG, name_ARG, nosync_ARG,
-   noudevsync_ARG, permission_ARG,
-   persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG, snapshot_ARG,
-   stripes_ARG, stripesize_ARG, test_ARG, thin_ARG, thinpool_ARG, type_ARG,
-   virtualoriginsize_ARG, poolmetadatasize_ARG, virtualsize_ARG, zero_ARG)
+   noudevsync_ARG, permission_ARG, persistent_ARG, poolmetadatasize_ARG,
+   readahead_ARG, regionsize_ARG,
+   size_ARG, snapshot_ARG, spare_ARG, stripes_ARG, stripesize_ARG,
+   test_ARG, thin_ARG, thinpool_ARG, type_ARG,
+   virtualoriginsize_ARG,virtualsize_ARG, zero_ARG)
 
 xx(lvdisplay,
    "Display information about a logical volume",
tools/lvcreate.c +81 -2

114 lines not on this page · raw message

Signature · 1 line
1.8.2.1
#6 lore raw

PATCH 6/6 thin: unfinished lvconvert

In reply to Zdenek Kabelac

begining of lvconvert support for spare LV.
will match what can be made in lvcreate.

---
 tools/commands.h  | 3 ++-
 tools/lvconvert.c | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)
tools/commands.h +2 -1
index d1cef36..b1e5544 100644
@@ -166,6 +166,7 @@ xx(lvconvert,
    "\t[--poolmetadata ThinMetadataLogicalVolume[Path] |\n"
    "\t [--poolmetadatasize size]\n"
    "\t [-r|--readahead ReadAheadSectors|auto|none]\n"
+   "\t [--spare {y|n}]\n"
    "\t [--stripes Stripes [-I|--stripesize StripeSize]]]\n"
    "\t[-T|--thin ExternalLogicalVolume[Path]\n"
    "\t [--originname NewExternalOriginVolumeName]]\n"
@@ -177,7 +178,7 @@ xx(lvconvert,
    readahead_ARG, regionsize_ARG, repair_ARG, replace_ARG, snapshot_ARG, splitmirrors_ARG,
    trackchanges_ARG, type_ARG, stripes_long_ARG, stripesize_ARG, test_ARG,
    chunksize_ARG, discards_ARG, poolmetadata_ARG, poolmetadatasize_ARG,
-   originname_ARG, thin_ARG, thinpool_ARG,
+   originname_ARG, spare_ARG, thin_ARG, thinpool_ARG,
    use_policies_ARG, force_ARG, zero_ARG)
 
 xx(lvcreate,
tools/lvconvert.c +2 -0
index be6b55f..7ee3d4b 100644
@@ -22,6 +22,7 @@ struct lvconvert_params {
 	int snapshot;
 	int merge;
 	int merge_mirror;
+	int spare;
 	int thin;
 	int yes;
 	int zero;
@@ -495,6 +496,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
 			return_0;
 	}
 
+	lp->spare = arg_uint_value(cmd, spare_ARG, 0);
 	lp->force = arg_count(cmd, force_ARG);
 	lp->yes = arg_count(cmd, yes_ARG);
 
Signature · 1 line
1.8.2.1