[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[lvm-devel] [PATCH 3/3] lvconvert mirror to wait for sync completion and remove temporary mirrors



With this patch, like pvmove, lvconvert mirror will
wait for sync completion, showing progress periodically,
and remove the temporary mirror after the completion.

If you don't like lvconvert to wait for sync completion,
use '--background' option. '--interval <sec>' option is also
available like pvmove.

If you stop lvconvert command, you can restart the polling
daemon with 'lvconvert <LV name>'.

Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
lvconvert can wait for sync comletion of added mirrors, like pvmove.

Changes in lvconvert:
  - Added polldaemon setup code.
    After successful addition of mirror, start polldaemon.
  - Added 'lv_name_full' to lvconvert_params.
    It contains lv name with "vg/lv" format and used by polldaemon.
  - Added 'wait_daemon' to lvconvert_param.
    lvconvert_mirror() will set it if mirror is added
    and polldaemon needs to be invoked.
  - Added '-i/--interval' and '-b/--background' options like pvmove.
  - Updated manpage

# lvcreate -L1G vg
  Logical volume "lvol0" created
# lvconvert -m+1 vg/lvol0
  Logical volume lvol0 converted.
# lvconvert -m+1 vg/lvol0
  vg/lvol0: Converted: 17.6%
  vg/lvol0: Converted: 36.3%
  vg/lvol0: Converted: 54.5%
  vg/lvol0: Converted: 72.3%
  vg/lvol0: Converted: 91.0%
  vg/lvol0: Converted: 100.0%
  Logical volume lvol0 converted.
# lvs -a vg
  LV               VG   Attr   LSize Origin Snap%  Move Log        Copy% 
  lvol0            vg   mwi-a- 1.00G                    lvol0_mlog 100.00
  [lvol0_mimage_0] vg   iwi-ao 1.00G                                     
  [lvol0_mimage_1] vg   iwi-ao 1.00G                                     
  [lvol0_mimage_2] vg   iwi-ao 1.00G                                     
  [lvol0_mlog]     vg   lwi-ao 2.00M                     

Index: LVM2.work/tools/lvconvert.c
===================================================================
--- LVM2.work.orig/tools/lvconvert.c
+++ LVM2.work/tools/lvconvert.c
@@ -13,6 +13,7 @@
  */
 
 #include "tools.h"
+#include "polldaemon.h"
 #include "lv_alloc.h"
 
 struct lvconvert_params {
@@ -21,7 +22,9 @@ struct lvconvert_params {
 
 	const char *origin;
 	const char *lv_name;
+	const char *lv_name_full;
 	const char *vg_name;
+	int wait_daemon;
 
 	uint32_t chunk_size;
 	uint32_t region_size;
@@ -70,11 +73,11 @@ static int _lvconvert_name_params(struct
 		return 0;
 	}
 
-	lp->lv_name = (*pargv)[0];
+	lp->lv_name = lp->lv_name_full = (*pargv)[0];
 	(*pargv)++, (*pargc)--;
 
-	if (strchr(lp->lv_name, '/') &&
-	    (vg_name = extract_vgname(cmd, lp->lv_name)) &&
+	if (strchr(lp->lv_name_full, '/') &&
+	    (vg_name = extract_vgname(cmd, lp->lv_name_full)) &&
 	    lp->vg_name && strcmp(vg_name, lp->vg_name)) {
 		log_error("Please use a single volume group name "
 			  "(\"%s\" or \"%s\")", vg_name, lp->vg_name);
@@ -89,7 +92,7 @@ static int _lvconvert_name_params(struct
 		return 0;
 	}
 
-	if ((ptr = strrchr(lp->lv_name, '/')))
+	if ((ptr = strrchr(lp->lv_name_full, '/')))
 		lp->lv_name = ptr + 1;
 
 	if (!apply_lvname_restrictions(lp->lv_name))
@@ -227,6 +230,90 @@ static int _read_params(struct lvconvert
 	return 1;
 }
 
+
+static struct volume_group *_get_lvconvert_vg(struct cmd_context *cmd,
+					      const char *lv_name)
+{
+        dev_close_all();
+
+        return vg_lock_and_read(cmd, extract_vgname(cmd, lv_name),
+				NULL, LCK_VG_WRITE,
+ 				CLUSTERED | EXPORTED_VG | LVM_WRITE,
+				CORRECT_INCONSISTENT | FAIL_INCONSISTENT);
+}
+
+static struct logical_volume *_get_lvconvert_lv(struct cmd_context *cmd __attribute((unused)),
+						struct volume_group *vg,
+						const char *name,
+						uint32_t lv_type __attribute((unused)))
+{
+	return find_lv(vg, name);
+}
+
+static int _update_lvconvert_mirror(struct cmd_context *cmd __attribute((unused)),
+				    struct volume_group *vg __attribute((unused)),
+				    struct logical_volume *lv __attribute((unused)),
+				    struct list *lvs_changed __attribute((unused)),
+				    int first_time __attribute((unused)))
+{
+	/* lvconvert mirror doesn't require periodical metadata update */
+	return 1;
+}
+
+static int _finish_lvconvert_mirror(struct cmd_context *cmd,
+				    struct volume_group *vg,
+				    struct logical_volume *lv,
+				    struct list *lvs_changed __attribute((unused)))
+{
+	if (!collapse_mirrored_lv(lv)) {
+		log_error("Failed to remove temporary sync layer.");
+		return 0;
+	}
+
+	log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
+
+	if (!vg_write(vg))
+		return_0;
+
+	backup(vg);
+
+	if (!suspend_lv(cmd, lv)) {
+		log_error("Failed to lock %s", lv->name);
+		vg_revert(vg);
+		return 0;
+	}
+
+	if (!vg_commit(vg)) {
+		resume_lv(cmd, lv);
+		return 0;
+	}
+
+	log_very_verbose("Updating \"%s\" in kernel", lv->name);
+
+	if (!resume_lv(cmd, lv)) {
+		log_error("Problem reactivating %s", lv->name);
+		return 0;
+	}
+
+	log_print("Logical volume %s converted.", lv->name);
+
+	return 1;
+}
+
+static struct poll_functions _lvconvert_mirror_fns = {
+	.get_copy_vg = _get_lvconvert_vg,
+	.get_copy_lv = _get_lvconvert_lv,
+	.update_metadata = _update_lvconvert_mirror,
+	.finish_copy = _finish_lvconvert_mirror,
+};
+
+static int _lvconvert_poll(struct cmd_context *cmd, const char *lv_name,
+			   unsigned background)
+{
+	return poll_daemon(cmd, lv_name, background, 0, &_lvconvert_mirror_fns,
+			   "Converted");
+}
+
 static int _insert_lvconvert_layer(struct cmd_context *cmd,
 				   struct logical_volume *lv)
 {
@@ -284,9 +371,8 @@ static int lvconvert_mirrors(struct cmd_
 
 	/* If called with no argument, try collapsing the resync layers */
 	if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, mirrorlog_ARG)) {
-		if (!collapse_mirrored_lv(lv))
-			return_0;
-		goto commit_changes;
+		lp->wait_daemon = 1;
+		return 1;
 	}
 
 	/*
@@ -439,6 +525,7 @@ static int lvconvert_mirrors(struct cmd_
 				    corelog ? 0U : 1U, lp->pvh, lp->alloc,
 				    MIRROR_BY_LV))
 			return_0;
+		lp->wait_daemon = 1;
 	} else {
 		/* Reduce number of mirrors */
 		if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors,
@@ -472,7 +559,8 @@ commit_changes:
 		return 0;
 	}
 
-	log_print("Logical volume %s converted.", lv->name);
+	if (!lp->wait_daemon)
+		log_print("Logical volume %s converted.", lv->name);
 
 	return 1;
 }
@@ -625,5 +713,9 @@ int lvconvert(struct cmd_context * cmd, 
 
 error:
 	unlock_vg(cmd, lp.vg_name);
+
+	if (lp.wait_daemon)
+		ret = _lvconvert_poll(cmd, lp.lv_name_full,
+				      arg_count(cmd, background_ARG) ? 1U : 0);
 	return ret;
 }
Index: LVM2.work/tools/commands.h
===================================================================
--- LVM2.work.orig/tools/commands.h
+++ LVM2.work/tools/commands.h
@@ -91,8 +91,10 @@ xx(lvconvert,
    "[-m|--mirrors Mirrors [{--mirrorlog {disk|core}|--corelog}]]\n"
    "\t[-R|--regionsize MirrorLogRegionSize]\n"
    "\t[--alloc AllocationPolicy]\n"
+   "\t[-b|--background]\n"
    "\t[-d|--debug]\n"
    "\t[-h|-?|--help]\n"
+   "\t[-i|--interval seconds]\n"
    "\t[-v|--verbose]\n"
    "\t[--version]" "\n"
    "\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n\n"
@@ -107,8 +109,8 @@ xx(lvconvert,
    "\t[--version]" "\n"
    "\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n",
 
-   alloc_ARG, chunksize_ARG, corelog_ARG, mirrorlog_ARG, mirrors_ARG,
-   regionsize_ARG, snapshot_ARG, test_ARG, zero_ARG)
+   alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, interval_ARG,
+   mirrorlog_ARG, mirrors_ARG, regionsize_ARG, snapshot_ARG, test_ARG, zero_ARG)
 
 xx(lvcreate,
    "Create a logical volume",
Index: LVM2.work/man/lvconvert.8
===================================================================
--- LVM2.work.orig/man/lvconvert.8
+++ LVM2.work/man/lvconvert.8
@@ -5,6 +5,7 @@ lvconvert \- convert a logical volume fr
 .B lvconvert
 \-m/\-\-mirrors Mirrors [\-\-mirrorlog {disk|core}] [\-\-corelog] [\-R/\-\-regionsize MirrorLogRegionSize]
 [\-A/\-\-alloc AllocationPolicy]
+[\-b/\-\-background] [\-i/\-\-interval Seconds]
 [\-h/\-?/\-\-help]
 [\-v/\-\-verbose]
 [\-\-version]
@@ -52,6 +53,12 @@ The optional argument "--corelog" is the
 .I \-R, \-\-regionsize MirrorLogRegionSize
 A mirror is divided into regions of this size (in MB), and the mirror log
 uses this granularity to track which regions are in sync.
+.TP
+.I \-b, \-\-background
+Run the daemon in the background.
+.TP
+.I \-i, \-\-interval Seconds
+Report progress as a percentage at regular intervals.
 .br
 .TP
 .I \-s, \-\-snapshot

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]