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-14 16:06:14 -0600
commit419c9b4f88caac6a3f7381c4dc64891c18123687 (patch)
tree0a82308190a69c76c816c616e6d5e4be12682ae0
parent9b3458d5a945302a68e4f5ed3011f01677411e9b (diff)
downloadlvm2-dev-dct-pvscan-list-1.tar.gz
pvscan: add options listlvs listvg checkcompletedev-dct-pvscan-list-1
pvscan --cache <dev> . read only dev . create online file for dev pvscan --listlvs <dev> . read only dev . list LVs using dev pvscan --listvg <dev> . read only dev . show VG using dev pvscan --cache --listlvs [--checkcomplete] <dev> . read only dev . create online file for dev . list LVs using dev . [check online files and report if LVs are complete] 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] 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). 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). 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. 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.h9
-rw-r--r--tools/command-lines.in30
-rw-r--r--tools/pvscan.c224
5 files changed, 250 insertions, 50 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..3ab5986c2 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")
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 5a8523966..748c49783 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 VG if complete.
+
+pvscan --cache_long --listvg PV
+OO: --ignorelockingfailure, --checkcomplete
+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
+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..2ef38002b 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)
{
@@ -1188,7 +1246,11 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
struct volume_group *vg;
const char *vgname;
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 list_lvs = arg_is_set(cmd, listlvs_ARG);
+ int list_vg = arg_is_set(cmd, listvg_ARG);
+ int check_complete = arg_is_set(cmd, checkcomplete_ARG);
int pvs_online;
int pvs_offline;
int pvs_unknown;
@@ -1243,8 +1305,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 +1316,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 +1348,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 +1358,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 && !list_lvs && !list_vg) {
log_print("pvscan[%d] PV %s online.", getpid(), dev_name(dev));
release_vg(vg);
continue;
@@ -1306,61 +1369,126 @@ 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 || 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 (list_lvs) {
+ struct dm_list lvs_list;
+ struct lv_list *lvl;
+
+ dm_list_init(&lvs_list);
+
/*
- * 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.
+ * 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.
*/
- 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;
- }
+ _set_pv_devices_online(cmd, vg);
- 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;
+ /*
+ * 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 (!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));
+ }
+ }
+ }
- } 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 (list_vg) {
+ if (!vgname)
+ log_print("VG unknown");
+ else if (!check_complete)
+ log_print("VG %s", vgname);
+ else if (vg_complete)
+ log_print("VG %s complete", vgname);
+ else
+ log_print("VG %s incomplete", vgname);
}
- 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);