File wait_udev.diff of Package device-mapper
Index: lib/ioctl/libdm-iface.c
===================================================================
--- lib/ioctl/libdm-iface.c.orig
+++ lib/ioctl/libdm-iface.c
@@ -118,6 +118,67 @@ static struct cmd_data _cmd_data_v4[] =
# define DM_EXISTS_FLAG 0x00000004
#endif
+static unsigned long long get_seq()
+{
+ struct stat s;
+ int r;
+ unsigned long long seq = 0;
+ FILE* fp;
+ r = stat("/sys/kernel/uevent_seqnum", &s);
+ if (r) { return seq; }
+ if (!S_ISREG(s.st_mode)) { return seq; }
+ fp = fopen("/sys/kernel/uevent_seqnum", "r");
+ if (fp == NULL) { return seq; }
+ fscanf(fp, "%llu\n", &seq);
+ fclose(fp);
+ return seq;
+}
+
+static int wait_4_udev(unsigned long long start_seq, unsigned long long end_seq)
+{
+ FILE* fp;
+ struct stat s;
+ int r;
+ int ite=30; /* Iterate 30 times. Otherwise, it's considered timed out */
+ unsigned long long seq;
+ /*
+ * len("/dev/.udev/queue/") + len(str(0xffffffffffffffff)) = 38
+ */
+ #define PATH_SIZE 40
+ char filename[PATH_SIZE];
+ #undef PATH_SIZE
+
+ if (start_seq > end_seq || end_seq == 0) return 1;
+
+ /* Wait until end_seq is enqueued into udev */
+ r = stat("/dev/.udev/uevent_seqnum", &s);
+ if (r) { return 1; }
+ if (!S_ISREG(s.st_mode)) { return 1; }
+ while (ite-- > 0) {
+ fp = fopen("/dev/.udev/uevent_seqnum", "r");
+ if (fp == NULL) { return 1; }
+ fscanf(fp, "%llu\n", &seq);
+ fclose(fp);
+ if (seq >= end_seq) { break; }
+ usleep(200000);
+ }
+ if (ite <=0 ) return 1;
+
+ /* Loop to make sure all $seq are unlinked in /dev/.udev/queue then */
+ for (seq = start_seq; seq <= end_seq; seq++) {
+ ite = 30;
+ while (ite-- > 0) {
+ snprintf(filename, sizeof(filename), "/dev/.udev/queue/%llu", seq);
+ r = open(filename, O_RDONLY);
+ if (r == -1 && errno == ENOENT) break;
+ if (r >= 0) close(r);
+ usleep(200000);
+ }
+ if (ite <=0 ) return 1;
+ }
+ return 0;
+}
+
static void *_align(void *ptr, unsigned int a)
{
register unsigned long agn = --a;
@@ -642,6 +703,7 @@ static int _dm_task_run_v1(struct dm_tas
{
struct dm_ioctl_v1 *dmi;
unsigned int command;
+ unsigned long long before_seq, after_seq;
dmi = _flatten_v1(dmt);
if (!dmi) {
@@ -668,6 +730,8 @@ static int _dm_task_run_v1(struct dm_tas
dmi->name, dmi->uuid, dmt->newname ? " " : "",
dmt->newname ? dmt->newname : "",
dmi->data_size);
+
+ before_seq = get_seq();
if (dmt->type == DM_DEVICE_LIST) {
if (!_dm_names_v1(dmi))
goto bad;
@@ -687,10 +751,13 @@ static int _dm_task_run_v1(struct dm_tas
#else /* Userspace alternative for testing */
#endif
+ after_seq = get_seq();
if (dmi->flags & DM_BUFFER_FULL_FLAG)
/* FIXME Increase buffer size and retry operation (if query) */
log_error("WARNING: libdevmapper buffer too small for data");
+ wait_4_udev(before_seq, after_seq);
+
switch (dmt->type) {
case DM_DEVICE_CREATE:
add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev),
@@ -1640,6 +1707,7 @@ int dm_task_run(struct dm_task *dmt)
{
struct dm_ioctl *dmi;
unsigned command;
+ unsigned long long before_seq, after_seq;
#ifdef DM_COMPAT
if (_dm_version == 1)
@@ -1670,9 +1738,11 @@ int dm_task_run(struct dm_task *dmt)
return 0;
repeat_ioctl:
+ before_seq = get_seq();
if (!(dmi = _do_dm_ioctl(dmt, command, _ioctl_buffer_double_factor)))
return 0;
+ after_seq = get_seq();
if (dmi->flags & DM_BUFFER_FULL_FLAG) {
switch (dmt->type) {
case DM_DEVICE_LIST_VERSIONS:
@@ -1689,6 +1759,8 @@ repeat_ioctl:
}
}
+ wait_4_udev(before_seq, after_seq);
+
switch (dmt->type) {
case DM_DEVICE_CREATE:
if (dmt->dev_name && *dmt->dev_name)