Re: [PATCH] race between util_create_path() and util_delete_path()?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

> That would limit paralellism to some degree.
> 
> Retrys won't be needed very often; they would surely have a lower
> overhead.  Less code too :-).  It's not completely out of left field;
> both seqlocks and transactional memory use retries.  There's no risk
> of livelock (i.e. infinite retries)...
> 
> I'm lazy and don't want udev to run measurably slower.  The only
> advantage I see of flock() is that it tells the reader "I'm a
> synchronization primitive, solving a concurrency problem here".  I
> think we can get close enough by explaining the race in a comment next
> to the definition of create_path().

plus, it seems to be the simpler solution by far - which is why I went
with flock() in my suggested fix you find below. Untested, as usual, and
I don't really have a clue whether there are any unhealthy interactions
with the rest of udev in this solution. Also, you most likely will want
to change the path of the lock file ;-)

Florian

diff --git a/libudev/libudev-device-private.c b/libudev/libudev-device-private.c
index 68dc0a5..43cf152 100644
--- a/libudev/libudev-device-private.c
+++ b/libudev/libudev-device-private.c
@@ -86,6 +86,7 @@ file:
 	f = fopen(filename, "w");
 	if (f == NULL) {
 		err(udev, "unable to create db file '%s': %m\n", filename);
+		util_create_path_done();
 		return -1;
 		}
 	info(udev, "created db file for '%s' in '%s'\n", udev_device_get_devpath(udev_device), filename);
@@ -114,6 +115,7 @@ file:
 	}
 	fclose(f);
 out:
+	util_create_path_done();
 	return 0;
 }
 
diff --git a/libudev/libudev-queue-private.c b/libudev/libudev-queue-private.c
index 0427b65..f2f3905 100644
--- a/libudev/libudev-queue-private.c
+++ b/libudev/libudev-queue-private.c
@@ -417,6 +417,7 @@ static void update_failed(struct udev_queue_export *udev_queue_export,
 		udev_selinux_setfscreatecon(udev, filename, S_IFLNK);
 		symlink(udev_device_get_devpath(udev_device), filename);
 		udev_selinux_resetfscreatecon(udev);
+		util_create_path_done();
 		break;
 
 	case DEVICE_QUEUED:
diff --git a/libudev/libudev-util-private.c b/libudev/libudev-util-private.c
index c309945..9d205d4 100644
--- a/libudev/libudev-util-private.c
+++ b/libudev/libudev-util-private.c
@@ -25,6 +25,29 @@
 #include "libudev.h"
 #include "libudev-private.h"
 
+static int util_path_lock_fd = -1;
+
+static void util_path_unlock(void)
+{
+	if (util_path_lock_fd >= 0) {
+		close(util_create_path_lock_fd);
+		util_create_path_lock_fd = -1;
+	}
+}
+
+static int util_path_lock(void)
+{
+	if (util_path_lock_fd < 0) {
+		if ((util_path_lock_fd = open("/dev/udev_util_path_lock", O_WRONLY | O_CREAT)) < 0)
+			return -1;
+		if (flock(util_path_lock_fd, LOCK_EX)) {
+			util_path_unlock();
+			return -1;
+		}
+	}
+	return 0;
+}
+
 int util_create_path(struct udev *udev, const char *path)
 {
 	char p[UTIL_PATH_SIZE];
@@ -32,6 +55,8 @@ int util_create_path(struct udev *udev, const char *path)
 	struct stat stats;
 	int ret;
 
+	if (util_path_lock())
+		return -1;
 	util_strscpy(p, sizeof(p), path);
 	pos = strrchr(p, '/');
 	if (pos == NULL)
@@ -63,6 +88,11 @@ int util_create_path(struct udev *udev, const char *path)
 	return -1;
 }
 
+void util_create_path_done(void)
+{
+	util_path_unlock();
+}
+
 int util_delete_path(struct udev *udev, const char *path)
 {
 	char p[UTIL_PATH_SIZE];
@@ -75,6 +105,8 @@ int util_delete_path(struct udev *udev, const char *path)
 	if (pos == p || pos == NULL)
 		return 0;
 
+	if (util_path_lock())
+		return 0;
 	while (1) {
 		*pos = '\0';
 		pos = strrchr(p, '/');
@@ -88,13 +120,13 @@ int util_delete_path(struct udev *udev, const char *path)
 		if (errno == ENOENT)
 			retval = 0;
 		if (retval) {
-			if (errno == ENOTEMPTY)
-				return 0;
-			err(udev, "rmdir(%s) failed: %m\n", p);
+			if (errno != ENOTEMPTY)
+				err(udev, "rmdir(%s) failed: %m\n", p);
 			break;
 		}
 		dbg(udev, "removed '%s'\n", p);
 	}
+	util_path_unlock();
 	return 0;
 }
 
diff --git a/udev/udev-node.c b/udev/udev-node.c
index d73bc6c..74de922 100644
--- a/udev/udev-node.c
+++ b/udev/udev-node.c
@@ -48,6 +48,7 @@ static int name_index(struct udev *udev, const char *devpath, const char *name,
 		dbg(udev, "creating index: '%s'\n", filename);
 		util_create_path(udev, filename);
 		fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
+		util_create_path_done();
 		if (fd > 0)
 			close(fd);
 	} else {
@@ -356,6 +357,7 @@ static int update_link(struct udev_device *dev, const char *slink)
 	info(udev, "'%s' with target '%s' has the highest priority %i, create it\n", slink, target, priority);
 	util_create_path(udev, slink);
 	node_symlink(udev, target, slink);
+	util_create_path_done();
 out:
 	return rc;
 }
@@ -456,6 +458,7 @@ int udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid)
 		update_link(dev, udev_list_entry_get_name(list_entry));
 	}
 exit:
+	util_create_path_done();
 	return err;
 }
 
diff --git a/udev/udev-rules.c b/udev/udev-rules.c
index 54a54c3..f19ead8 100644
--- a/udev/udev-rules.c
+++ b/udev/udev-rules.c
@@ -1733,6 +1733,7 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
 			udev_selinux_setfscreatecon(udev, filename, S_IFDIR|0755);
 			mkdir(filename, 0755);
 			udev_selinux_resetfscreatecon(udev);
+			util_create_path_done();
 		}
 		udev_list_init(&sort_list);
 		add_matching_files(udev, &sort_list, filename, ".rules");
diff --git a/udev/udev-watch.c b/udev/udev-watch.c
index 5a49c96..3eb45a1 100644
--- a/udev/udev-watch.c
+++ b/udev/udev-watch.c
@@ -127,6 +127,7 @@ void udev_watch_begin(struct udev *udev, struct udev_device *dev)
 	util_create_path(udev, filename);
 	unlink(filename);
 	symlink(udev_device_get_devpath(dev), filename);
+	util_create_path_done();
 
 	udev_device_set_watch_handle(dev, wd);
 }
--
To unsubscribe from this list: send the line "unsubscribe linux-hotplug" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [Linux DVB]     [Asterisk Internet PBX]     [DCCP]     [Netdev]     [X.org]     [Util Linux NG]     [Fedora Women]     [ALSA Devel]     [Linux USB]

  Powered by Linux