diff options
author | root <root@rshg054.dnsready.net> | 2012-01-19 23:15:04 +0000 |
---|---|---|
committer | root <root@rshg054.dnsready.net> | 2012-01-19 23:15:04 +0000 |
commit | eefecc8813e0c062a2058b33209cb30830f824b6 (patch) | |
tree | f2dd237a65b4a8a3587da4cb6ac211ae6048911f /testing/udev | |
parent | 3e2075427791725d8e6a007feba107d94c017caf (diff) |
Thu Jan 19 23:15:03 UTC 2012
Diffstat (limited to 'testing/udev')
-rw-r--r-- | testing/udev/0001-udevd-kill-hanging-event-processes-after-30-seconds.patch | 162 | ||||
-rw-r--r-- | testing/udev/PKGBUILD | 22 |
2 files changed, 174 insertions, 10 deletions
diff --git a/testing/udev/0001-udevd-kill-hanging-event-processes-after-30-seconds.patch b/testing/udev/0001-udevd-kill-hanging-event-processes-after-30-seconds.patch new file mode 100644 index 000000000..3ff89ae43 --- /dev/null +++ b/testing/udev/0001-udevd-kill-hanging-event-processes-after-30-seconds.patch @@ -0,0 +1,162 @@ +From e64fae5573e566ce4fd9b23c68ac8f3096603314 Mon Sep 17 00:00:00 2001 +From: Kay Sievers <kay.sievers@vrfy.org> +Date: Wed, 18 Jan 2012 05:06:18 +0100 +Subject: [PATCH] udevd: kill hanging event processes after 30 seconds + +Some broken kernel drivers load firmware synchronously in the module init +path and block modprobe until the firmware request is fulfilled. + +The modprobe-generated firmware request is a direct child device of the +device which caused modprobe to run. Child device event are blocked until +the parent device is handled. This dead-locks until the kernel firmware +loading timeout of 60 seconds is reached. + +The hanging modprobe event should now time-out and allow the firmware +event to run before the 60 second kernel timeout. +--- + src/udev-event.c | 2 +- + src/udevd.c | 62 +++++++++++++++++++++++++++++++++++++++++++---------- + 2 files changed, 51 insertions(+), 13 deletions(-) + +diff --git a/src/udev-event.c b/src/udev-event.c +index 9bdc518..f0b9548 100644 +--- a/src/udev-event.c ++++ b/src/udev-event.c +@@ -49,7 +49,7 @@ struct udev_event *udev_event_new(struct udev_device *dev) + udev_list_init(udev, &event->run_list, false); + event->fd_signal = -1; + event->birth_usec = now_usec(); +- event->timeout_usec = 60 * 1000 * 1000; ++ event->timeout_usec = 30 * 1000 * 1000; + dbg(event->udev, "allocated event %p\n", event); + return event; + } +diff --git a/src/udevd.c b/src/udevd.c +index 11ab19a..77a1e79 100644 +--- a/src/udevd.c ++++ b/src/udevd.c +@@ -133,6 +133,7 @@ struct worker { + struct udev_monitor *monitor; + enum worker_state state; + struct event *event; ++ unsigned long long event_start_usec; + }; + + /* passed from worker to main process */ +@@ -372,6 +373,7 @@ out: + close(fd_inotify); + close(worker_watch[WRITE_END]); + udev_rules_unref(rules); ++ udev_builtin_exit(udev); + udev_monitor_unref(worker_monitor); + udev_unref(udev); + udev_log_close(); +@@ -389,6 +391,7 @@ out: + worker->monitor = worker_monitor; + worker->pid = pid; + worker->state = WORKER_RUNNING; ++ worker->event_start_usec = now_usec(); + worker->event = event; + event->state = EVENT_RUNNING; + udev_list_node_append(&worker->node, &worker_list); +@@ -419,6 +422,7 @@ static void event_run(struct event *event) + worker_ref(worker); + worker->event = event; + worker->state = WORKER_RUNNING; ++ worker->event_start_usec = now_usec(); + event->state = EVENT_RUNNING; + return; + } +@@ -610,9 +614,11 @@ static void worker_returned(int fd_worker) + continue; + + /* worker returned */ +- worker->event->exitcode = msg.exitcode; +- event_queue_delete(worker->event, true); +- worker->event = NULL; ++ if (worker->event) { ++ worker->event->exitcode = msg.exitcode; ++ event_queue_delete(worker->event, true); ++ worker->event = NULL; ++ } + if (worker->state != WORKER_KILLED) + worker->state = WORKER_IDLE; + worker_unref(worker); +@@ -796,7 +802,7 @@ static void handle_signal(struct udev *udev, int signo) + } + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { +- if (worker->event != NULL) { ++ if (worker->event) { + err(udev, "worker [%u] failed while handling '%s'\n", + pid, worker->event->devpath); + worker->event->exitcode = -32; +@@ -1574,25 +1580,57 @@ int main(int argc, char *argv[]) + break; + + /* timeout at exit for workers to finish */ +- timeout = 60 * 1000; +- } else if (udev_list_node_is_empty(&event_list) && children > 2) { +- /* set timeout to kill idle workers */ +- timeout = 3 * 1000; +- } else { ++ timeout = 30 * 1000; ++ } else if (udev_list_node_is_empty(&event_list) && children <= 2) { ++ /* we are idle */ + timeout = -1; ++ } else { ++ /* kill idle or hanging workers */ ++ timeout = 3 * 1000; + } + fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), timeout); + if (fdcount < 0) + continue; + + if (fdcount == 0) { ++ struct udev_list_node *loop; ++ ++ /* timeout */ + if (udev_exit) { +- info(udev, "timeout, giving up waiting for workers to finish\n"); ++ err(udev, "timeout, giving up waiting for workers to finish\n"); + break; + } + +- /* timeout - kill idle workers */ +- worker_kill(udev, 2); ++ /* kill idle workers */ ++ if (udev_list_node_is_empty(&event_list)) { ++ info(udev, "cleanup idle workers\n"); ++ worker_kill(udev, 2); ++ } ++ ++ /* check for hanging events */ ++ udev_list_node_foreach(loop, &worker_list) { ++ struct worker *worker = node_to_worker(loop); ++ ++ if (worker->state != WORKER_RUNNING) ++ continue; ++ ++ if ((now_usec() - worker->event_start_usec) > 30 * 1000 * 1000) { ++ err(udev, "worker [%u] timeout, kill it\n", worker->pid, ++ worker->event ? worker->event->devpath : "<idle>"); ++ kill(worker->pid, SIGKILL); ++ worker->state = WORKER_KILLED; ++ /* drop reference taken for state 'running' */ ++ worker_unref(worker); ++ if (worker->event) { ++ err(udev, "seq %llu '%s' killed\n", ++ udev_device_get_seqnum(worker->event->dev), worker->event->devpath); ++ worker->event->exitcode = -64; ++ event_queue_delete(worker->event, true); ++ worker->event = NULL; ++ } ++ } ++ } ++ + } + + is_worker = is_signal = is_inotify = is_netlink = is_ctrl = false; +-- +1.7.8.3 + diff --git a/testing/udev/PKGBUILD b/testing/udev/PKGBUILD index 2db9e58ad..171a03bc5 100644 --- a/testing/udev/PKGBUILD +++ b/testing/udev/PKGBUILD @@ -1,4 +1,4 @@ -# $Id: PKGBUILD 146541 2012-01-12 20:45:08Z tomegun $ +# $Id: PKGBUILD 146792 2012-01-18 11:05:48Z tomegun $ # Maintainer: Tom Gundersen <teg@jklm.no> # Contributor: Aaron Griffin <aaron@archlinux.org> # Contributor: Tobias Powalowski <tpowa@archlinux.org> @@ -7,18 +7,22 @@ pkgbase="udev" pkgname=('udev' 'udev-compat') pkgver=177 -pkgrel=1 +pkgrel=3 arch=(i686 x86_64) -url="http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html" +url="http://git.kernel.org/?p=linux/hotplug/udev.git;a=summary" license=('GPL') groups=('base') options=(!makeflags !libtool) makedepends=('gobject-introspection' 'gperf' 'libxslt' 'usbutils' 'kmod') -source=(ftp://ftp.kernel.org/pub/linux/utils/kernel/hotplug/$pkgbase-$pkgver.tar.xz) +source=(ftp://ftp.kernel.org/pub/linux/utils/kernel/hotplug/$pkgbase-$pkgver.tar.xz + 0001-udevd-kill-hanging-event-processes-after-30-seconds.patch) build() { cd $srcdir/$pkgbase-$pkgver + # deal with broken drivers waiting for firmware to be loaded + patch -p1 -i ../0001-udevd-kill-hanging-event-processes-after-30-seconds.patch + ./configure --prefix=/usr \ --with-rootprefix= \ --sysconfdir=/etc \ @@ -34,12 +38,10 @@ build() { package_udev() { pkgdesc="The userspace dev tools (udev)" - depends=('util-linux' 'libusb-compat' 'glib2' 'kmod' 'pciutils' 'usbutils' 'pciutils' 'glib2') + depends=('util-linux' 'libusb-compat' 'glib2' 'kmod' 'pciutils' 'usbutils' 'pciutils') install=udev.install backup=(etc/udev/udev.conf) - conflicts=('pcmcia-cs' 'hotplug' 'initscripts<2009.07') - replaces=('devfsd') - + cd $srcdir/$pkgbase-$pkgver make DESTDIR=${pkgdir} install @@ -101,5 +103,5 @@ package_udev-compat() { mknod cpu/microcode c 10 184 } - -md5sums=('b4e00faf8153fd7202a7ef609284b0c3') +md5sums=('b4e00faf8153fd7202a7ef609284b0c3' + '3e40dca1c4f8194b4633e3befb4da4d4') |