X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fudev%2Fudevd.c;h=1c9488e457e3f7d4ba551b7086b8b11737571d13;hb=24efb112451413c1013d5f7fe27d7e2cd407647a;hp=f9ee36870bd3727dca1d01702050f76bef1c781b;hpb=9ea28c55a2488e6cd4a44ac5786f12b71ad5bc9f;p=elogind.git diff --git a/src/udev/udevd.c b/src/udev/udevd.c index f9ee36870..1c9488e45 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -265,7 +266,8 @@ static void worker_new(struct event *event) for (;;) { struct udev_event *udev_event; struct worker_message msg; - int err; + int fd_lock = -1; + int err = 0; log_debug("seq %llu running", udev_device_get_seqnum(dev)); udev_event = udev_event_new(dev); @@ -280,25 +282,51 @@ static void worker_new(struct event *event) if (exec_delay > 0) udev_event->exec_delay = exec_delay; + /* + * Take a "read lock" on the device node; this establishes + * a concept of device "ownership" to serialize device + * access. External processes holding a "write lock" will + * cause udev to skip the event handling; in the case udev + * acquired the lock, the external process will block until + * udev has finished its event handling. + */ + if (streq_ptr("block", udev_device_get_subsystem(dev))) { + struct udev_device *d = dev; + + if (streq_ptr("partition", udev_device_get_devtype(d))) + d = udev_device_get_parent(d); + + if (d) { + fd_lock = open(udev_device_get_devnode(d), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); + if (fd_lock >= 0 && flock(fd_lock, LOCK_SH|LOCK_NB) < 0) { + log_debug("Unable to flock(%s), skipping event handling: %m", udev_device_get_devnode(d)); + err = -EWOULDBLOCK; + goto skip; + } + } + } + /* apply rules, create node, symlinks */ - err = udev_event_execute_rules(udev_event, rules, &sigmask_orig); + udev_event_execute_rules(udev_event, rules, &sigmask_orig); - if (err == 0) - udev_event_execute_run(udev_event, &sigmask_orig); + udev_event_execute_run(udev_event, &sigmask_orig); /* apply/restore inotify watch */ - if (err == 0 && udev_event->inotify_watch) { + if (udev_event->inotify_watch) { udev_watch_begin(udev, dev); udev_device_update_db(dev); } + if (fd_lock >= 0) + close(fd_lock); + /* send processed event back to libudev listeners */ udev_monitor_send_device(worker_monitor, NULL, dev); +skip: /* send udevd the result of the event execution */ memzero(&msg, sizeof(struct worker_message)); - if (err != 0) - msg.exitcode = err; + msg.exitcode = err; msg.pid = getpid(); send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0);