report LV is usable for upper layer. Signed-off-by: Zhao Heming <heming.zhao@xxxxxxxx> --- lib/activate/activate.h | 2 + lib/activate/dev_manager.c | 67 ++++++++++++++++ lib/metadata/metadata-exported.h | 1 + lib/metadata/metadata.c | 130 +++++++++++++++++++++++++++++++ lib/report/columns.h | 1 + lib/report/properties.c | 2 + lib/report/report.c | 13 ++++ lib/report/values.h | 1 + 8 files changed, 217 insertions(+) diff --git a/lib/activate/activate.h b/lib/activate/activate.h index e3c1bb35e..25de3d6b1 100644 --- a/lib/activate/activate.h +++ b/lib/activate/activate.h @@ -255,6 +255,8 @@ struct dev_usable_check_params { */ int device_is_usable(struct device *dev, struct dev_usable_check_params check); +char *lv_mapping_table(const char *dm_table_dev); +bool dm_has_lvdev(const char *dm_table_dev, const char *lvdev); /* * Declaration moved here from fs.h to keep header fs.h hidden */ diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index a626b000a..c272c20f6 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -778,6 +778,73 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check) return r; } +/* + * Return input LV underlying devs + * NOTE: Caller should free the return string. + */ +char *lv_mapping_table(const char *dm_table_dev) +{ + struct dm_task *dmt; + uint64_t start, len; + char *params, *type = NULL; + void *next = NULL; + char *ret_str = NULL; + + if (!(dmt = _setup_task_run(DM_DEVICE_TABLE, NULL, + dm_table_dev, NULL, NULL, 0, 0, 0, 0, 0))) { + log_error("can't get %s device mapping table", dm_table_dev); + return NULL; + } + + do { + next = dm_get_next_target(dmt, next, &start, &len, &type, ¶ms); + if (strcmp(type, TARGET_NAME_LINEAR)) + goto out; /* only support linear type */ + /* TODO: merge all sub-dm dev into one ret_str */ + ret_str = strndup(params, strchr(params, ' ') - params); + break; + } while (next); + +out: + dm_task_destroy(dmt); + + return ret_str; +} + +/* + * To check whether 1st parameter lv underlying devs contains + * 2nd parameter lv dev + */ +bool dm_has_lvdev(const char *dm_table_dev, const char *lvdev) +{ + struct dm_task *dmt; + uint64_t start, len; + char *params, *type = NULL; + void *next = NULL; + bool ret = false; + + if (!(dmt = _setup_task_run(DM_DEVICE_TABLE, NULL, + dm_table_dev, NULL, NULL, 0, 0, 0, 0, 0))) { + log_error("can't get %s device mapping table", dm_table_dev); + return false; + } + + do { + next = dm_get_next_target(dmt, next, &start, &len, &type, ¶ms); + if (strcmp(type, TARGET_NAME_LINEAR)) + goto out; /* only support linear type */ + if (strstr(params, lvdev)) { + ret = true; + break; + } + } while (next); + +out: + dm_task_destroy(dmt); + + return ret; +} + /* * If active LVs were activated by a version of LVM2 before 2.02.00 we must * perform additional checks to find them because they do not have the LVM- diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index 670656a0f..620216dc0 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -1416,5 +1416,6 @@ int lv_extend_integrity_in_raid(struct logical_volume *lv, struct dm_list *pvh); int lv_get_raid_integrity_settings(struct logical_volume *lv, struct integrity_settings **isettings); int integrity_mode_set(const char *mode, struct integrity_settings *settings); int lv_integrity_mismatches(struct cmd_context *cmd, const struct logical_volume *lv, uint64_t *mismatches); +bool _lv_is_usable(const struct logical_volume *lv, char *dm_dev); #endif diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 8b8c491c0..03bc399a8 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -2043,6 +2043,136 @@ static int _lv_mark_if_partial_collect(struct logical_volume *lv, void *data) return 1; } +/* + * Return LV is still work or not when underlying dev is removed + * + * RAID: + * - raid 0: if there is any disk loose, return false + * - raid1,10,4/5,6: below case think as available, return true: + * - raid 1: at least 1 disk live + * - raid 10: loose 1 disk + * - raid 4/5: loose 1 disk + * - raid 6: loose 2 disk + * + * LINEAR: + * - if there is any disk loose, return false + * + * MIRROR: + * - mirror type won't be in 'not available' status, return true directly. + * - the failing rule + * - 3-way mirror convert to 2-way mirror + * - 2-way mirror to linear device + * + * For all other LV type (e.g. thin, cache, integrity, vdo etc): + * - return false if there is any disk loose. + */ +bool _lv_is_usable(const struct logical_volume *lv, char *dm_dev) +{ + int s, missing_pv = 0, exist_pv = 0, un_usable_pv = 0; + bool ret = true; + struct lv_segment *seg = NULL; + struct device *dev; + char t_dev[8]; /* strlen(255:255)+1: 8 */ + char lvname[50]; + char *lv_dev; + struct physical_volume *pv; + + /* see comment, return directly */ + if (!dm_dev && seg_is_mirror(first_seg(lv))) { + ret = true; + goto out; + } + + dm_list_iterate_items(seg, &lv->segments) { + for (s = 0; s < seg->area_count; ++s) { + if (seg_type(seg, s) == AREA_LV) { + if (seg_lv(seg, s)->status & PARTIAL_LV) { + missing_pv++; + } else { + /* format is right: "vgname" + '-' + "lvname" ?? */ + snprintf(lvname, 50, "%s-%s", lv->vg->name, seg_lv(seg, s)->name); + lv_dev = lv_mapping_table(lvname); + if (lv_dev) + _lv_is_usable(seg_lv(seg, s), lv_dev) ? + exist_pv++ : un_usable_pv++; + else + missing_pv++; + } + } else if (seg_type(seg, s) == AREA_PV) { + pv = seg_pv(seg, s); + snprintf(t_dev, 8, "%d:%d", + pv->dev ? (int) MAJOR(pv->dev->dev) : -1, + pv->dev ? (int) MINOR(pv->dev->dev) : -1); + + if (dm_dev) { /* call from recursion */ + ret = strncmp(t_dev, dm_dev, 8) ? false : true; + free(dm_dev); + return ret; + } + + if (!(pv->dev) && is_missing_pv(pv)) { + missing_pv++; + } else { + if (pv->dev) { + dev = seg_dev(seg, s); + snprintf(t_dev, 8, "%d:%d", (int) MAJOR(dev->dev), (int) MINOR(dev->dev)); + /* format is right: "vgname" + '-' + "lvname" ?? */ + snprintf(lvname, 50, "%s-%s", lv->vg->name, lv->name); + dm_has_lvdev(lvname, t_dev) ? exist_pv++ : un_usable_pv++; + } else + missing_pv++; + } + } + } + } + + /* make sure recursioin must return from here */ + if (dm_dev) { + ret = (un_usable_pv || missing_pv ) ? false : true; + free(dm_dev); + return ret; + } + + seg = first_seg(lv); + if (seg_is_linear(seg)) { + ret = (missing_pv || un_usable_pv) ? false : true; + goto out; + } + if (seg_is_any_raid0(seg)) { + ret = (missing_pv || un_usable_pv) ? false : true; + goto out; + } + if (seg_is_raid1(seg)) { + ret = exist_pv ? true : false; + goto out; + } + if (seg_is_any_raid10(seg)) { + ret = ((missing_pv + un_usable_pv) > 1) ? false : true; + goto out; + } + if (seg_is_raid4(seg)) { + ret = ((missing_pv + un_usable_pv) > 1) ? false : true; + goto out; + } + if (seg_is_any_raid5(seg)) { + ret = ((missing_pv + un_usable_pv) > 1) ? false : true; + goto out; + } + if (seg_is_any_raid6(seg)) { + ret = ((missing_pv + un_usable_pv) > 2) ? false : true; + goto out; + } + + /* + * if code go there, the LV type must be thin, cache, integrity, vdo etc + * return false if there is any disk loose or un_usable. + */ + ret = (missing_pv || un_usable_pv )? false : true; + +out: + return ret; +} + static int _lv_mark_if_partial_single(struct logical_volume *lv, void *data) { unsigned s; diff --git a/lib/report/columns.h b/lib/report/columns.h index 426a32c50..357c42530 100644 --- a/lib/report/columns.h +++ b/lib/report/columns.h @@ -145,6 +145,7 @@ FIELD(LVSSTATUS, lv, STR_LIST, "KCacheSettings", lvid, 18, kernel_cache_settings FIELD(LVSSTATUS, lv, STR, "KCachePolicy", lvid, 18, kernel_cache_policy, kernel_cache_policy, "Cache policy used in kernel.", 0) FIELD(LVSSTATUS, lv, NUM, "KMFmt", lvid, 0, kernelmetadataformat, kernel_metadata_format, "Cache metadata format used in kernel.", 0) FIELD(LVSSTATUS, lv, STR, "Health", lvid, 15, lvhealthstatus, lv_health_status, "LV health status.", 0) +FIELD(LVSSTATUS, lv, STR, "Usable", lvid, 15, lvusable, lv_usable, "whether lvm believes the uppser layer can successfully do io to the entire LV.", 0) FIELD(LVSSTATUS, lv, STR, "KDiscards", lvid, 0, kdiscards, kernel_discards, "For thin pools, how discards are handled in kernel.", 0) FIELD(LVSSTATUS, lv, BIN, "CheckNeeded", lvid, 15, lvcheckneeded, lv_check_needed, "For thin pools and cache volumes, whether metadata check is needed.", 0) FIELD(LVSSTATUS, lv, BIN, "MergeFailed", lvid, 15, lvmergefailed, lv_merge_failed, "Set if snapshot merge failed.", 0) diff --git a/lib/report/properties.c b/lib/report/properties.c index d4ac8c47e..e3d64a5d6 100644 --- a/lib/report/properties.c +++ b/lib/report/properties.c @@ -296,6 +296,8 @@ GET_PV_NUM_PROPERTY_FN(pv_ba_size, SECTOR_SIZE * pv->ba_size) #define _lv_device_open_get prop_not_implemented_get #define _lv_health_status_set prop_not_implemented_set #define _lv_health_status_get prop_not_implemented_get +#define _lv_usable_set prop_not_implemented_set +#define _lv_usable_get prop_not_implemented_get #define _lv_skip_activation_set prop_not_implemented_set #define _lv_skip_activation_get prop_not_implemented_get #define _lv_check_needed_set prop_not_implemented_set diff --git a/lib/report/report.c b/lib/report/report.c index cd7971562..dad7649aa 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -3900,6 +3900,19 @@ static int _lvhealthstatus_disp(struct dm_report *rh, struct dm_pool *mem, return _field_string(rh, field, health); } +static int _lvusable_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + const struct lv_with_info_and_seg_status *lvdm = (const struct lv_with_info_and_seg_status *) data; + const struct logical_volume *lv = lvdm->lv; + const char *usable = ""; + + usable = _lv_is_usable(lv, NULL) ? "usable" : "not usable"; + + return _field_string(rh, field, usable); +} + static int _lvcheckneeded_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) diff --git a/lib/report/values.h b/lib/report/values.h index 9b98c229e..53f285db6 100644 --- a/lib/report/values.h +++ b/lib/report/values.h @@ -102,6 +102,7 @@ FIELD_RESERVED_VALUE(NAMED | RANGE | FUZZY | DYNAMIC, lv_time_removed, lv_time_r FIELD_RESERVED_VALUE(NOFLAG, cache_policy, cache_policy_undef, "", "", "", "undefined") FIELD_RESERVED_VALUE(NOFLAG, seg_monitor, seg_monitor_undef, "", "", "", "undefined") FIELD_RESERVED_VALUE(NOFLAG, lv_health_status, health_undef, "", "", "", "undefined") +FIELD_RESERVED_VALUE(NOFLAG, lv_usable, usable_undef, "", "", "", "undefined") FIELD_RESERVED_VALUE(NOFLAG, kernel_discards, seg_kernel_discards_undef, "", "", "", "undefined") FIELD_RESERVED_VALUE(NOFLAG, vdo_write_policy, vdo_write_policy_undef, "", "", "", "undefined") /* TODO the following 2 need STR_LIST support for reserved values -- 2.27.0 _______________________________________________ linux-lvm mailing list linux-lvm@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/linux-lvm read the LVM HOW-TO at http://tldp.org/HOWTO/LVM-HOWTO/