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)
openSUSE Build Service is sponsored by