Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8d1d83504dcf9c86…
Commit: 8d1d83504dcf9c86ad42d34d3bd0b201d7bab8f6
Parent: 9ba40da7ae908fb36cb9927cde60a1a45cacce80
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Tue Sep 10 15:49:05 2013 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Sep 10 16:27:58 2013 +0200
udev: fix pvscan --cache -aay to trigger on relevant events
This patch fixes the way the special devices are handled
(special in this context means that they're not usable
after the usual ADD event like other generic devices):
- DM and MD devices are pvscanned only when they are just set up.
This is the first CHANGE event that makes the device usable
(the DM_UDEV_PRIMARY_SOURCE_FLAG is set for DM and the
md/array_state sysfs attribute is present for MD).
Whether the device is activated is remembered via
DM_ACTIVATED (for DM) and LVM_MD_PV_ACTIVATED (for MD)
udev environment variable. This is then used to decide
whether we should fire the pvscan on ADD event to
support coldplugging. For any (artificial) ADD event
generated during coldplug, the device must be already
set up properly to fire the pvscan on it.
- Similar for loop devices. For loop devices, only CHANGE
events are relevant (so there's a CHANGE after the loop
device is set up as well as detached). Whether the loop
has just been activated is detected via loop/backing_file
sysfs attribute presence. The activation state is remembered
via LVM_LOOP_PV_ACTIVATED udev environment variable.
- Do not pvscan multipath device components (underlying paths).
- Do not pvscan RAID device components.
- Also, set LVM_SCANNED="1" udev environment variable for
debug purposes (it's visible in the lvmdump -u that takes
the current udev database). This variable is set once
the pvscan is triggered.
The table below summarises when the pvscan is triggered
(marked with X, X* means fire only if the special dev is properly set up):
| real ADD | real CHANGE | artificial ADD | artificial CHANGE | remove
=============================================================================
DM | | X | X* | | X
MD | | X | X* | |
loop | | X | X* | |
other | X | | X | | X
---
udev/10-dm.rules.in | 20 +++++-------
udev/13-dm-disk.rules.in | 4 --
udev/69-dm-lvm-metad.rules.in | 66 +++++++++++++++++++++++++++++++++++-----
3 files changed, 65 insertions(+), 25 deletions(-)
diff --git a/udev/10-dm.rules.in b/udev/10-dm.rules.in
index 3a157d5..f495103 100644
--- a/udev/10-dm.rules.in
+++ b/udev/10-dm.rules.in
@@ -45,14 +45,13 @@ ENV{DISK_RO}=="1", GOTO="dm_disable"
# in libdevmapper so we need to detect this and try to behave correctly.
# For such spurious events, regenerate all flags from current udev database content
# (this information would normally be inaccessible for spurious ADD and CHANGE events).
-ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}=="1", ENV{DM_ACTIVATION}="1", GOTO="dm_flags_done"
+ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}=="1", ENV{DM_ACTIVATED}="1", GOTO="dm_flags_done"
IMPORT{db}="DM_UDEV_DISABLE_DM_RULES_FLAG"
IMPORT{db}="DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG"
IMPORT{db}="DM_UDEV_DISABLE_DISK_RULES_FLAG"
IMPORT{db}="DM_UDEV_DISABLE_OTHER_RULES_FLAG"
IMPORT{db}="DM_UDEV_LOW_PRIORITY_FLAG"
IMPORT{db}="DM_UDEV_DISABLE_LIBRARY_FALLBACK_FLAG"
-IMPORT{db}="DM_UDEV_PRIMARY_SOURCE_FLAG"
IMPORT{db}="DM_UDEV_FLAG7"
IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG0"
IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1"
@@ -63,6 +62,7 @@ IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG5"
IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG6"
IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG7"
IMPORT{db}="DM_UDEV_RULES_VSN"
+IMPORT{db}="DM_ACTIVATED"
LABEL="dm_flags_done"
# Normally, we operate on "change" events. But when coldplugging, there's an
@@ -77,28 +77,24 @@ LABEL="dm_flags_done"
# before (e.g. in initrd). If udev is used in initrd, we require the udev init
# script to not remove the existing udev database so we can reuse the information
# stored at the time of device activation in the initrd.
-# The DM_ACTIVATION variable tells when any device stacked above should be
-# (re)activated as well.
-ACTION!="add", GOTO="dm_no_coldplug"
-ENV{DM_UDEV_RULES_VSN}!="1", ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}!="1", GOTO="dm_disable"
-ENV{DM_ACTIVATION}="1"
-LABEL="dm_no_coldplug"
+# The DM_ACTIVATED variable indicates that the device has already been activated.
+ACTION=="add", ENV{DM_UDEV_RULES_VSN}!="1", ENV{DM_ACTIVATED}!="1", GOTO="dm_disable"
# Putting it together, following table is used to recognize genuine and spurious events.
# N.B. Spurious events are generated based on use of the WATCH udev
# rule or by triggering an event manually by "udevadm trigger" call
# or by "echo <event_name> > /sys/block/dm-X/uevent".
#
-# EVENT DM_UDEV_PRIMARY_SOURCE_FLAG DM_ACTIVATION
-# ======================================================================
+# EVENT DM_UDEV_PRIMARY_SOURCE_FLAG DM_ACTIVATED
+# ====================================================================
# add event (genuine) 0 0
# change event (genuine) 1 1
# add event (spurious)
# |_ dev still not active 0 0
-# \_ dev already active 1 1
+# \_ dev already active 0 1
# change event (spurious)
# |_ dev still not active 0 0
-# \_ dev already active 1 0
+# \_ dev already active 0 1
# "dm" sysfs subdirectory is available in newer versions of DM
# only (kernels >= 2.6.29). We have to check for its existence
diff --git a/udev/13-dm-disk.rules.in b/udev/13-dm-disk.rules.in
index f8e4ac6..1920260 100644
--- a/udev/13-dm-disk.rules.in
+++ b/udev/13-dm-disk.rules.in
@@ -17,10 +17,6 @@ ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}=="1", GOTO="dm_end"
SYMLINK+="disk/by-id/dm-name-$env{DM_NAME}"
ENV{DM_UUID}=="?*", SYMLINK+="disk/by-id/dm-uuid-$env{DM_UUID}"
-# Save previously detected dev type.
-IMPORT{db}="ID_FS_TYPE"
-ENV{ID_FS_TYPE}=="?*", ENV{DM_ID_FS_TYPE_OLD}="$env{ID_FS_TYPE}", ENV{ID_FS_TYPE}=""
-
ENV{DM_SUSPENDED}=="1", GOTO="dm_end"
(BLKID_RULE)
diff --git a/udev/69-dm-lvm-metad.rules.in b/udev/69-dm-lvm-metad.rules.in
index aa787e3..f2d2f1b 100644
--- a/udev/69-dm-lvm-metad.rules.in
+++ b/udev/69-dm-lvm-metad.rules.in
@@ -17,23 +17,71 @@
SUBSYSTEM!="block", GOTO="lvm_end"
(LVM_EXEC_RULE)
-# If the PV label got lost, inform lvmetad about it.
-ENV{DM_ID_FS_TYPE_OLD}=="LVM2_member|LVM1_member", ENV{ID_FS_TYPE}!="LVM2_member|LVM1_member", GOTO="lvm_scan"
+# 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}"
+IMPORT{db}="ID_FS_TYPE"
+ENV{ID_FS_TYPE}=="LVM2_member|LVM1_member", ENV{.ID_FS_TYPE_NEW}!="LVM2_member|LVM1_member", ENV{LVM_PV_GONE}="1"
+ENV{ID_FS_TYPE}="$env{.ID_FS_TYPE_NEW}"
+ENV{LVM_PV_GONE}=="1", GOTO="lvm_scan"
# Only process devices already marked as a PV - this requires blkid to be called before.
ENV{ID_FS_TYPE}!="LVM2_member|LVM1_member", GOTO="lvm_end"
+# Inform lvmetad about any PV that is gone.
ACTION=="remove", GOTO="lvm_scan"
-ACTION=="change", KERNEL=="md[0-9]*|loop[0-9]*", GOTO="lvm_scan"
-# If the PV is not a dm device, scan only after device addition (ADD event)
-KERNEL!="dm-[0-9]*", ACTION!="add", GOTO="lvm_end"
+# If the PV is a special device listed below, scan only if the device is
+# properly activated. These devices are not usable after an ADD event,
+# but they require an extra setup and they are ready after a CHANGE event.
+# Also support coldplugging with ADD event but only if the device is already
+# properly activated.
-# If the PV is a dm device, scan only after proper mapping activation (CHANGE event + DM_ACTIVATION=1)
-# or after a coldplug (event retrigger) with "add" event (ADD event + DM_ACTIVATION=1)
-KERNEL=="dm-[0-9]*", ENV{DM_ACTIVATION}!="1", GOTO="lvm_end"
+# DM device:
+KERNEL!="dm-[0-9]*", GOTO="next"
+ACTION=="add", ENV{DM_ACTIVATED}=="1", GOTO="lvm_scan"
+ACTION=="change", ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}=="1", GOTO="lvm_scan"
+GOTO="lvm_end"
+
+# MD device:
+LABEL="next"
+KERNEL!="md[0-9]*", GOTO="next"
+IMPORT{db}="LVM_MD_PV_ACTIVATED"
+ACTION=="add", ENV{LVM_MD_PV_ACTIVATED}=="1", GOTO="lvm_scan"
+ACTION=="change", ENV{LVM_MD_PV_ACTIVATED}!="1", TEST=="md/array_state", ENV{LVM_MD_PV_ACTIVATED}="1", GOTO="lvm_scan"
+GOTO="lvm_end"
+
+# Loop device:
+LABEL="next"
+KERNEL!="loop[0-9]*", GOTO="next"
+ACTION=="add", ENV{LVM_LOOP_PV_ACTIVATED}=="1", GOTO="lvm_scan"
+ACTION=="change", ENV{LVM_LOOP_PV_ACTIVATED}!="1", TEST=="loop/backing_file", ENV{LVM_LOOP_PV_ACTIVATED}="1", GOTO="lvm_scan"
+GOTO="lvm_end"
+
+# If the PV is not a special device listed above, scan only after device addition (ADD event)
+LABEL="next"
+ACTION!="add", GOTO="lvm_end"
LABEL="lvm_scan"
-RUN+="(LVM_EXEC)/lvm pvscan --background --cache --activate ay --major $major --minor $minor"
+
+# The table below summarises the situations in which we reach the LABEL="lvm_scan".
+# Marked by X, X* means only if the special dev is properly set up.
+# The artificial ADD is supported for coldplugging. We avoid running the pvscan
+# on artificial CHANGE so there's no unexpected autoactivation when WATCH rule fires.
+# N.B. MD and loop never actually reaches lvm_scan on REMOVE as the PV label is gone
+# within a CHANGE event (these are caught by the "LVM_PV_GONE" rule at the beginning).
+#
+# | real ADD | real CHANGE | artificial ADD | artificial CHANGE | REMOVE
+# =============================================================================
+# DM | | X | X* | | X
+# MD | | X | X* | |
+# loop | | X | X* | |
+# other | X | | X | | X
+
+# Skip device that is a multipath or RAID component
+ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="lvm_end"
+ENV{ID_FS_TYPE}=="*_raid_member", GOTO="lvm_end"
+
+RUN+="(LVM_EXEC)/lvm pvscan --background --cache --activate ay --major $major --minor $minor", ENV{LVM_SCANNED}="1"
LABEL="lvm_end"
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=9ba40da7ae908fb3…
Commit: 9ba40da7ae908fb36cb9927cde60a1a45cacce80
Parent: ca514351536c2dd8929944bb6b01a64587cb0a46
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Tue Sep 10 12:38:18 2013 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Sep 10 12:39:23 2013 +0200
udev: DM_ID_FS_TYPE should be ID_FS_TYPE when comparing with old value
---
udev/69-dm-lvm-metad.rules.in | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/udev/69-dm-lvm-metad.rules.in b/udev/69-dm-lvm-metad.rules.in
index b4be582..aa787e3 100644
--- a/udev/69-dm-lvm-metad.rules.in
+++ b/udev/69-dm-lvm-metad.rules.in
@@ -18,7 +18,7 @@ SUBSYSTEM!="block", GOTO="lvm_end"
(LVM_EXEC_RULE)
# If the PV label got lost, inform lvmetad about it.
-ENV{DM_ID_FS_TYPE_OLD}=="LVM2_member|LVM1_member", ENV{DM_ID_FS_TYPE}!="LVM2_member|LVM1_member", GOTO="lvm_scan"
+ENV{DM_ID_FS_TYPE_OLD}=="LVM2_member|LVM1_member", ENV{ID_FS_TYPE}!="LVM2_member|LVM1_member", GOTO="lvm_scan"
# Only process devices already marked as a PV - this requires blkid to be called before.
ENV{ID_FS_TYPE}!="LVM2_member|LVM1_member", GOTO="lvm_end"
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ca514351536c2dd8…
Commit: ca514351536c2dd8929944bb6b01a64587cb0a46
Parent: 9f2fc2471cd39effccd549d73c2fc9c0e6419f94
Author: Jonathan Brassow <jbrassow(a)redhat.com>
AuthorDate: Mon Sep 9 15:07:28 2013 -0500
Committer: Jonathan Brassow <jbrassow(a)redhat.com>
CommitterDate: Mon Sep 9 15:07:28 2013 -0500
Misc/RAID: Enable resume_lv to handle some renaming conflicts.
When images and their associated metadata are removed from a RAID1 LV,
the remaining sub-LVs are "shifted" down to fill the gaps. For
example, if there is a 3-way mirror:
[0][1][2]
and we remove device#0, the devices will be shifted down
[1][2]
and renamed.
[0][1]
This can create a problem for resume_lv (specifically,
dm_tree_activate_children) during the renaming process though. This
is because it will attempt to rename the higher indexed sub-LVs first
and find that it cannot because there are currently other sub-LVs with
that name. The solution is to check for a conflicting name before
attempting to rename. If a conflict is found and that conflicting
sub-LV is also in the process of renaming, we can defer the current
rename until the conflicting sub-LV has renamed and cleared the
conflict.
Now that resume_lv can handle these types of rename conflicts, we can
remove the workaround in RAID that was attempting to resume a RAID1
LV from the bottom-up in order to force a proper rename in assending
order before attempting a resume on the top-level LV. This "hack"
only worked for single machine use-cases of LVM. Clearing this up
paves the way for exclusive activation of RAID LVs in a cluster.
---
lib/metadata/raid_manip.c | 42 +--------------------------------
libdm/libdm-deptree.c | 55 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 57 insertions(+), 40 deletions(-)
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 47c2788..d13750d 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -59,24 +59,6 @@ uint32_t lv_raid_image_count(const struct logical_volume *lv)
return seg->area_count;
}
-/*
- * Resume sub-LVs first, then top-level LV
- */
-static int _bottom_up_resume(struct logical_volume *lv)
-{
- uint32_t s;
- struct lv_segment *seg = first_seg(lv);
-
- if (seg_is_raid(seg) && (seg->area_count > 1)) {
- for (s = 0; s < seg->area_count; s++)
- if (!resume_lv(lv->vg->cmd, seg_lv(seg, s)) ||
- !resume_lv(lv->vg->cmd, seg_metalv(seg, s)))
- return_0;
- }
-
- return resume_lv(lv->vg->cmd, lv);
-}
-
static int _activate_sublv_preserving_excl(struct logical_volume *top_lv,
struct logical_volume *sub_lv)
{
@@ -991,17 +973,7 @@ static int _raid_remove_images(struct logical_volume *lv,
}
}
- /*
- * Resume the remaining LVs
- * We must start by resuming the sub-LVs first (which would
- * otherwise be handled automatically) because the shifting
- * of positions could otherwise cause name collisions. For
- * example, if position 0 of a 3-way array is removed, position
- * 1 and 2 must be shifted and renamed 0 and 1. If position 2
- * tries to rename first, it will collide with the existing
- * position 1.
- */
- if (!_bottom_up_resume(lv)) {
+ if (!resume_lv(lv->vg->cmd, lv)) {
log_error("Failed to resume %s/%s after committing changes",
lv->vg->name, lv->name);
return 0;
@@ -1164,17 +1136,7 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
if (!resume_lv(cmd, lvl->lv))
return_0;
- /*
- * Resume the remaining LVs
- * We must start by resuming the sub-LVs first (which would
- * otherwise be handled automatically) because the shifting
- * of positions could otherwise cause name collisions. For
- * example, if position 0 of a 3-way array is split, position
- * 1 and 2 must be shifted and renamed 0 and 1. If position 2
- * tries to rename first, it will collide with the existing
- * position 1.
- */
- if (!_bottom_up_resume(lv)) {
+ if (!resume_lv(lv->vg->cmd, lv)) {
log_error("Failed to resume %s/%s after committing changes",
lv->vg->name, lv->name);
return 0;
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index 57f00f6..752a44b 100644
--- a/libdm/libdm-deptree.c
+++ b/libdm/libdm-deptree.c
@@ -1702,11 +1702,58 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
return r;
}
+/*
+ * _rename_conflict_exists
+ * @dnode
+ * @node
+ * @resolvable
+ *
+ * Check if there is a rename conflict with existing peers in
+ * this tree. 'resolvable' is set if the conflicting node will
+ * also be undergoing a rename. (Allowing that node to rename
+ * first would clear the conflict.)
+ *
+ * Returns: 1 if conflict, 0 otherwise
+ */
+static int _rename_conflict_exists(struct dm_tree_node *parent,
+ struct dm_tree_node *node,
+ int *resolvable)
+{
+ void *handle = NULL;
+ const char *name = dm_tree_node_get_name(node);
+ const char *sibling_name;
+ struct dm_tree_node *sibling;
+
+ *resolvable = 0;
+
+ if (!name)
+ return_0;
+
+ while ((sibling = dm_tree_next_child(&handle, parent, 0))) {
+ if (sibling == node)
+ continue;
+
+ if (!(sibling_name = dm_tree_node_get_name(sibling))) {
+ stack;
+ continue;
+ }
+
+ if (!strcmp(node->props.new_name, sibling_name)) {
+ if (sibling->props.new_name)
+ *resolvable = 1;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
int dm_tree_activate_children(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len)
{
int r = 1;
+ int resolvable_name_conflict, awaiting_peer_rename = 0;
void *handle = NULL;
struct dm_tree_node *child = dnode;
struct dm_info newinfo;
@@ -1732,6 +1779,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
handle = NULL;
for (priority = 0; priority < 3; priority++) {
+ awaiting_peer_rename = 0;
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
if (priority != child->activation_priority)
continue;
@@ -1751,6 +1799,11 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
/* Rename? */
if (child->props.new_name) {
+ if (_rename_conflict_exists(dnode, child, &resolvable_name_conflict) &&
+ resolvable_name_conflict) {
+ awaiting_peer_rename++;
+ continue;
+ }
if (!_rename_node(name, child->props.new_name, child->info.major,
child->info.minor, &child->dtree->cookie,
child->udev_flags)) {
@@ -1779,6 +1832,8 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
/* Update cached info */
child->info = newinfo;
}
+ if (awaiting_peer_rename)
+ priority--; /* redo priority level */
}
/*