WHATS_NEW | 2 ++ daemons/clvmd/lvm-functions.c | 2 +- lib/activate/activate.c | 20 ++++++++++++-------- lib/activate/activate.h | 5 +++-- lib/activate/dev_manager.c | 15 +++++++++++---- lib/format_text/flags.c | 5 +++-- lib/locking/file_locking.c | 4 ++-- lib/locking/no_locking.c | 4 ++-- lib/metadata/lv_manip.c | 6 ++++++ lib/metadata/metadata-exported.h | 1 + udev/11-dm-lvm.rules.in | 15 +++++++++++++++ udev/13-dm-disk.rules.in | 3 ++- udev/69-dm-lvm-metad.rules.in | 2 ++ 13 files changed, 62 insertions(+), 22 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index e0cb795..cd55d54 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,7 @@ Version 2.02.104 - =================================== + Recognize new flag to skip udev scanning in udev rules and act appropriately. + Add support for flagging an LV to skip udev scanning during activation. Improve message when unable to change discards setting on active thin pool. Fix lvconvert when converting to a thin pool and thin LV at once. diff --git a/daemons/clvmd/lvm-functions.c b/daemons/clvmd/lvm-functions.c index da7d335..f544218 100644 --- a/daemons/clvmd/lvm-functions.c +++ b/daemons/clvmd/lvm-functions.c @@ -401,7 +401,7 @@ static int do_activate_lv(char *resource, unsigned char command, unsigned char l } /* Now activate it */ - if (!lv_activate(cmd, resource, exclusive, NULL)) + if (!lv_activate(cmd, resource, exclusive, 0, NULL)) goto error; return 0; diff --git a/lib/activate/activate.c b/lib/activate/activate.c index 28549fc..c077113 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -337,12 +337,13 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s, { return 1; } -int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, struct logical_volume *lv) +int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, int noscan, + struct logical_volume *lv) { return 1; } int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive, - struct logical_volume *lv) + int noscan, struct logical_volume *lv) { return 1; } @@ -2027,9 +2028,10 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, if (filter) laopts->read_only = _passes_readonly_filter(cmd, lv); - log_debug_activation("Activating %s/%s%s%s.", lv->vg->name, lv->name, + log_debug_activation("Activating %s/%s%s%s%s.", lv->vg->name, lv->name, laopts->exclusive ? " exclusively" : "", - laopts->read_only ? " read-only" : ""); + laopts->read_only ? " read-only" : "", + laopts->noscan ? " noscan" : ""); if (!lv_info(cmd, lv, 0, &info, 0, 0)) goto_out; @@ -2066,9 +2068,10 @@ out: } /* Activate LV */ -int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, struct logical_volume *lv) +int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, + int noscan, struct logical_volume *lv) { - struct lv_activate_opts laopts = { .exclusive = exclusive }; + struct lv_activate_opts laopts = { .exclusive = exclusive, .noscan = noscan }; if (!_lv_activate(cmd, lvid_s, &laopts, 0, lv)) return_0; @@ -2077,9 +2080,10 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, stru } /* Activate LV only if it passes filter */ -int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive, struct logical_volume *lv) +int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive, + int noscan, struct logical_volume *lv) { - struct lv_activate_opts laopts = { .exclusive = exclusive }; + struct lv_activate_opts laopts = { .exclusive = exclusive, .noscan = noscan }; if (!_lv_activate(cmd, lvid_s, &laopts, 1, lv)) return_0; diff --git a/lib/activate/activate.h b/lib/activate/activate.h index f34d376..4eac320 100644 --- a/lib/activate/activate.h +++ b/lib/activate/activate.h @@ -38,6 +38,7 @@ struct lv_activate_opts { int skip_in_use; unsigned revert; unsigned read_only; + unsigned noscan; }; /* target attribute flags */ @@ -80,9 +81,9 @@ int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned o int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, struct logical_volume *lv); int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive, unsigned revert, struct logical_volume *lv); -int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, struct logical_volume *lv); +int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, int noscan, struct logical_volume *lv); int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, - int exclusive, struct logical_volume *lv); + int exclusive, int noscan, struct logical_volume *lv); int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, struct logical_volume *lv); int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv); diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index b8233bf..0f5a04c 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -30,6 +30,7 @@ #include #define MAX_TARGET_PARAMSIZE 50000 +#define LVM_UDEV_NOSCAN_FLAG DM_SUBSYSTEM_UDEV_FLAG0 typedef enum { PRELOAD, @@ -1399,7 +1400,7 @@ static int _check_udev_fallback(struct cmd_context *cmd) #endif /* UDEV_SYNC_SUPPORT */ static uint16_t _get_udev_flags(struct dev_manager *dm, struct logical_volume *lv, - const char *layer) + const char *layer, uint16_t flags) { uint16_t udev_flags = 0; @@ -1447,6 +1448,11 @@ static uint16_t _get_udev_flags(struct dev_manager *dm, struct logical_volume *l udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG; + /* + * Firmly set requested flags. + */ + udev_flags |= flags; + return udev_flags; } @@ -1493,7 +1499,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, } if (info.exists && !dm_tree_add_dev_with_udev_flags(dtree, info.major, info.minor, - _get_udev_flags(dm, lv, layer))) { + _get_udev_flags(dm, lv, layer, 0))) { log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to dtree", info.major, info.minor); return 0; @@ -2334,7 +2340,7 @@ static int _set_udev_flags_for_children(struct dev_manager *dm, } dm_tree_node_set_udev_flags(child, - _get_udev_flags(dm, lvl->lv, NULL)); + _get_udev_flags(dm, lvl->lv, NULL, 0)); } return 1; @@ -2411,7 +2417,8 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, read_only_lv(lv, laopts), ((lv->vg->status & PRECOMMITTED) | laopts->revert) ? 1 : 0, lvlayer, - _get_udev_flags(dm, lv, layer)))) + _get_udev_flags(dm, lv, layer, + laopts->noscan ? LVM_UDEV_NOSCAN_FLAG : 0)))) return_0; /* Store existing name so we can do rename later */ diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c index 5077576..a27b791 100644 --- a/lib/format_text/flags.c +++ b/lib/format_text/flags.c @@ -61,6 +61,7 @@ static const struct flag _lv_flags[] = { {LV_REBUILD, "REBUILD", STATUS_FLAG}, {LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG}, {LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG}, + {LV_NOSCAN, NULL, 0}, {POOL_METADATA_SPARE, NULL, 0}, {RAID, NULL, 0}, {RAID_META, NULL, 0}, @@ -144,8 +145,8 @@ int print_flags(uint64_t status, int type, char *buffer, size_t size) return 0; if (status) - log_warn("Metadata inconsistency: Not all flags successfully " - "exported."); + log_warn(INTERNAL_ERROR "Metadata inconsistency: " + "Not all flags successfully exported."); return 1; } diff --git a/lib/locking/file_locking.c b/lib/locking/file_locking.c index 5e49bc4..b6b2b10 100644 --- a/lib/locking/file_locking.c +++ b/lib/locking/file_locking.c @@ -305,7 +305,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource, break; case LCK_READ: log_very_verbose("Locking LV %s (R)", resource); - if (!lv_activate_with_filter(cmd, resource, 0, lv_ondisk(lv))) + if (!lv_activate_with_filter(cmd, resource, 0, lv->status & LV_NOSCAN ? 1 : 0, lv_ondisk(lv))) return 0; break; case LCK_PREAD: @@ -318,7 +318,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource, break; case LCK_EXCL: log_very_verbose("Locking LV %s (EX)", resource); - if (!lv_activate_with_filter(cmd, resource, 1, lv_ondisk(lv))) + if (!lv_activate_with_filter(cmd, resource, 1, lv->status & LV_NOSCAN ? 1 : 0, lv_ondisk(lv))) return 0; break; default: diff --git a/lib/locking/no_locking.c b/lib/locking/no_locking.c index 5f3f0b6..4772706 100644 --- a/lib/locking/no_locking.c +++ b/lib/locking/no_locking.c @@ -48,11 +48,11 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource, case LCK_UNLOCK: return lv_resume_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1: 0, 0, (flags & LCK_REVERT) ? 1 : 0, lv_ondisk(lv)); case LCK_READ: - return lv_activate_with_filter(cmd, resource, 0, lv_ondisk(lv)); + return lv_activate_with_filter(cmd, resource, 0, lv->status & LV_NOSCAN ? 1 : 0, lv_ondisk(lv)); case LCK_WRITE: return lv_suspend_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1 : 0, 0, lv_ondisk(lv), lv); case LCK_EXCL: - return lv_activate_with_filter(cmd, resource, 1, lv_ondisk(lv)); + return lv_activate_with_filter(cmd, resource, 1, lv->status & LV_NOSCAN ? 1 : 0, lv_ondisk(lv)); default: break; } diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index f42db1d..22327d7 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -5421,6 +5421,8 @@ int set_lv(struct cmd_context *cmd, struct logical_volume *lv, if (!dev_close_immediate(dev)) stack; + lv->status &= ~LV_NOSCAN; + return 1; } @@ -5977,6 +5979,10 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, goto out; } + /* Do not scan this LV until properly zeroed. */ + if (lp->zero) + lv->status |= LV_NOSCAN; + if (lv_is_thin_pool(lv)) { if (is_change_activating(lp->activate)) { if (vg_is_clustered(lv->vg)) { diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index 308dcfe..1e9543a 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -102,6 +102,7 @@ #define LV_WRITEMOSTLY UINT64_C(0x0000020000000000) /* LV (RAID1) */ #define LV_ACTIVATION_SKIP UINT64_C(0x0000040000000000) /* LV */ +#define LV_NOSCAN UINT64_C(0x0000080000000000) /* LV */ /* Format features flags */ #define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */ diff --git a/udev/11-dm-lvm.rules.in b/udev/11-dm-lvm.rules.in index f21d0aa..5032280 100644 --- a/udev/11-dm-lvm.rules.in +++ b/udev/11-dm-lvm.rules.in @@ -20,6 +20,21 @@ ENV{DM_UUID}!="LVM-?*", GOTO="lvm_end" # Use DM name and split it up into its VG/LV/layer constituents. IMPORT{program}="(DM_EXEC)/dmsetup splitname --nameprefixes --noheadings --rows $env{DM_NAME}" +# DM_SUBSYSTEM_UDEV_FLAG0 is the 'NOSCAN' flag for LVM subsystem. +# This flag is used to temporarily disable selected rules to prevent any +# processing or scanning done on the LVM volume before LVM has any chance +# to zero any stale metadata found within the LV data area. Such stale +# metadata could cause false claim of the LV device, keeping it open etc. +# +# If the NOSCAN flag is present, backup selected existing flags used to +# disable rules, then set them firmly so those selected rules are surely skipped. +# Restore these flags once the NOSCAN flag is dropped (which is normally any +# uevent that follows for this LV, even an artificially generated one). +ENV{DM_SUBSYSTEM_UDEV_FLAG0}=="1", ENV{DM_NOSCAN}="1", ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="$env{DM_UDEV_DISABLE_OTHER_RULES_FLAG}", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1" +ENV{DM_SUBSYSTEM_UDEV_FLAG0}!="1", IMPORT{db}="DM_NOSCAN", IMPORT{db}="DM_DISABLE_OTHER_RULES_FLAG_OLD" +ENV{DM_SUBSYSTEM_UDEV_FLAG0}!="1", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{DM_DISABLE_OTHER_RULES_FLAG_OLD}", \ + ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG_OLD}="", ENV{DM_NOSCAN}="" + ENV{DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG}=="1", GOTO="lvm_end" OPTIONS+="event_timeout=180" diff --git a/udev/13-dm-disk.rules.in b/udev/13-dm-disk.rules.in index 1920260..4b64dd6 100644 --- a/udev/13-dm-disk.rules.in +++ b/udev/13-dm-disk.rules.in @@ -18,6 +18,7 @@ SYMLINK+="disk/by-id/dm-name-$env{DM_NAME}" ENV{DM_UUID}=="?*", SYMLINK+="disk/by-id/dm-uuid-$env{DM_UUID}" ENV{DM_SUSPENDED}=="1", GOTO="dm_end" +ENV{DM_NOSCAN}=="1", GOTO="dm_watch" (BLKID_RULE) ENV{DM_UDEV_LOW_PRIORITY_FLAG}=="1", OPTIONS="link_priority=-100" @@ -32,7 +33,7 @@ ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk # (like creating a filesystem, changing filesystem label etc.). # # But let's use this until we have something better... - +LABEL="dm_watch" OPTIONS+="watch" LABEL="dm_end" diff --git a/udev/69-dm-lvm-metad.rules.in b/udev/69-dm-lvm-metad.rules.in index ba43396..3303f4d 100644 --- a/udev/69-dm-lvm-metad.rules.in +++ b/udev/69-dm-lvm-metad.rules.in @@ -17,6 +17,8 @@ SUBSYSTEM!="block", GOTO="lvm_end" (LVM_EXEC_RULE) +ENV{DM_NOSCAN}=="1", GOTO="lvm_end" + # If the PV label got lost, inform lvmetad immediately. # Detect the lost PV label by comparing previous ID_FS_TYPE value with current one. ENV{.ID_FS_TYPE_NEW}="$env{ID_FS_TYPE}"