summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2020-12-09 10:59:40 -0600
committerDavid Teigland <teigland@redhat.com>2020-12-16 15:15:13 -0600
commit7b8098e7491f9169da392e40170579101517f052 (patch)
treee89d3d285acd73e72cc6d40ac0978f8436ad00d5
parent9b3458d5a945302a68e4f5ed3011f01677411e9b (diff)
downloadlvm2-dev-dct-pvscan-list-2.tar.gz
pvscan: add options listlvs listvg checkcompletedev-dct-pvscan-list-2
pvscan --cache <dev> . read only dev . create online file for dev pvscan --listvg <dev> . read only dev . list VG using dev pvscan --listlvs <dev> . read only dev . list VG using dev . list LVs using dev pvscan --cache --listvg [--checkcomplete] <dev> . read only dev . create online file for dev . list VG using dev . [check online files and report if VG is complete] pvscan --cache --listlvs [--checkcomplete] <dev> . read only dev . create online file for dev . list VG using dev . list LVs using dev . [check online files and report if VG is complete] . [check online files and report if LVs are complete] [--vgonline] can be used with --checkcomplete, to enable use of a vg online file. This results in only the first pvscan command to see the complete VG to report 'VG complete', and others will report 'VG finished'. This allows the caller to easily run a single activation of the VG. The list of complete LVs is meant to be passed to lvchange -aay, or the complete VG used with vgchange -aay. Example of listlvs ------------------ $ lvs -a vg -olvname,devices LV Devices lv_a /dev/loop0(0) lv_ab /dev/loop0(1),/dev/loop1(1) lv_abc /dev/loop0(3),/dev/loop1(3),/dev/loop2(1) lv_b /dev/loop1(0) lv_c /dev/loop2(0) $ pvscan --cache --listlvs --checkcomplete /dev/loop0 pvscan[35680] PV /dev/loop0 online, VG vg incomplete (need 2). VG vg incomplete LV vg/lv_a complete LV vg/lv_ab incomplete LV vg/lv_abc incomplete $ pvscan --cache --listlvs --checkcomplete /dev/loop1 pvscan[35681] PV /dev/loop1 online, VG vg incomplete (need 1). VG vg incomplete LV vg/lv_b complete LV vg/lv_ab complete LV vg/lv_abc incomplete $ pvscan --cache --listlvs --checkcomplete /dev/loop2 pvscan[35682] PV /dev/loop2 online, VG vg is complete. VG vg complete LV vg/lv_c complete LV vg/lv_abc complete Example of listvg ----------------- $ pvscan --cache --listvg --checkcomplete /dev/loop0 pvscan[35684] PV /dev/loop0 online, VG vg incomplete (need 2). VG vg incomplete $ pvscan --cache --listvg --checkcomplete /dev/loop1 pvscan[35685] PV /dev/loop1 online, VG vg incomplete (need 1). VG vg incomplete $ pvscan --cache --listvg --checkcomplete /dev/loop2 pvscan[35686] PV /dev/loop2 online, VG vg is complete. VG vg complete
-rw-r--r--lib/metadata/metadata.c33
-rw-r--r--lib/metadata/metadata.h4
-rw-r--r--tools/args.h13
-rw-r--r--tools/command-lines.in30
-rw-r--r--tools/pvscan.c243
5 files changed, 274 insertions, 49 deletions
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index d04b8d8ba..9ca4a35c9 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -5312,3 +5312,36 @@ struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_
return vg;
}
+
+int get_visible_lvs_using_pv(struct cmd_context *cmd, struct volume_group *vg, struct device *dev,
+ struct dm_list *lvs_list)
+{
+ struct pv_list *pvl;
+ struct lv_list *lvl, *lvl2;
+ struct physical_volume *pv = NULL;
+
+ dm_list_iterate_items(pvl, &vg->pvs) {
+ if (pvl->pv->dev == dev) {
+ pv = pvl->pv;
+ break;
+ }
+ }
+
+ if (!pv)
+ return_0;
+
+ dm_list_iterate_items(lvl, &vg->lvs) {
+ if (!lv_is_visible(lvl->lv))
+ continue;
+ if (!lv_is_on_pv(lvl->lv, pv))
+ continue;
+
+ if (!(lvl2 = dm_pool_zalloc(cmd->mem, sizeof(*lvl2))))
+ return_0;
+ lvl2->lv = lvl->lv;
+ dm_list_add(lvs_list, &lvl2->list);
+ }
+
+ return 1;
+}
+
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index 2c224505a..c8fb3901c 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -526,4 +526,8 @@ char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tagsl);
void set_pv_devices(struct format_instance *fid, struct volume_group *vg, int *found_md_component);
+int get_visible_lvs_using_pv(struct cmd_context *cmd, struct volume_group *vg, struct device *dev,
+ struct dm_list *lvs_list);
+
+
#endif
diff --git a/tools/args.h b/tools/args.h
index 3a7e5d488..d3ecea031 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -286,6 +286,15 @@ arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0,
"start of the disk (between 0 and 3 inclusive - see LABEL_SCAN_SECTORS\n"
"in the source). Use with care.\n")
+arg(listlvs_ARG, '\0', "listlvs", 0, 0, 0,
+ "Print a list of LVs that use the device.\n")
+
+arg(listvg_ARG, '\0', "listvg", 0, 0, 0,
+ "Print the VG that uses the device.\n")
+
+arg(checkcomplete_ARG, '\0', "checkcomplete", 0, 0, 0,
+ "Check if all the devices used by VG or LV are present.\n")
+
arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0,
"Used to pass options for special cases to lvmlockd.\n"
"See \\fBlvmlockd\\fP(8) for more information.\n")
@@ -841,6 +850,10 @@ arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", vgmetadatacopies_VAL, 0, 0,
"\\fBall\\fP causes LVM to first clear the metadataignore flags on\n"
"all PVs, and then to become unmanaged.\n")
+arg(vgonline_ARG, '\0', "vgonline", 0, 0, 0,
+ "The first command to see the complete VG will report it uniquely.\n"
+ "Other commands to see the complete VG will report it differently.\n")
+
arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0,
"Display a one line comment for each configuration node.\n")
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 5a8523966..921bd1841 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1569,11 +1569,37 @@ DESC: Display PV information.
pvscan --cache_long
OO: --ignorelockingfailure, --reportformat ReportFmt,
---activate ay, --major Number, --minor Number, --noudevsync
+--major Number, --minor Number, --noudevsync
OP: PV|String ...
IO: --background
ID: pvscan_cache
-DESC: Autoactivate a VG when all PVs are online.
+DESC: Record that a PV is online or offline.
+
+pvscan --cache_long --activate ay
+OO: --ignorelockingfailure, --reportformat ReportFmt,
+--major Number, --minor Number, --noudevsync
+OP: PV|String ...
+IO: --background
+ID: pvscan_cache
+DESC: Record that a PV is online and autoactivate the VG if complete.
+
+pvscan --cache_long --listvg PV
+OO: --ignorelockingfailure, --checkcomplete, --vgonline
+ID: pvscan_cache
+DESC: Record that a PV is online and list the VG using the PV.
+
+pvscan --cache_long --listlvs PV
+OO: --ignorelockingfailure, --checkcomplete, --vgonline
+ID: pvscan_cache
+DESC: Record that a PV is online and list LVs using the PV.
+
+pvscan --listlvs PV
+ID: pvscan_cache
+DESC: List LVs using the PV.
+
+pvscan --listvg PV
+ID: pvscan_cache
+DESC: List the VG using the PV.
---
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 55c708682..2fd6c42eb 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -1175,6 +1175,64 @@ static int _get_args_devs(struct cmd_context *cmd, struct dm_list *pvscan_args,
return 1;
}
+static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group *vg)
+{
+ char path[PATH_MAX];
+ char file_vgname[NAME_LEN];
+ char pvid[ID_LEN+1] = { 0 };
+ struct pv_list *pvl;
+ struct device *dev;
+ int major, minor;
+ dev_t devno;
+
+ dm_list_iterate_items(pvl, &vg->pvs) {
+ memcpy(&pvid, &pvl->pv->id.uuid, ID_LEN);
+
+ if (pvl->pv->status & MISSING_PV) {
+ log_debug("set_pv_devices_online vg %s pv %s missing flag already set",
+ vg->name, pvid);
+ continue;
+ }
+
+ if (!_online_pvid_file_exists(pvid)) {
+ log_debug("set_pv_devices_online vg %s pv %s no online file",
+ vg->name, pvid);
+ pvl->pv->status |= MISSING_PV;
+ continue;
+ }
+
+ memset(path, 0, sizeof(path));
+ snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid);
+
+ major = 0;
+ minor = 0;
+ file_vgname[0] = '\0';
+
+ _online_pvid_file_read(path, &major, &minor, file_vgname);
+
+ if (file_vgname[0] && strcmp(vg->name, file_vgname)) {
+ log_warn("WARNING: VG %s PV %s wrong vgname in online file %s",
+ vg->name, pvid, file_vgname);
+ pvl->pv->status |= MISSING_PV;
+ continue;
+ }
+
+ devno = MKDEV(major, minor);
+
+ if (!(dev = dev_cache_get_by_devt(cmd, devno, NULL, NULL))) {
+ log_print("WARNING: VG %s PV %s no device found for %d:%d",
+ vg->name, pvid, major, minor);
+ pvl->pv->status |= MISSING_PV;
+ continue;
+ }
+
+ log_debug("set_pv_devices_online vg %s pv %s is online %s",
+ vg->name, pvid, dev_name(dev));
+
+ pvl->pv->dev = dev;
+ }
+}
+
static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvscan_devs,
int *pv_count, struct dm_list *complete_vgnames)
{
@@ -1186,9 +1244,14 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
struct format_instance *fid;
struct metadata_area *mda1, *mda2;
struct volume_group *vg;
- const char *vgname;
+ const char *vgname = NULL;
uint32_t ext_version, ext_flags;
+ int do_cache = arg_is_set(cmd, cache_long_ARG);
int do_activate = arg_is_set(cmd, activate_ARG);
+ int do_list_lvs = arg_is_set(cmd, listlvs_ARG);
+ int do_list_vg = arg_is_set(cmd, listvg_ARG);
+ int do_check_complete = arg_is_set(cmd, checkcomplete_ARG);
+ int do_vgonline = arg_is_set(cmd, vgonline_ARG);
int pvs_online;
int pvs_offline;
int pvs_unknown;
@@ -1243,8 +1306,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
goto online;
}
- set_pv_devices(fid, vg, NULL);
-
+#if 0
/*
* Skip devs that are md components (set_pv_devices can do new
* md check), are shared, or foreign.
@@ -1255,6 +1317,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
release_vg(vg);
continue;
}
+#endif
if (vg_is_shared(vg)) {
log_print("pvscan[%d] PV %s ignore shared VG.", getpid(), dev_name(dev));
@@ -1286,8 +1349,9 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
/*
* Create file named for pvid to record this PV is online.
+ * The command creates/checks online files only when --cache is used.
*/
- if (!_online_pvid_file_create(dev, vg ? vg->name : NULL)) {
+ if (do_cache && !_online_pvid_file_create(dev, vg ? vg->name : NULL)) {
log_error("pvscan[%d] PV %s failed to create online file.", getpid(), dev_name(dev));
release_vg(vg);
ret = 0;
@@ -1295,9 +1359,9 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
}
/*
- * When not activating we don't need to know about vg completeness.
+ * A plain pvscan --cache <dev> just creates the online file.
*/
- if (!do_activate) {
+ if (!do_activate && !do_list_lvs && !do_list_vg) {
log_print("pvscan[%d] PV %s online.", getpid(), dev_name(dev));
release_vg(vg);
continue;
@@ -1306,61 +1370,146 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
/*
* Check if all the PVs for this VG are online. If the arrival
* of this dev completes the VG, then save the vgname in
- * complete_vgnames so it will be activated.
+ * complete_vgnames (activation phase will want to know which
+ * VGs to activate.)
*/
- pvs_online = 0;
- pvs_offline = 0;
- pvs_unknown = 0;
- vg_complete = 0;
-
- if (vg) {
- /*
- * Use the VG metadata from this PV for a list of all
- * PVIDs. Write a lookup file of PVIDs in case another
- * pvscan needs it. After writing lookup file, recheck
- * pvid files to resolve a possible race with another
- * pvscan reading the lookup file that missed it.
- */
- log_debug("checking all pvid files from vg %s", vg->name);
- _count_pvid_files(vg, &pvs_online, &pvs_offline);
+ if (do_activate || do_check_complete) {
+ pvs_online = 0;
+ pvs_offline = 0;
+ pvs_unknown = 0;
+ vg_complete = 0;
- if (pvs_offline && _write_lookup_file(cmd, vg)) {
- log_debug("rechecking all pvid files from vg %s", vg->name);
+ if (vg) {
+ /*
+ * Use the VG metadata from this PV for a list of all
+ * PVIDs. Write a lookup file of PVIDs in case another
+ * pvscan needs it. After writing lookup file, recheck
+ * pvid files to resolve a possible race with another
+ * pvscan reading the lookup file that missed it.
+ */
+ log_debug("checking all pvid files from vg %s", vg->name);
_count_pvid_files(vg, &pvs_online, &pvs_offline);
- if (!pvs_offline)
- log_print("pvscan[%d] VG %s complete after recheck.", getpid(), vg->name);
+
+ if (pvs_offline && _write_lookup_file(cmd, vg)) {
+ log_debug("rechecking all pvid files from vg %s", vg->name);
+ _count_pvid_files(vg, &pvs_online, &pvs_offline);
+ if (!pvs_offline)
+ log_print("pvscan[%d] VG %s complete after recheck.", getpid(), vg->name);
+ }
+
+ vgname = vg->name;
+ } else {
+ /*
+ * No VG metadata on this PV, so try to use a lookup
+ * file written by a prior pvscan for a list of all
+ * PVIDs. A lookup file may not exist for this PV if
+ * it's the first to appear from the VG.
+ */
+ log_debug("checking all pvid files from lookup file");
+ if (!_count_pvid_files_from_lookup_file(cmd, dev, &pvs_online, &pvs_offline, &vgname))
+ pvs_unknown = 1;
}
+
+ if (pvs_unknown) {
+ log_print("pvscan[%d] PV %s online, VG unknown.", getpid(), dev_name(dev));
+ vg_complete = 0;
+
+ } else if (pvs_offline) {
+ log_print("pvscan[%d] PV %s online, VG %s incomplete (need %d).",
+ getpid(), dev_name(dev), vgname, pvs_offline);
+ vg_complete = 0;
+
+ } else {
+ log_print("pvscan[%d] PV %s online, VG %s is complete.", getpid(), dev_name(dev), vgname);
+ if (!str_list_add(cmd->mem, complete_vgnames, dm_pool_strdup(cmd->mem, vgname)))
+ stack;
+ vg_complete = 1;
+ }
+ }
+ if (!vgname && vg)
vgname = vg->name;
- } else {
+
+ if (do_list_vg || do_list_lvs) {
+ if (!vgname)
+ log_print("VG unknown");
+ else if (!do_check_complete)
+ log_print("VG %s", vgname);
+ else if (vg_complete) {
+ if (do_vgonline && !_online_vg_file_create(cmd, vgname))
+ log_print("VG %s finished", vgname);
+ else
+ log_print("VG %s complete", vgname);
+ } else {
+ log_print("VG %s incomplete", vgname);
+ }
+
/*
- * No VG metadata on this PV, so try to use a lookup
- * file written by a prior pvscan for a list of all
- * PVIDs. A lookup file may not exist for this PV if
- * it's the first to appear from the VG.
+ * When the VG is complete|finished, we could print
+ * a list of devices in the VG, by reading the pvid files
+ * that were counted, which provides major:minor of each
+ * device and using that to get the struct dev and dev_name.
+ * The user could pass this list of devices to --devices
+ * to optimize a subsequent command (activation) on the VG.
+ * Just call set_pv_devices_online (if not done othewise)
+ * since that finds the devs.
*/
- log_debug("checking all pvid files from lookup file");
- if (!_count_pvid_files_from_lookup_file(cmd, dev, &pvs_online, &pvs_offline, &vgname))
- pvs_unknown = 1;
}
- if (pvs_unknown) {
- log_print("pvscan[%d] PV %s online, VG unknown.", getpid(), dev_name(dev));
- vg_complete = 0;
+ if (do_list_lvs && !vg) {
+ /* require all PVs used for booting have metadata */
+ log_print("Cannot list LVs from device without metadata.");
+ }
- } else if (pvs_offline) {
- log_print("pvscan[%d] PV %s online, VG %s incomplete (need %d).",
- getpid(), dev_name(dev), vgname, pvs_offline);
- vg_complete = 0;
+ if (do_list_lvs && vg) {
+ struct dm_list lvs_list;
+ struct lv_list *lvl;
+
+ dm_list_init(&lvs_list);
+
+ /*
+ * For each vg->pvs entry, get the dev based on the online file
+ * for the pvid and set pv->dev or pv->status MISSING_PV.
+ */
+ _set_pv_devices_online(cmd, vg);
- } else {
- log_print("pvscan[%d] PV %s online, VG %s is complete.", getpid(), dev_name(dev), vgname);
- if (!str_list_add(cmd->mem, complete_vgnames, dm_pool_strdup(cmd->mem, vgname)))
- stack;
- vg_complete = 1;
+ /*
+ * lvs_list are LVs that use dev.
+ */
+ if (!get_visible_lvs_using_pv(cmd, vg, dev, &lvs_list))
+ log_warn("WARNING: failed to find LVs using %s.", dev_name(dev));
+
+ if (!do_check_complete) {
+ dm_list_iterate_items(lvl, &lvs_list)
+ log_print("LV %s", display_lvname(lvl->lv));
+ } else if (vg_complete) {
+ /*
+ * A shortcut; the vg complete implies all lvs are complete.
+ */
+ dm_list_iterate_items(lvl, &lvs_list)
+ log_print("LV %s complete", display_lvname(lvl->lv));
+ } else {
+ /*
+ * For each LV in VG, check if all devs are present.
+ * Sets the PARTIAL flag on LVs that are not complete.
+ */
+ if (!vg_mark_partial_lvs(vg, 1))
+ log_print("Failed to check partial lvs.");
+
+ dm_list_iterate_items(lvl, &lvs_list) {
+ if (!lv_is_partial(lvl->lv))
+ log_print("LV %s complete", display_lvname(lvl->lv));
+ else
+ log_print("LV %s incomplete", display_lvname(lvl->lv));
+ }
+ }
}
- if (!saved_vg && vg && vg_complete && !do_all && (dm_list_size(pvscan_devs) == 1))
+ /*
+ * When "pvscan --cache -aay <dev>" completes the vg, save the
+ * struct vg to use for quick activation function.
+ */
+ if (do_activate && !saved_vg && vg && vg_complete && !do_all && (dm_list_size(pvscan_devs) == 1))
saved_vg = vg;
else
release_vg(vg);