[dm-devel] [PATCH] Fix race-condition when reading sysfs attributes.

Konrad Rzeszutek konrad at virtualiron.com
Tue Mar 24 15:24:59 UTC 2009


This fix re-introduces a wait loop when reading sysfs attributes.
The reason a wait is necessary is due to the way the kernel
sends the event. When a SCSI device is added the SCSI subsystem
pursues this path:

_sysfs_add_sdev:
    calls device_add ...
    [ '/devices/platform/host16/session6/target16:0:0/16:0:0:17'] uevent
        bus_attach_device
            bus_for_each_drv
                driver_probe_device
                    sd_probe
                    ['/class/scsi_disk/16:0:0:17' ] uevent
                        add_disk
                        ['/block/sdai'] [ Here multipath starts its job ]

    calls class_device_add ...
        [ '/class/scsi_device/16:0:0:17' ] uevent
        sg_add:
            [ '/class/scsi_generic/sg35' ] uevent

    done with device_add, and now the kernel adds the  attributes:
    scsi_sysfs_sdev_attrs[i].vendor, model, rev

There are four uevents sent from the kernel in the creation of
a SysFS representation of the device. After the last event, the
SysFs entries for vendor,model, rev are populated. The window
time between the uevent with /block/sdX sent and the sysfs
attributes being populated is small. But it is possible (with
a slow serial link, slow SCSI target), to get us in a race
condition where multipath investigates the new block device and
finds it can't read the vendor, and the block device ends up
being discarded and never added to the device mapper multipath map.
---
 libmultipath/discovery.c |   38 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 38 insertions(+), 0 deletions(-)

diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 9ae2b8f..1d2c396 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -124,11 +124,49 @@ path_discovery (vector pathvec, struct config * conf, int flag)
 	return r;
 }
 
+
+#define WAIT_MAX_SECONDS 5
+#define WAIT_LOOP_PER_SECOND 5
+
+static int
+wait_for_file (char * filename)
+{
+	int loop;
+	struct stat stats;
+	/*
+ 	* the daemon can race udev upon path add,
+ 	* not multipath(8), if ran by udev
+ 	*/
+
+	if (!conf->daemon)
+		return 0;
+
+	loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
+
+	while (--loop) {
+		if (stat(filename, &stats) == 0)
+			return 0;
+
+		if (errno != ENOENT)
+			return 1;
+
+		usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
+	}
+	return 1;
+}
+
 #define declare_sysfs_get_str(fname) \
 extern int \
 sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \
 { \
 	char *attr; \
+	char attr_path[SYSFS_PATH_SIZE]; \
+\
+	if (safe_sprintf(attr_path, "%s/%s/%s", sysfs_path, dev->devpath, #fname)) \
+		return 1; \
+\
+	if (wait_for_file(attr_path)) \
+		return 1; \
 \
 	attr = sysfs_attr_get_value(dev->devpath, #fname); \
 	if (!attr) \
-- 
1.5.4.1




More information about the dm-devel mailing list