chiark / gitweb /
[PATCH] udevd: serialization of the event sequence of a chain of devices
authorkay.sievers@vrfy.org <kay.sievers@vrfy.org>
Sat, 11 Dec 2004 20:43:08 +0000 (21:43 +0100)
committerGreg KH <gregkh@suse.de>
Wed, 27 Apr 2005 06:13:47 +0000 (23:13 -0700)
Currently udevd delays only events for the same DEVPATH.

Example of an "add" event sequence:
  /block/sda
  /block/sda/sda1

With this change, we make sure, that the udev process handling
/block/sda has finished its work (waited for all attributes,
created the node) before we fork the udev event for /block/sda/sda1.
This way the event for sda1 can be sure, that the node for the
main device is already created (may be useful for disk labels).

It will not affect any parallel device handling, only the sequence
of the devices directory chain is serialized. The 10.000 disks
plugged in will still run as parallel events. :)

The main motivation to do this is the program execution of the
dev.d/ and hotplug.d/ directory. If we don't wait for the parent
event to exit, we can't be sure that the executed scripts are
run in the right order.

On Thu, Dec 09, 2004 at 09:18:28AM +0100, Kay Sievers wrote:
> On Wed, 2004-12-08 at 19:07 -0800, David Brownell wrote:
> > Could that argument apply to the underlying hardware, too?

> We now make sure that the sequence of events for a device
> is serialized for every device chain and the class/block
> devices which have a "device" link to a physical device are
> handled after the physical device is fully populated and
> notified to userspace. It will only work this way on kernels
> later than 2.6.10-rc1 cause it depends on the PHYSDEVPATH
> value in the hotplug environment.

udevd.8
udevd.c
udevd.h

diff --git a/udevd.8 b/udevd.8
index 1a5940fef5c3d06179d23415a31ea29168f0bcd1..b06a2b7af12578071898ac059114cea4e8273fd2 100644 (file)
--- a/udevd.8
+++ b/udevd.8
@@ -28,8 +28,6 @@ running for a single device at the same time.
 .B udevd
 receives the events from
 .B udevsend
-which is called by
-.BR hotplug (8).
 If
 .B udevd
 isn't already running,
diff --git a/udevd.c b/udevd.c
index 58f5be94bc42c43f368e1fe9665e5f34d861ab2b..2e6f5793d3747ea57447e966bf8e91c18e70644d 100644 (file)
--- a/udevd.c
+++ b/udevd.c
@@ -151,22 +151,40 @@ static void udev_run(struct hotplug_msg *msg)
        }
 }
 
-/* returns already running task with devpath */
+/* returns still running task for the same event sequence */
 static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg)
 {
        struct hotplug_msg *loop_msg;
+       int i;
+
        list_for_each_entry(loop_msg, &running_list, list) {
                if (loop_msg->devpath == NULL || msg->devpath == NULL)
                        continue;
 
-               if (strcmp(loop_msg->devpath, msg->devpath) == 0)
-                       return loop_msg;
+               /* is a parent or child device event still running */
+               for (i = 0; i < DEVPATH_SIZE; i++) {
+                       if (loop_msg->devpath[i] == '\0' || msg->devpath[i] == '\0')
+                               return loop_msg;
+
+                       if (loop_msg->devpath[i] != msg->devpath[i])
+                               break;
+               }
+
+               /* is the physical device event still running on an add sequence */
+               if (msg->physdevpath && msg->action && strcmp(msg->action, "add") == 0)
+                       for (i = 0; i < DEVPATH_SIZE; i++) {
+                               if (loop_msg->devpath[i] == '\0' || msg->physdevpath[i] == '\0')
+                                       return loop_msg;
+
+                               if (loop_msg->devpath[i] != msg->physdevpath[i])
+                                       break;
+                       }
        }
 
        return NULL;
 }
 
-/* exec queue management routine executes the events and delays events for the same devpath */
+/* exec queue management routine executes the events and serializes events in the same sequence */
 static void exec_queue_manager(void)
 {
        struct hotplug_msg *loop_msg;
@@ -181,8 +199,8 @@ static void exec_queue_manager(void)
                        udev_run(loop_msg);
                        dbg("moved seq %llu to running list", loop_msg->seqnum);
                } else {
-                       dbg("delay seq %llu, cause seq %llu already working on '%s'",
-                               loop_msg->seqnum, msg->seqnum, msg->devpath);
+                       dbg("delay seq %llu (%s), cause seq %llu (%s) is still running",
+                           loop_msg->seqnum, loop_msg->devpath, msg->seqnum, msg->devpath);
                }
        }
 }
@@ -314,6 +332,9 @@ static void handle_udevsend_msg(int sock)
 
                if (strncmp(key, "SEQNUM=", 7) == 0)
                        msg->seqnum = strtoull(&key[7], NULL, 10);
+
+               if (strncmp(key, "PHYSDEVPATH=", 12) == 0)
+                       msg->physdevpath = &key[12];
        }
        msg->envp[i++] = "MANAGED_EVENT=1";
        msg->envp[i] = NULL;
diff --git a/udevd.h b/udevd.h
index 31f07de8265a693ec3b2c8b0d5af677e67b527f6..1c4b1b88c22d23352f4b57098ae63c4894204890 100644 (file)
--- a/udevd.h
+++ b/udevd.h
@@ -47,6 +47,7 @@ struct hotplug_msg {
        char *devpath;
        char *subsystem;
        unsigned long long seqnum;
+       char *physdevpath;
        char *envp[HOTPLUG_NUM_ENVP+1];
        char envbuf[];
 };