diff options
-rw-r--r-- | lib/metadata/metadata.c | 33 | ||||
-rw-r--r-- | lib/metadata/metadata.h | 4 | ||||
-rw-r--r-- | tools/args.h | 9 | ||||
-rw-r--r-- | tools/command-lines.in | 30 | ||||
-rw-r--r-- | tools/pvscan.c | 224 |
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); |