1
0
mirror of https://github.com/systemd/systemd.git synced 2024-11-08 11:27:32 +03:00
systemd/udev/udevd.c

1733 lines
44 KiB
C
Raw Normal View History

[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
/*
2011-04-13 03:17:09 +04:00
* Copyright (C) 2004-2011 Kay Sievers <kay.sievers@vrfy.org>
* Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
* Copyright (C) 2009 Canonical Ltd.
* Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
*
2008-09-10 04:40:42 +04:00
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
*
2008-09-10 04:40:42 +04:00
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
*
2008-09-10 04:40:42 +04:00
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
*/
#include <stddef.h>
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
2009-07-13 05:33:15 +04:00
#include <stdbool.h>
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <time.h>
2006-09-08 13:27:03 +04:00
#include <getopt.h>
#include <dirent.h>
2009-07-17 15:24:37 +04:00
#include <sys/time.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/signalfd.h>
2011-04-13 03:17:09 +04:00
#include <sys/epoll.h>
#include <sys/poll.h>
2005-03-10 02:58:01 +03:00
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
2008-07-30 03:45:23 +04:00
#include <sys/inotify.h>
#include <sys/utsname.h>
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
#include "udev.h"
2010-10-07 16:59:11 +04:00
#include "sd-daemon.h"
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
2009-07-13 05:33:15 +04:00
static bool debug;
static void log_fn(struct udev *udev, int priority,
const char *file, int line, const char *fn,
const char *format, va_list args)
{
if (debug) {
2009-07-17 15:24:37 +04:00
char buf[1024];
2011-07-12 00:56:07 +04:00
struct timespec ts;
2009-07-17 15:24:37 +04:00
vsnprintf(buf, sizeof(buf), format, args);
2011-07-12 00:56:07 +04:00
clock_gettime(CLOCK_MONOTONIC, &ts);
2011-07-31 01:16:43 +04:00
fprintf(stderr, "[%llu.%06u] [%u] %s: %s",
2011-07-12 00:56:07 +04:00
(unsigned long long) ts.tv_sec, (unsigned int) ts.tv_nsec/1000,
2009-07-17 15:24:37 +04:00
(int) getpid(), fn, buf);
} else {
vsyslog(priority, format, args);
}
}
2008-10-18 17:02:01 +04:00
static struct udev_rules *rules;
static struct udev_queue_export *udev_queue_export;
2008-09-08 19:59:00 +04:00
static struct udev_ctrl *udev_ctrl;
static struct udev_monitor *monitor;
static int worker_watch[2] = { -1, -1 };
2011-04-13 03:17:09 +04:00
static int fd_signal = -1;
static int fd_ep = -1;
static int fd_inotify = -1;
2009-07-13 05:33:15 +04:00
static bool stop_exec_queue;
static bool reload_config;
2010-05-27 19:27:56 +04:00
static int children;
static int children_max;
static int exec_delay;
2011-04-20 03:53:03 +04:00
static sigset_t sigmask_orig;
2011-04-13 03:17:09 +04:00
static UDEV_LIST(event_list);
static UDEV_LIST(worker_list);
2009-07-13 05:33:15 +04:00
static bool udev_exit;
enum event_state {
EVENT_UNDEF,
EVENT_QUEUED,
EVENT_RUNNING,
};
struct event {
struct udev_list_node node;
struct udev *udev;
struct udev_device *dev;
enum event_state state;
int exitcode;
unsigned long long int delaying_seqnum;
unsigned long long int seqnum;
const char *devpath;
size_t devpath_len;
const char *devpath_old;
dev_t devnum;
bool is_block;
int ifindex;
};
static struct event *node_to_event(struct udev_list_node *node)
2008-10-17 20:59:27 +04:00
{
char *event;
event = (char *)node;
event -= offsetof(struct event, node);
return (struct event *)event;
}
2011-04-13 03:17:09 +04:00
static void event_queue_cleanup(struct udev *udev, enum event_state type);
enum worker_state {
WORKER_UNDEF,
WORKER_RUNNING,
WORKER_IDLE,
WORKER_KILLED,
};
struct worker {
struct udev_list_node node;
struct udev *udev;
int refcount;
pid_t pid;
struct udev_monitor *monitor;
enum worker_state state;
struct event *event;
};
/* passed from worker to main process */
struct worker_message {
pid_t pid;
int exitcode;
};
static struct worker *node_to_worker(struct udev_list_node *node)
{
char *worker;
worker = (char *)node;
worker -= offsetof(struct worker, node);
return (struct worker *)worker;
2008-10-17 20:59:27 +04:00
}
2011-04-13 03:17:09 +04:00
static void event_queue_delete(struct event *event, bool export)
{
2008-10-17 20:59:27 +04:00
udev_list_node_remove(&event->node);
2011-04-13 03:17:09 +04:00
if (export) {
udev_queue_export_device_finished(udev_queue_export, event->dev);
2011-04-13 03:17:09 +04:00
info(event->udev, "seq %llu done with %i\n", udev_device_get_seqnum(event->dev), event->exitcode);
}
2008-10-16 19:16:58 +04:00
udev_device_unref(event->dev);
free(event);
2008-10-16 19:16:58 +04:00
}
static struct worker *worker_ref(struct worker *worker)
{
worker->refcount++;
return worker;
}
2011-04-13 03:17:09 +04:00
static void worker_cleanup(struct worker *worker)
{
udev_list_node_remove(&worker->node);
udev_monitor_unref(worker->monitor);
children--;
free(worker);
}
static void worker_unref(struct worker *worker)
{
worker->refcount--;
if (worker->refcount > 0)
return;
info(worker->udev, "worker [%u] cleaned up\n", worker->pid);
2011-04-13 03:17:09 +04:00
worker_cleanup(worker);
}
static void worker_list_cleanup(struct udev *udev)
{
struct udev_list_node *loop, *tmp;
udev_list_node_foreach_safe(loop, tmp, &worker_list) {
struct worker *worker = node_to_worker(loop);
worker_cleanup(worker);
}
}
static void worker_new(struct event *event)
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
{
2011-04-13 03:17:09 +04:00
struct udev *udev = event->udev;
struct worker *worker;
struct udev_monitor *worker_monitor;
pid_t pid;
/* listen for new events */
2011-04-13 03:17:09 +04:00
worker_monitor = udev_monitor_new_from_netlink(udev, NULL);
if (worker_monitor == NULL)
return;
/* allow the main daemon netlink address to send devices to the worker */
udev_monitor_allow_unicast_sender(worker_monitor, monitor);
udev_monitor_enable_receiving(worker_monitor);
worker = calloc(1, sizeof(struct worker));
if (worker == NULL) {
udev_monitor_unref(worker_monitor);
return;
}
/* worker + event reference */
worker->refcount = 2;
2011-04-13 03:17:09 +04:00
worker->udev = udev;
pid = fork();
switch (pid) {
case 0: {
2011-04-18 04:14:24 +04:00
struct udev_device *dev = NULL;
int fd_monitor;
struct epoll_event ep_signal, ep_monitor;
sigset_t mask;
int rc = EXIT_SUCCESS;
2011-04-13 03:17:09 +04:00
/* move initial device from queue */
dev = event->dev;
event->dev = NULL;
free(worker);
worker_list_cleanup(udev);
event_queue_cleanup(udev, EVENT_UNDEF);
udev_queue_export_unref(udev_queue_export);
udev_monitor_unref(monitor);
2008-09-08 19:59:00 +04:00
udev_ctrl_unref(udev_ctrl);
2011-04-13 03:17:09 +04:00
close(fd_signal);
close(fd_ep);
close(worker_watch[READ_END]);
2006-07-25 16:45:09 +04:00
2011-04-18 04:14:24 +04:00
sigfillset(&mask);
fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (fd_signal < 0) {
err(udev, "error creating signalfd %m\n");
rc = 2;
goto out;
}
fd_ep = epoll_create1(EPOLL_CLOEXEC);
if (fd_ep < 0) {
err(udev, "error creating epoll fd: %m\n");
rc = 3;
goto out;
}
memset(&ep_signal, 0, sizeof(struct epoll_event));
ep_signal.events = EPOLLIN;
ep_signal.data.fd = fd_signal;
fd_monitor = udev_monitor_get_fd(worker_monitor);
memset(&ep_monitor, 0, sizeof(struct epoll_event));
ep_monitor.events = EPOLLIN;
ep_monitor.data.fd = fd_monitor;
if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) {
err(udev, "fail to add fds to epoll: %m\n");
rc = 4;
goto out;
}
2008-10-16 19:16:58 +04:00
/* request TERM signal if parent exits */
prctl(PR_SET_PDEATHSIG, SIGTERM);
2008-10-16 19:16:58 +04:00
2011-04-18 04:14:24 +04:00
for (;;) {
struct udev_event *udev_event;
2011-04-20 03:53:03 +04:00
struct worker_message msg;
int err;
2008-10-16 19:16:58 +04:00
2011-04-13 03:17:09 +04:00
info(udev, "seq %llu running\n", udev_device_get_seqnum(dev));
udev_event = udev_event_new(dev);
2011-04-18 04:14:24 +04:00
if (udev_event == NULL) {
rc = 5;
goto out;
}
2011-04-20 03:53:03 +04:00
/* needed for SIGCHLD/SIGTERM in spawn() */
udev_event->fd_signal = fd_signal;
if (exec_delay > 0)
udev_event->exec_delay = exec_delay;
/* apply rules, create node, symlinks */
2011-04-20 03:53:03 +04:00
err = udev_event_execute_rules(udev_event, rules, &sigmask_orig);
if (err == 0)
udev_event_execute_run(udev_event, &sigmask_orig);
/* apply/restore inotify watch */
if (err == 0 && udev_event->inotify_watch) {
2011-04-13 03:17:09 +04:00
udev_watch_begin(udev, dev);
udev_device_update_db(dev);
}
/* send processed event back to libudev listeners */
udev_monitor_send_device(worker_monitor, NULL, dev);
/* send udevd the result of the event execution */
2011-04-20 03:53:03 +04:00
memset(&msg, 0, sizeof(struct worker_message));
if (err != 0)
msg.exitcode = err;
msg.pid = getpid();
send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0);
2011-04-13 03:17:09 +04:00
info(udev, "seq %llu processed with %i\n", udev_device_get_seqnum(dev), err);
2011-04-20 03:53:03 +04:00
udev_device_unref(dev);
dev = NULL;
2011-04-20 03:53:03 +04:00
if (udev_event->sigterm) {
udev_event_unref(udev_event);
goto out;
}
udev_event_unref(udev_event);
2011-04-18 04:14:24 +04:00
/* wait for more device messages from main udevd, or term signal */
while (dev == NULL) {
struct epoll_event ev[4];
int fdcount;
2011-04-18 04:14:24 +04:00
int i;
2011-04-18 04:14:24 +04:00
fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1);
2011-04-20 03:53:03 +04:00
if (fdcount < 0) {
if (errno == EINTR)
continue;
err = -errno;
err(udev, "failed to poll: %m\n");
goto out;
}
2011-04-18 04:14:24 +04:00
for (i = 0; i < fdcount; i++) {
if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) {
dev = udev_monitor_receive_device(worker_monitor);
break;
2011-04-18 04:14:24 +04:00
} else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) {
struct signalfd_siginfo fdsi;
ssize_t size;
size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
if (size != sizeof(struct signalfd_siginfo))
continue;
switch (fdsi.ssi_signo) {
case SIGTERM:
goto out;
}
}
}
}
2011-04-18 04:14:24 +04:00
}
out:
udev_device_unref(dev);
if (fd_signal >= 0)
close(fd_signal);
if (fd_ep >= 0)
close(fd_ep);
2011-04-13 03:17:09 +04:00
close(fd_inotify);
close(worker_watch[WRITE_END]);
udev_rules_unref(rules);
udev_monitor_unref(worker_monitor);
2011-04-13 03:17:09 +04:00
udev_unref(udev);
2009-06-10 00:47:48 +04:00
udev_log_close();
2011-04-18 04:14:24 +04:00
exit(rc);
}
case -1:
udev_monitor_unref(worker_monitor);
event->state = EVENT_QUEUED;
free(worker);
2011-04-13 03:17:09 +04:00
err(udev, "fork of child failed: %m\n");
break;
default:
/* close monitor, but keep address around */
udev_monitor_disconnect(worker_monitor);
worker->monitor = worker_monitor;
worker->pid = pid;
worker->state = WORKER_RUNNING;
worker->event = event;
event->state = EVENT_RUNNING;
udev_list_node_append(&worker->node, &worker_list);
2010-05-27 19:27:56 +04:00
children++;
2011-04-13 03:17:09 +04:00
info(udev, "seq %llu forked new worker [%u]\n", udev_device_get_seqnum(event->dev), pid);
break;
}
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
}
static void event_run(struct event *event, bool force)
{
struct udev_list_node *loop;
udev_list_node_foreach(loop, &worker_list) {
struct worker *worker = node_to_worker(loop);
ssize_t count;
if (worker->state != WORKER_IDLE)
continue;
count = udev_monitor_send_device(monitor, worker->monitor, event->dev);
if (count < 0) {
err(event->udev, "worker [%u] did not accept message %zi (%m), kill it\n", worker->pid, count);
kill(worker->pid, SIGKILL);
worker->state = WORKER_KILLED;
continue;
}
worker_ref(worker);
worker->event = event;
worker->state = WORKER_RUNNING;
event->state = EVENT_RUNNING;
return;
}
2010-05-27 19:27:56 +04:00
if (!force && children >= children_max) {
if (children_max > 1)
info(event->udev, "maximum number (%i) of children reached\n", children);
return;
}
/* start new worker and pass initial device */
worker_new(event);
}
static int event_queue_insert(struct udev_device *dev)
{
struct event *event;
event = calloc(1, sizeof(struct event));
if (event == NULL)
return -1;
event->udev = udev_device_get_udev(dev);
event->dev = dev;
event->seqnum = udev_device_get_seqnum(dev);
event->devpath = udev_device_get_devpath(dev);
event->devpath_len = strlen(event->devpath);
event->devpath_old = udev_device_get_devpath_old(dev);
event->devnum = udev_device_get_devnum(dev);
event->is_block = (strcmp("block", udev_device_get_subsystem(dev)) == 0);
event->ifindex = udev_device_get_ifindex(dev);
udev_queue_export_device_queued(udev_queue_export, dev);
info(event->udev, "seq %llu queued, '%s' '%s'\n", udev_device_get_seqnum(dev),
udev_device_get_action(dev), udev_device_get_subsystem(dev));
event->state = EVENT_QUEUED;
udev_list_node_append(&event->node, &event_list);
2006-09-08 13:30:00 +04:00
/* run all events with a timeout set immediately */
if (udev_device_get_timeout(dev) > 0) {
event_run(event, true);
return 0;
}
return 0;
}
static void worker_kill(struct udev *udev, int retain)
{
struct udev_list_node *loop;
int max;
2010-05-27 19:27:56 +04:00
if (children <= retain)
return;
2010-05-27 19:27:56 +04:00
max = children - retain;
udev_list_node_foreach(loop, &worker_list) {
struct worker *worker = node_to_worker(loop);
if (max-- <= 0)
break;
if (worker->state == WORKER_KILLED)
continue;
worker->state = WORKER_KILLED;
kill(worker->pid, SIGTERM);
}
}
/* lookup event for identical, parent, child device */
static bool is_devpath_busy(struct event *event)
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
{
2008-10-17 20:59:27 +04:00
struct udev_list_node *loop;
size_t common;
/* check if queue contains events we depend on */
udev_list_node_foreach(loop, &event_list) {
struct event *loop_event = node_to_event(loop);
2008-10-17 20:59:27 +04:00
/* we already found a later event, earlier can not block us, no need to check again */
if (loop_event->seqnum < event->delaying_seqnum)
continue;
/* event we checked earlier still exists, no need to check again */
if (loop_event->seqnum == event->delaying_seqnum)
return true;
/* found ourself, no later event can block us */
if (loop_event->seqnum >= event->seqnum)
break;
/* check major/minor */
if (major(event->devnum) != 0 && event->devnum == loop_event->devnum && event->is_block == loop_event->is_block)
return true;
/* check network device ifindex */
if (event->ifindex != 0 && event->ifindex == loop_event->ifindex)
return true;
/* check our old name */
if (event->devpath_old != NULL && strcmp(loop_event->devpath, event->devpath_old) == 0) {
event->delaying_seqnum = loop_event->seqnum;
return true;
}
/* compare devpath */
common = MIN(loop_event->devpath_len, event->devpath_len);
/* one devpath is contained in the other? */
if (memcmp(loop_event->devpath, event->devpath, common) != 0)
continue;
/* identical device event found */
if (loop_event->devpath_len == event->devpath_len) {
/* devices names might have changed/swapped in the meantime */
if (major(event->devnum) != 0 && (event->devnum != loop_event->devnum || event->is_block != loop_event->is_block))
continue;
if (event->ifindex != 0 && event->ifindex != loop_event->ifindex)
continue;
event->delaying_seqnum = loop_event->seqnum;
return true;
}
/* parent device event found */
if (event->devpath[common] == '/') {
event->delaying_seqnum = loop_event->seqnum;
return true;
}
/* child device event found */
if (loop_event->devpath[common] == '/') {
event->delaying_seqnum = loop_event->seqnum;
return true;
}
/* no matching device */
continue;
}
return false;
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
}
2011-04-13 03:17:09 +04:00
static void event_queue_start(struct udev *udev)
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
{
2008-10-17 20:59:27 +04:00
struct udev_list_node *loop;
udev_list_node_foreach(loop, &event_list) {
struct event *event = node_to_event(loop);
if (event->state != EVENT_QUEUED)
continue;
/* do not start event if parent or child event is still running */
if (is_devpath_busy(event)) {
dbg(udev, "delay seq %llu (%s)\n", event->seqnum, event->devpath);
continue;
}
event_run(event, false);
}
}
2011-04-13 03:17:09 +04:00
static void event_queue_cleanup(struct udev *udev, enum event_state match_type)
{
struct udev_list_node *loop, *tmp;
udev_list_node_foreach_safe(loop, tmp, &event_list) {
struct event *event = node_to_event(loop);
if (match_type != EVENT_UNDEF && match_type != event->state)
continue;
event_queue_delete(event, false);
}
}
static void worker_returned(int fd_worker)
{
2010-05-27 17:11:00 +04:00
for (;;) {
struct worker_message msg;
ssize_t size;
struct udev_list_node *loop;
2011-04-13 03:17:09 +04:00
size = recv(fd_worker, &msg, sizeof(struct worker_message), MSG_DONTWAIT);
if (size != sizeof(struct worker_message))
break;
/* lookup worker who sent the signal */
udev_list_node_foreach(loop, &worker_list) {
struct worker *worker = node_to_worker(loop);
if (worker->pid != msg.pid)
continue;
/* worker returned */
worker->event->exitcode = msg.exitcode;
2011-04-13 03:17:09 +04:00
event_queue_delete(worker->event, true);
worker->event = NULL;
if (worker->state != WORKER_KILLED)
worker->state = WORKER_IDLE;
worker_unref(worker);
break;
}
}
}
/* receive the udevd message from userspace */
2011-04-13 03:17:09 +04:00
static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl)
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
{
2008-09-08 19:59:00 +04:00
struct udev *udev = udev_ctrl_get_udev(uctrl);
2011-04-13 03:17:09 +04:00
struct udev_ctrl_connection *ctrl_conn;
struct udev_ctrl_msg *ctrl_msg = NULL;
2008-09-08 19:59:00 +04:00
const char *str;
int i;
2011-04-13 03:17:09 +04:00
ctrl_conn = udev_ctrl_get_connection(uctrl);
if (ctrl_conn == NULL)
goto out;
ctrl_msg = udev_ctrl_receive_msg(ctrl_conn);
2008-09-08 19:59:00 +04:00
if (ctrl_msg == NULL)
2011-04-13 03:17:09 +04:00
goto out;
2008-09-08 19:59:00 +04:00
i = udev_ctrl_get_set_log_level(ctrl_msg);
if (i >= 0) {
info(udev, "udevd message (SET_LOG_PRIORITY) received, log_priority=%i\n", i);
udev_set_log_priority(udev, i);
worker_kill(udev, 0);
}
2008-09-08 19:59:00 +04:00
if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
info(udev, "udevd message (STOP_EXEC_QUEUE) received\n");
2009-07-13 05:33:15 +04:00
stop_exec_queue = true;
2008-09-08 19:59:00 +04:00
}
if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
info(udev, "udevd message (START_EXEC_QUEUE) received\n");
2009-07-13 05:33:15 +04:00
stop_exec_queue = false;
2008-09-08 19:59:00 +04:00
}
if (udev_ctrl_get_reload_rules(ctrl_msg) > 0) {
info(udev, "udevd message (RELOAD_RULES) received\n");
2009-07-13 05:33:15 +04:00
reload_config = true;
}
2008-09-08 19:59:00 +04:00
str = udev_ctrl_get_set_env(ctrl_msg);
if (str != NULL) {
2008-10-16 19:16:58 +04:00
char *key;
key = strdup(str);
if (key != NULL) {
char *val;
val = strchr(key, '=');
if (val != NULL) {
val[0] = '\0';
val = &val[1];
if (val[0] == '\0') {
info(udev, "udevd message (ENV) received, unset '%s'\n", key);
udev_add_property(udev, key, NULL);
} else {
info(udev, "udevd message (ENV) received, set '%s=%s'\n", key, val);
udev_add_property(udev, key, val);
}
2008-09-08 19:59:00 +04:00
} else {
2008-10-16 19:16:58 +04:00
err(udev, "wrong key format '%s'\n", key);
2008-09-08 19:59:00 +04:00
}
2008-10-16 19:16:58 +04:00
free(key);
2008-09-08 19:59:00 +04:00
}
worker_kill(udev, 0);
2008-09-08 19:59:00 +04:00
}
2010-05-27 19:27:56 +04:00
i = udev_ctrl_get_set_children_max(ctrl_msg);
2008-09-08 19:59:00 +04:00
if (i >= 0) {
2010-05-27 19:27:56 +04:00
info(udev, "udevd message (SET_MAX_CHILDREN) received, children_max=%i\n", i);
children_max = i;
2008-09-08 19:59:00 +04:00
}
2011-04-13 03:17:09 +04:00
if (udev_ctrl_get_ping(ctrl_msg) > 0)
info(udev, "udevd message (SYNC) received\n");
if (udev_ctrl_get_exit(ctrl_msg) > 0) {
info(udev, "udevd message (EXIT) received\n");
udev_exit = true;
/* keep reference to block the client until we exit */
udev_ctrl_connection_ref(ctrl_conn);
}
2011-04-13 03:17:09 +04:00
out:
2008-09-08 19:59:00 +04:00
udev_ctrl_msg_unref(ctrl_msg);
2011-04-13 03:17:09 +04:00
return udev_ctrl_connection_unref(ctrl_conn);
}
/* read inotify messages */
static int handle_inotify(struct udev *udev)
{
int nbytes, pos;
char *buf;
struct inotify_event *ev;
2011-04-13 03:17:09 +04:00
if ((ioctl(fd_inotify, FIONREAD, &nbytes) < 0) || (nbytes <= 0))
return 0;
buf = malloc(nbytes);
if (buf == NULL) {
err(udev, "error getting buffer for inotify\n");
return -1;
}
2011-04-13 03:17:09 +04:00
nbytes = read(fd_inotify, buf, nbytes);
for (pos = 0; pos < nbytes; pos += sizeof(struct inotify_event) + ev->len) {
struct udev_device *dev;
ev = (struct inotify_event *)(buf + pos);
if (ev->len) {
const char *s;
info(udev, "inotify event: %x for %s\n", ev->mask, ev->name);
s = strstr(ev->name, ".rules");
if (s == NULL)
continue;
if (strlen(s) != strlen(".rules"))
continue;
2009-07-13 05:33:15 +04:00
reload_config = true;
continue;
}
dev = udev_watch_lookup(udev, ev->wd);
if (dev != NULL) {
info(udev, "inotify event: %x for %s\n", ev->mask, udev_device_get_devnode(dev));
if (ev->mask & IN_CLOSE_WRITE) {
char filename[UTIL_PATH_SIZE];
int fd;
info(udev, "device %s closed, synthesising 'change'\n", udev_device_get_devnode(dev));
2009-05-20 19:57:52 +04:00
util_strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
fd = open(filename, O_WRONLY);
2011-04-13 03:47:56 +04:00
if (fd >= 0) {
if (write(fd, "change", 6) < 0)
info(udev, "error writing uevent: %m\n");
close(fd);
}
}
if (ev->mask & IN_IGNORED)
udev_watch_end(udev, dev);
udev_device_unref(dev);
}
}
free(buf);
2009-02-11 23:56:35 +03:00
return 0;
}
static void handle_signal(struct udev *udev, int signo)
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
{
switch (signo) {
case SIGINT:
case SIGTERM:
2009-07-13 05:33:15 +04:00
udev_exit = true;
break;
case SIGCHLD:
2010-05-27 17:11:00 +04:00
for (;;) {
pid_t pid;
int status;
struct udev_list_node *loop, *tmp;
pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0)
break;
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
udev_list_node_foreach_safe(loop, tmp, &worker_list) {
struct worker *worker = node_to_worker(loop);
2008-10-17 20:59:27 +04:00
if (worker->pid != pid)
continue;
info(udev, "worker [%u] exit\n", pid);
2011-04-21 12:06:12 +04:00
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0)
err(udev, "worker [%u] exit with return code %i\n", pid, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
err(udev, "worker [%u] terminated by signal %i (%s)\n",
pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
} else if (WIFSTOPPED(status)) {
err(udev, "worker [%u] stopped\n", pid);
} else if (WIFCONTINUED(status)) {
err(udev, "worker [%u] continued\n", pid);
} else {
err(udev, "worker [%u] exit with status 0x%04x\n", pid, status);
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
if (worker->event != NULL) {
err(udev, "worker [%u] failed while handling '%s'\n",
pid, worker->event->devpath);
worker->event->exitcode = -32;
2011-04-13 03:17:09 +04:00
event_queue_delete(worker->event, true);
/* drop reference taken for state 'running' */
worker_unref(worker);
}
}
worker_unref(worker);
break;
}
}
break;
case SIGHUP:
2009-07-13 05:33:15 +04:00
reload_config = true;
break;
}
}
static void static_dev_create_from_modules(struct udev *udev)
{
struct utsname kernel;
char modules[UTIL_PATH_SIZE];
char buf[4096];
FILE *f;
uname(&kernel);
util_strscpyl(modules, sizeof(modules), "/lib/modules/", kernel.release, "/modules.devname", NULL);
f = fopen(modules, "r");
if (f == NULL)
return;
while (fgets(buf, sizeof(buf), f) != NULL) {
char *s;
const char *modname;
const char *devname;
const char *devno;
int maj, min;
char type;
mode_t mode;
char filename[UTIL_PATH_SIZE];
if (buf[0] == '#')
continue;
modname = buf;
s = strchr(modname, ' ');
if (s == NULL)
continue;
s[0] = '\0';
devname = &s[1];
s = strchr(devname, ' ');
if (s == NULL)
continue;
s[0] = '\0';
devno = &s[1];
s = strchr(devno, ' ');
if (s == NULL)
s = strchr(devno, '\n');
if (s != NULL)
s[0] = '\0';
if (sscanf(devno, "%c%u:%u", &type, &maj, &min) != 3)
continue;
/* set sticky bit, so we do not remove the node on module unload */
if (type == 'c')
mode = 01600|S_IFCHR;
else if (type == 'b')
mode = 01600|S_IFBLK;
else
continue;
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/", devname, NULL);
util_create_path_selinux(udev, filename);
udev_selinux_setfscreatecon(udev, filename, mode);
info(udev, "mknod '%s' %c%u:%u\n", filename, type, maj, min);
if (mknod(filename, mode, makedev(maj, min)) < 0 && errno == EEXIST)
utimensat(AT_FDCWD, filename, NULL, 0);
udev_selinux_resetfscreatecon(udev);
}
fclose(f);
}
static int copy_dev_dir(struct udev *udev, DIR *dir_from, DIR *dir_to, int maxdepth)
{
struct dirent *dent;
for (dent = readdir(dir_from); dent != NULL; dent = readdir(dir_from)) {
struct stat stats;
if (dent->d_name[0] == '.')
continue;
if (fstatat(dirfd(dir_from), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
continue;
if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, stats.st_mode & 0777);
if (mknodat(dirfd(dir_to), dent->d_name, stats.st_mode, stats.st_rdev) == 0) {
fchmodat(dirfd(dir_to), dent->d_name, stats.st_mode & 0777, 0);
fchownat(dirfd(dir_to), dent->d_name, stats.st_uid, stats.st_gid, 0);
} else {
utimensat(dirfd(dir_to), dent->d_name, NULL, 0);
}
udev_selinux_resetfscreatecon(udev);
} else if (S_ISLNK(stats.st_mode)) {
char target[UTIL_PATH_SIZE];
ssize_t len;
len = readlinkat(dirfd(dir_from), dent->d_name, target, sizeof(target));
if (len <= 0 || len == (ssize_t)sizeof(target))
continue;
target[len] = '\0';
udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFLNK);
if (symlinkat(target, dirfd(dir_to), dent->d_name) < 0 && errno == EEXIST)
utimensat(dirfd(dir_to), dent->d_name, NULL, AT_SYMLINK_NOFOLLOW);
udev_selinux_resetfscreatecon(udev);
} else if (S_ISDIR(stats.st_mode)) {
DIR *dir2_from, *dir2_to;
if (maxdepth == 0)
continue;
udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFDIR|0755);
mkdirat(dirfd(dir_to), dent->d_name, 0755);
udev_selinux_resetfscreatecon(udev);
dir2_to = fdopendir(openat(dirfd(dir_to), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
if (dir2_to == NULL)
continue;
dir2_from = fdopendir(openat(dirfd(dir_from), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
if (dir2_from == NULL) {
closedir(dir2_to);
continue;
}
copy_dev_dir(udev, dir2_from, dir2_to, maxdepth-1);
closedir(dir2_to);
closedir(dir2_from);
}
}
return 0;
}
static void static_dev_create_links(struct udev *udev, DIR *dir)
{
struct stdlinks {
const char *link;
const char *target;
};
static const struct stdlinks stdlinks[] = {
{ "core", "/proc/kcore" },
{ "fd", "/proc/self/fd" },
{ "stdin", "/proc/self/fd/0" },
{ "stdout", "/proc/self/fd/1" },
{ "stderr", "/proc/self/fd/2" },
};
unsigned int i;
for (i = 0; i < ARRAY_SIZE(stdlinks); i++) {
struct stat sb;
if (stat(stdlinks[i].target, &sb) == 0) {
udev_selinux_setfscreateconat(udev, dirfd(dir), stdlinks[i].link, S_IFLNK);
if (symlinkat(stdlinks[i].target, dirfd(dir), stdlinks[i].link) < 0 && errno == EEXIST)
utimensat(dirfd(dir), stdlinks[i].link, NULL, AT_SYMLINK_NOFOLLOW);
udev_selinux_resetfscreatecon(udev);
}
}
}
static void static_dev_create_from_devices(struct udev *udev, DIR *dir)
{
DIR *dir_from;
dir_from = opendir(LIBEXECDIR "/devices");
if (dir_from == NULL)
return;
copy_dev_dir(udev, dir_from, dir, 8);
closedir(dir_from);
}
static void static_dev_create(struct udev *udev)
{
DIR *dir;
dir = opendir(udev_get_dev_path(udev));
if (dir == NULL)
return;
static_dev_create_links(udev, dir);
static_dev_create_from_devices(udev, dir);
closedir(dir);
}
static int mem_size_mb(void)
{
FILE *f;
char buf[4096];
long int memsize = -1;
f = fopen("/proc/meminfo", "r");
if (f == NULL)
return -1;
while (fgets(buf, sizeof(buf), f) != NULL) {
long int value;
if (sscanf(buf, "MemTotal: %ld kB", &value) == 1) {
memsize = value / 1024;
break;
}
}
fclose(f);
return memsize;
}
static int convert_db(struct udev *udev)
{
char filename[UTIL_PATH_SIZE];
FILE *f;
struct udev_enumerate *udev_enumerate;
struct udev_list_entry *list_entry;
/* current database */
util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
if (access(filename, F_OK) >= 0)
return 0;
/* make sure we do not get here again */
util_create_path(udev, filename);
mkdir(filename, 0755);
/* old database */
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db", NULL);
if (access(filename, F_OK) < 0)
return 0;
f = fopen("/dev/kmsg", "w");
if (f != NULL) {
2011-04-20 19:39:44 +04:00
fprintf(f, "<30>udevd[%u]: converting old udev database\n", getpid());
fclose(f);
}
udev_enumerate = udev_enumerate_new(udev);
if (udev_enumerate == NULL)
return -1;
udev_enumerate_scan_devices(udev_enumerate);
udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
struct udev_device *device;
device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
if (device == NULL)
continue;
/* try to find the old database for devices without a current one */
if (udev_device_read_db(device, NULL) < 0) {
bool have_db;
const char *id;
struct stat stats;
char devpath[UTIL_PATH_SIZE];
char from[UTIL_PATH_SIZE];
have_db = false;
/* find database in old location */
id = udev_device_get_id_filename(device);
util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
if (lstat(from, &stats) == 0) {
if (!have_db) {
udev_device_read_db(device, from);
have_db = true;
}
unlink(from);
}
/* find old database with $subsys:$sysname name */
util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
"/.udev/db/", udev_device_get_subsystem(device), ":",
udev_device_get_sysname(device), NULL);
if (lstat(from, &stats) == 0) {
if (!have_db) {
udev_device_read_db(device, from);
have_db = true;
}
unlink(from);
}
/* find old database with the encoded devpath name */
util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath));
util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", devpath, NULL);
if (lstat(from, &stats) == 0) {
if (!have_db) {
udev_device_read_db(device, from);
have_db = true;
}
unlink(from);
}
/* write out new database */
if (have_db)
udev_device_update_db(device);
}
udev_device_unref(device);
}
udev_enumerate_unref(udev_enumerate);
return 0;
}
2011-04-15 01:46:44 +04:00
static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink)
{
int ctrl = -1, netlink = -1;
int fd, n;
n = sd_listen_fds(true);
if (n <= 0)
return -1;
for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) {
if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) {
if (ctrl >= 0)
return -1;
ctrl = fd;
continue;
}
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) {
if (netlink >= 0)
return -1;
netlink = fd;
continue;
}
return -1;
}
if (ctrl < 0 || netlink < 0)
return -1;
info(udev, "ctrl=%i netlink=%i\n", ctrl, netlink);
*rctrl = ctrl;
*rnetlink = netlink;
return 0;
}
int main(int argc, char *argv[])
{
struct udev *udev;
FILE *f;
sigset_t mask;
2009-07-13 05:33:15 +04:00
int daemonize = false;
int resolve_names = 1;
2006-09-08 13:27:03 +04:00
static const struct option options[] = {
{ "daemon", no_argument, NULL, 'd' },
{ "debug", no_argument, NULL, 'D' },
{ "children-max", required_argument, NULL, 'c' },
{ "exec-delay", required_argument, NULL, 'e' },
{ "resolve-names", required_argument, NULL, 'N' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
2006-09-08 13:27:03 +04:00
{}
};
2011-04-13 03:17:09 +04:00
int fd_ctrl = -1;
int fd_netlink = -1;
int fd_worker = -1;
struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_worker;
struct udev_ctrl_connection *ctrl_conn = NULL;
int rc = 1;
[PATCH] udevd - cleanup and better timeout handling On Thu, Jan 29, 2004 at 04:55:11PM +0100, Kay Sievers wrote: > On Thu, Jan 29, 2004 at 02:56:25AM +0100, Kay Sievers wrote: > > On Wed, Jan 28, 2004 at 10:47:36PM +0100, Kay Sievers wrote: > > > Oh, couldn't resist to try threads. > > > It's a multithreaded udevd that communicates through a localhost socket. > > > The message includes a magic with the udev version, so we don't accept > > > older udevsend's. > > > > > > No need for locking, cause we can't bind two sockets on the same address. > > > The daemon tries to connect and if it fails it starts the daemon. > > > > > > We create a thread for every incoming connection, handle over the socket, > > > sort the messages in the global message queue and exit the thread. > > > Huh, that was easy with threads :) > > > > > > With the addition of a message we wakeup the queue manager thread and > > > handle timeouts or move the message to the global exec list. This wakes > > > up the exec list manager who looks if a process is already running for this > > > device path. > > > If yes, the exec is delayed otherwise we create a thread that execs udev. > > > n the background. With the return of udev we free the message and wakeup > > > the exec list manager to look if something is pending. > > > > > > It is just a quick shot, cause I couldn't solve the problems with fork an > > > scheduling and I wanted to see if I'm to stupid :) > > > But if anybody with a better idea or more experience with I/O scheduling > > > we may go another way. The remaining problem is that klibc doesn't support > > > threads. > > > > > > By now, we don't exec anything, it's just a sleep 3 for every exec, > > > but you can see the queue management by watching syslog and do: > > > > > > DEVPATH=/abc ACTION=add SEQNUM=0 ./udevsend /abc > > Next version, switched to unix domain sockets. Next cleaned up version. Hey, nobody wants to try it :) Works for me, It's funny if I connect/disconnect my 4in1-usb-flash-reader every two seconds. The 2.6 usb rocks! I can connect/diconnect a hub with 3 devices plugged in every second and don't run into any problem but a _very_ big udevd queue.
2004-02-01 20:12:36 +03:00
udev = udev_new();
if (udev == NULL)
goto exit;
2009-06-10 00:47:48 +04:00
udev_log_init("udevd");
udev_set_log_fn(udev, log_fn);
2008-10-16 19:16:58 +04:00
info(udev, "version %s\n", VERSION);
udev_selinux_init(udev);
/* make sure, that our runtime dir exists and is writable */
if (utimensat(AT_FDCWD, udev_get_run_config_path(udev), NULL, 0) < 0) {
/* try to create our own subdirectory, do not create parent directories */
mkdir(udev_get_run_config_path(udev), 0755);
if (utimensat(AT_FDCWD, udev_get_run_config_path(udev), NULL, 0) >= 0) {
/* directory seems writable now */
udev_set_run_path(udev, udev_get_run_config_path(udev));
} else {
/* fall back to /dev/.udev */
char filename[UTIL_PATH_SIZE];
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev", NULL);
if (udev_set_run_path(udev, filename) == NULL)
goto exit;
mkdir(udev_get_run_path(udev), 0755);
err(udev, "error: runtime directory '%s' not writable, for now falling back to '%s'",
udev_get_run_config_path(udev), udev_get_run_path(udev));
}
}
/* relabel runtime dir only if it resides below /dev */
if (strncmp(udev_get_run_path(udev), udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) == 0)
udev_selinux_lsetfilecon(udev, udev_get_run_path(udev), 0755);
info(udev, "runtime dir '%s'\n", udev_get_run_path(udev));
2010-05-27 17:11:00 +04:00
for (;;) {
int option;
option = getopt_long(argc, argv, "c:deDtN:hV", options, NULL);
2006-09-08 13:27:03 +04:00
if (option == -1)
break;
switch (option) {
case 'd':
2009-07-13 05:33:15 +04:00
daemonize = true;
2006-09-08 13:27:03 +04:00
break;
case 'c':
children_max = strtoul(optarg, NULL, 0);
break;
case 'e':
exec_delay = strtoul(optarg, NULL, 0);
2006-09-08 13:30:00 +04:00
break;
case 'D':
2009-07-13 05:33:15 +04:00
debug = true;
if (udev_get_log_priority(udev) < LOG_INFO)
udev_set_log_priority(udev, LOG_INFO);
break;
case 'N':
if (strcmp (optarg, "early") == 0) {
resolve_names = 1;
} else if (strcmp (optarg, "late") == 0) {
resolve_names = 0;
} else if (strcmp (optarg, "never") == 0) {
resolve_names = -1;
} else {
fprintf(stderr, "resolve-names must be early, late or never\n");
err(udev, "resolve-names must be early, late or never\n");
goto exit;
}
break;
2006-09-08 13:27:03 +04:00
case 'h':
printf("Usage: udevd OPTIONS\n"
" --daemon\n"
" --debug\n"
" --children-max=<maximum number of workers>\n"
" --exec-delay=<seconds to wait before executing RUN=>\n"
" --resolve-names=early|late|never\n"
" --version\n"
" --help\n"
"\n");
2007-02-25 01:43:36 +03:00
goto exit;
case 'V':
2008-07-30 03:45:23 +04:00
printf("%s\n", VERSION);
goto exit;
2006-09-08 13:27:03 +04:00
default:
goto exit;
}
}
/*
* read the kernel commandline, in case we need to get into debug mode
* udev.log-priority=<level> syslog priority
* udev.children-max=<number of workers> events are fully serialized if set to 1
*
*/
f = fopen("/proc/cmdline", "r");
if (f != NULL) {
char cmdline[4096];
if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
char *pos;
pos = strstr(cmdline, "udev.log-priority=");
if (pos != NULL) {
pos += strlen("udev.log-priority=");
udev_set_log_priority(udev, util_log_priority(pos));
}
pos = strstr(cmdline, "udev.children-max=");
if (pos != NULL) {
pos += strlen("udev.children-max=");
children_max = strtoul(pos, NULL, 0);
}
pos = strstr(cmdline, "udev.exec-delay=");
if (pos != NULL) {
pos += strlen("udev.exec-delay=");
exec_delay = strtoul(pos, NULL, 0);
}
}
fclose(f);
}
if (getuid() != 0) {
fprintf(stderr, "root privileges required\n");
err(udev, "root privileges required\n");
goto exit;
}
/* set umask before creating any file/directory */
chdir("/");
umask(022);
/* create standard links, copy static nodes, create nodes from modules */
static_dev_create(udev);
static_dev_create_from_modules(udev);
/* before opening new files, make sure std{in,out,err} fds are in a sane state */
if (daemonize) {
int fd;
fd = open("/dev/null", O_RDWR);
if (fd >= 0) {
if (write(STDOUT_FILENO, 0, 0) < 0)
dup2(fd, STDOUT_FILENO);
if (write(STDERR_FILENO, 0, 0) < 0)
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO)
close(fd);
} else {
fprintf(stderr, "cannot open /dev/null\n");
err(udev, "cannot open /dev/null\n");
}
}
2011-04-15 01:46:44 +04:00
if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) {
/* get control and netlink socket from from systemd */
udev_ctrl = udev_ctrl_new_from_fd(udev, fd_ctrl);
2011-04-15 01:46:44 +04:00
if (udev_ctrl == NULL) {
err(udev, "error taking over udev control socket");
rc = 1;
goto exit;
}
monitor = udev_monitor_new_from_netlink_fd(udev, "kernel", fd_netlink);
if (monitor == NULL) {
err(udev, "error taking over netlink socket\n");
rc = 3;
goto exit;
}
} else {
/* open control and netlink socket */
udev_ctrl = udev_ctrl_new(udev);
2011-04-15 01:46:44 +04:00
if (udev_ctrl == NULL) {
fprintf(stderr, "error initializing udev control socket");
err(udev, "error initializing udev control socket");
rc = 1;
goto exit;
}
fd_ctrl = udev_ctrl_get_fd(udev_ctrl);
monitor = udev_monitor_new_from_netlink(udev, "kernel");
if (monitor == NULL) {
fprintf(stderr, "error initializing netlink socket\n");
err(udev, "error initializing netlink socket\n");
rc = 3;
goto exit;
}
fd_netlink = udev_monitor_get_fd(monitor);
}
if (udev_monitor_enable_receiving(monitor) < 0) {
fprintf(stderr, "error binding netlink socket\n");
err(udev, "error binding netlink socket\n");
rc = 3;
2008-09-08 19:59:00 +04:00
goto exit;
}
2011-04-15 01:46:44 +04:00
2008-09-08 19:59:00 +04:00
if (udev_ctrl_enable_receiving(udev_ctrl) < 0) {
fprintf(stderr, "error binding udev control socket\n");
err(udev, "error binding udev control socket\n");
2008-09-08 19:59:00 +04:00
rc = 1;
goto exit;
}
udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024);
/* create queue file before signalling 'ready', to make sure we block 'settle' */
udev_queue_export = udev_queue_export_new(udev);
if (udev_queue_export == NULL) {
err(udev, "error creating queue file\n");
goto exit;
}
2011-04-13 03:17:09 +04:00
if (daemonize) {
pid_t pid;
int fd;
2011-04-13 03:17:09 +04:00
pid = fork();
switch (pid) {
case 0:
break;
case -1:
err(udev, "fork of daemon failed: %m\n");
rc = 4;
goto exit;
default:
rc = EXIT_SUCCESS;
goto exit_daemonize;
2011-04-13 03:17:09 +04:00
}
setsid();
fd = open("/proc/self/oom_score_adj", O_RDWR);
if (fd < 0) {
/* Fallback to old interface */
fd = open("/proc/self/oom_adj", O_RDWR);
if (fd < 0) {
err(udev, "error disabling OOM: %m\n");
} else {
/* OOM_DISABLE == -17 */
write(fd, "-17", 3);
close(fd);
}
} else {
write(fd, "-1000", 5);
close(fd);
}
2011-04-13 03:17:09 +04:00
} else {
sd_notify(1, "READY=1");
}
f = fopen("/dev/kmsg", "w");
if (f != NULL) {
2011-04-20 19:39:44 +04:00
fprintf(f, "<30>udevd[%u]: starting version " VERSION "\n", getpid());
fclose(f);
}
if (!debug) {
int fd;
fd = open("/dev/null", O_RDWR);
if (fd >= 0) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
}
}
2011-04-13 03:17:09 +04:00
fd_inotify = udev_watch_init(udev);
if (fd_inotify < 0) {
fprintf(stderr, "error initializing inotify\n");
err(udev, "error initializing inotify\n");
rc = 4;
goto exit;
}
if (udev_get_rules_path(udev) != NULL) {
2011-04-13 03:17:09 +04:00
inotify_add_watch(fd_inotify, udev_get_rules_path(udev),
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
} else {
char filename[UTIL_PATH_SIZE];
struct stat statbuf;
2011-04-13 03:17:09 +04:00
inotify_add_watch(fd_inotify, LIBEXECDIR "/rules.d",
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
2011-04-13 03:17:09 +04:00
inotify_add_watch(fd_inotify, SYSCONFDIR "/udev/rules.d",
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
/* watch dynamic rules directory */
util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/rules.d", NULL);
if (stat(filename, &statbuf) != 0) {
util_create_path(udev, filename);
mkdir(filename, 0755);
}
2011-04-13 03:17:09 +04:00
inotify_add_watch(fd_inotify, filename,
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
}
udev_watch_restore(udev);
/* block and listen to all signals on signalfd */
sigfillset(&mask);
2011-04-20 03:53:03 +04:00
sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
2011-04-18 04:14:24 +04:00
fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
2011-04-13 03:17:09 +04:00
if (fd_signal < 0) {
2011-04-18 04:14:24 +04:00
fprintf(stderr, "error creating signalfd\n");
err(udev, "error creating signalfd\n");
rc = 5;
goto exit;
}
/* unnamed socket from workers to the main daemon */
2009-10-30 14:31:59 +03:00
if (socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, worker_watch) < 0) {
2011-04-18 04:14:24 +04:00
fprintf(stderr, "error creating socketpair\n");
err(udev, "error creating socketpair\n");
rc = 6;
goto exit;
}
2011-04-13 03:17:09 +04:00
fd_worker = worker_watch[READ_END];
2011-12-22 02:10:56 +04:00
udev_builtin_load(udev);
rules = udev_rules_new(udev, resolve_names);
2008-10-18 17:02:01 +04:00
if (rules == NULL) {
err(udev, "error reading rules\n");
goto exit;
}
2011-04-13 03:17:09 +04:00
memset(&ep_ctrl, 0, sizeof(struct epoll_event));
ep_ctrl.events = EPOLLIN;
ep_ctrl.data.fd = fd_ctrl;
2011-04-15 01:46:44 +04:00
2011-04-13 03:17:09 +04:00
memset(&ep_inotify, 0, sizeof(struct epoll_event));
ep_inotify.events = EPOLLIN;
ep_inotify.data.fd = fd_inotify;
2011-04-15 01:46:44 +04:00
2011-04-13 03:17:09 +04:00
memset(&ep_signal, 0, sizeof(struct epoll_event));
ep_signal.events = EPOLLIN;
ep_signal.data.fd = fd_signal;
2011-04-15 01:46:44 +04:00
2011-04-13 03:17:09 +04:00
memset(&ep_netlink, 0, sizeof(struct epoll_event));
ep_netlink.events = EPOLLIN;
ep_netlink.data.fd = fd_netlink;
2011-04-15 01:46:44 +04:00
2011-04-13 03:17:09 +04:00
memset(&ep_worker, 0, sizeof(struct epoll_event));
ep_worker.events = EPOLLIN;
ep_worker.data.fd = fd_worker;
2011-04-15 01:46:44 +04:00
2011-04-13 03:17:09 +04:00
fd_ep = epoll_create1(EPOLL_CLOEXEC);
if (fd_ep < 0) {
err(udev, "error creating epoll fd: %m\n");
goto exit;
}
if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_ctrl, &ep_ctrl) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_inotify, &ep_inotify) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_netlink, &ep_netlink) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_worker, &ep_worker) < 0) {
err(udev, "fail to add fds to epoll: %m\n");
goto exit;
}
/* if needed, convert old database from earlier udev version */
convert_db(udev);
if (children_max <= 0) {
int memsize = mem_size_mb();
/* set value depending on the amount of RAM */
if (memsize > 0)
children_max = 128 + (memsize / 8);
else
children_max = 128;
}
info(udev, "set children_max to %u\n", children_max);
udev_rules_apply_static_dev_perms(rules);
udev_list_node_init(&event_list);
udev_list_node_init(&worker_list);
2011-04-13 03:17:09 +04:00
for (;;) {
struct epoll_event ev[8];
2009-01-21 13:09:27 +03:00
int fdcount;
int timeout;
2011-04-13 03:17:09 +04:00
bool is_worker, is_signal, is_inotify, is_netlink, is_ctrl;
int i;
if (udev_exit) {
/* close sources of new events and discard buffered events */
if (fd_ctrl >= 0) {
epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_ctrl, NULL);
fd_ctrl = -1;
}
if (monitor != NULL) {
epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_netlink, NULL);
udev_monitor_unref(monitor);
monitor = NULL;
}
if (fd_inotify >= 0) {
epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_inotify, NULL);
close(fd_inotify);
fd_inotify = -1;
}
2011-04-13 03:17:09 +04:00
/* discard queued events and kill workers */
event_queue_cleanup(udev, EVENT_QUEUED);
worker_kill(udev, 0);
/* exit after all has cleaned up */
if (udev_list_node_is_empty(&event_list) && udev_list_node_is_empty(&worker_list))
2011-04-13 03:17:09 +04:00
break;
/* timeout at exit for workers to finish */
timeout = 60 * 1000;
} else if (udev_list_node_is_empty(&event_list) && children > 2) {
2011-04-13 03:17:09 +04:00
/* set timeout to kill idle workers */
timeout = 3 * 1000;
2011-04-13 03:17:09 +04:00
} else {
timeout = -1;
2011-04-13 03:17:09 +04:00
}
fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), timeout);
if (fdcount < 0)
continue;
2011-04-13 03:17:09 +04:00
if (fdcount == 0) {
if (udev_exit) {
info(udev, "timeout, giving up waiting for workers to finish\n");
break;
}
/* timeout - kill idle workers */
worker_kill(udev, 2);
2011-04-13 03:17:09 +04:00
}
is_worker = is_signal = is_inotify = is_netlink = is_ctrl = false;
for (i = 0; i < fdcount; i++) {
if (ev[i].data.fd == fd_worker && ev[i].events & EPOLLIN)
is_worker = true;
else if (ev[i].data.fd == fd_netlink && ev[i].events & EPOLLIN)
is_netlink = true;
else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN)
is_signal = true;
else if (ev[i].data.fd == fd_inotify && ev[i].events & EPOLLIN)
is_inotify = true;
else if (ev[i].data.fd == fd_ctrl && ev[i].events & EPOLLIN)
is_ctrl = true;
}
2009-01-21 13:09:27 +03:00
/* event has finished */
2011-04-13 03:17:09 +04:00
if (is_worker)
worker_returned(fd_worker);
2009-01-21 13:09:27 +03:00
2011-04-13 03:17:09 +04:00
if (is_netlink) {
struct udev_device *dev;
dev = udev_monitor_receive_device(monitor);
if (dev != NULL) {
udev_device_set_usec_initialized(dev, now_usec());
if (event_queue_insert(dev) < 0)
udev_device_unref(dev);
}
}
/* start new events */
if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue)
2011-04-13 03:17:09 +04:00
event_queue_start(udev);
2008-10-16 19:16:58 +04:00
2011-04-13 03:17:09 +04:00
if (is_signal) {
struct signalfd_siginfo fdsi;
ssize_t size;
2008-10-16 19:16:58 +04:00
2011-04-13 03:17:09 +04:00
size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
if (size == sizeof(struct signalfd_siginfo))
handle_signal(udev, fdsi.ssi_signo);
}
2011-04-13 03:17:09 +04:00
/* we are shutting down, the events below are not handled anymore */
if (udev_exit)
continue;
/* device node and rules directory inotify watch */
2011-04-13 03:17:09 +04:00
if (is_inotify)
2009-02-11 23:56:35 +03:00
handle_inotify(udev);
/*
* This needs to be after the inotify handling, to make sure,
2011-04-13 03:17:09 +04:00
* that the ping is send back after the possibly generated
* "change" events by the inotify device node watch.
2011-04-13 03:17:09 +04:00
*
* A single time we may receive a client connection which we need to
* keep open to block the client. It will be closed right before we
* exit.
*/
2011-04-13 03:17:09 +04:00
if (is_ctrl)
ctrl_conn = handle_ctrl_msg(udev_ctrl);
/* rules changed, set by inotify or a HUP signal */
if (reload_config) {
2008-10-18 17:02:01 +04:00
struct udev_rules *rules_new;
worker_kill(udev, 0);
rules_new = udev_rules_new(udev, resolve_names);
2008-10-18 17:02:01 +04:00
if (rules_new != NULL) {
udev_rules_unref(rules);
rules = rules_new;
}
reload_config = 0;
}
[PATCH] udevd - cleanup and better timeout handling On Thu, Jan 29, 2004 at 04:55:11PM +0100, Kay Sievers wrote: > On Thu, Jan 29, 2004 at 02:56:25AM +0100, Kay Sievers wrote: > > On Wed, Jan 28, 2004 at 10:47:36PM +0100, Kay Sievers wrote: > > > Oh, couldn't resist to try threads. > > > It's a multithreaded udevd that communicates through a localhost socket. > > > The message includes a magic with the udev version, so we don't accept > > > older udevsend's. > > > > > > No need for locking, cause we can't bind two sockets on the same address. > > > The daemon tries to connect and if it fails it starts the daemon. > > > > > > We create a thread for every incoming connection, handle over the socket, > > > sort the messages in the global message queue and exit the thread. > > > Huh, that was easy with threads :) > > > > > > With the addition of a message we wakeup the queue manager thread and > > > handle timeouts or move the message to the global exec list. This wakes > > > up the exec list manager who looks if a process is already running for this > > > device path. > > > If yes, the exec is delayed otherwise we create a thread that execs udev. > > > n the background. With the return of udev we free the message and wakeup > > > the exec list manager to look if something is pending. > > > > > > It is just a quick shot, cause I couldn't solve the problems with fork an > > > scheduling and I wanted to see if I'm to stupid :) > > > But if anybody with a better idea or more experience with I/O scheduling > > > we may go another way. The remaining problem is that klibc doesn't support > > > threads. > > > > > > By now, we don't exec anything, it's just a sleep 3 for every exec, > > > but you can see the queue management by watching syslog and do: > > > > > > DEVPATH=/abc ACTION=add SEQNUM=0 ./udevsend /abc > > Next version, switched to unix domain sockets. Next cleaned up version. Hey, nobody wants to try it :) Works for me, It's funny if I connect/disconnect my 4in1-usb-flash-reader every two seconds. The 2.6 usb rocks! I can connect/diconnect a hub with 3 devices plugged in every second and don't run into any problem but a _very_ big udevd queue.
2004-02-01 20:12:36 +03:00
}
rc = EXIT_SUCCESS;
[PATCH] udevd - cleanup and better timeout handling On Thu, Jan 29, 2004 at 04:55:11PM +0100, Kay Sievers wrote: > On Thu, Jan 29, 2004 at 02:56:25AM +0100, Kay Sievers wrote: > > On Wed, Jan 28, 2004 at 10:47:36PM +0100, Kay Sievers wrote: > > > Oh, couldn't resist to try threads. > > > It's a multithreaded udevd that communicates through a localhost socket. > > > The message includes a magic with the udev version, so we don't accept > > > older udevsend's. > > > > > > No need for locking, cause we can't bind two sockets on the same address. > > > The daemon tries to connect and if it fails it starts the daemon. > > > > > > We create a thread for every incoming connection, handle over the socket, > > > sort the messages in the global message queue and exit the thread. > > > Huh, that was easy with threads :) > > > > > > With the addition of a message we wakeup the queue manager thread and > > > handle timeouts or move the message to the global exec list. This wakes > > > up the exec list manager who looks if a process is already running for this > > > device path. > > > If yes, the exec is delayed otherwise we create a thread that execs udev. > > > n the background. With the return of udev we free the message and wakeup > > > the exec list manager to look if something is pending. > > > > > > It is just a quick shot, cause I couldn't solve the problems with fork an > > > scheduling and I wanted to see if I'm to stupid :) > > > But if anybody with a better idea or more experience with I/O scheduling > > > we may go another way. The remaining problem is that klibc doesn't support > > > threads. > > > > > > By now, we don't exec anything, it's just a sleep 3 for every exec, > > > but you can see the queue management by watching syslog and do: > > > > > > DEVPATH=/abc ACTION=add SEQNUM=0 ./udevsend /abc > > Next version, switched to unix domain sockets. Next cleaned up version. Hey, nobody wants to try it :) Works for me, It's funny if I connect/disconnect my 4in1-usb-flash-reader every two seconds. The 2.6 usb rocks! I can connect/diconnect a hub with 3 devices plugged in every second and don't run into any problem but a _very_ big udevd queue.
2004-02-01 20:12:36 +03:00
exit:
udev_queue_export_cleanup(udev_queue_export);
udev_ctrl_cleanup(udev_ctrl);
exit_daemonize:
2011-04-13 03:17:09 +04:00
if (fd_ep >= 0)
close(fd_ep);
worker_list_cleanup(udev);
event_queue_cleanup(udev, EVENT_UNDEF);
2008-10-18 17:02:01 +04:00
udev_rules_unref(rules);
2011-12-22 02:10:56 +04:00
udev_builtin_unload(udev);
2011-04-13 03:17:09 +04:00
if (fd_signal >= 0)
close(fd_signal);
if (worker_watch[READ_END] >= 0)
close(worker_watch[READ_END]);
if (worker_watch[WRITE_END] >= 0)
close(worker_watch[WRITE_END]);
udev_monitor_unref(monitor);
2011-04-13 03:17:09 +04:00
udev_queue_export_unref(udev_queue_export);
udev_ctrl_connection_unref(ctrl_conn);
udev_ctrl_unref(udev_ctrl);
udev_selinux_exit(udev);
udev_unref(udev);
2009-06-10 00:47:48 +04:00
udev_log_close();
return rc;
[PATCH] spilt udev into pieces On Thu, Jan 22, 2004 at 01:27:45AM +0100, Kay Sievers wrote: > On Wed, Jan 21, 2004 at 02:38:25PM +0100, Kay Sievers wrote: > > On Thu, Jan 15, 2004 at 01:45:10PM -0800, Greg KH wrote: > > > On Thu, Jan 15, 2004 at 10:36:25PM +0800, Ling, Xiaofeng wrote: > > > > Hi, Greg > > > > I wrote a simple implementation for the two pieces > > > > of send and receive hotplug event, > > > > use a message queue and a list for the out of order > > > > hotplug event. It also has a timeout timer of 3 seconds. > > > > They are now separate program. the file nseq is the test script. > > > > Could you have a look to see wether it is feasible? > > > > If so, I'll continue to merge with udev. > > > > > > Yes, very nice start. Please continue on. > > > > > > One minor comment, please stick with the kernel coding style when you > > > are writing new code for udev. > > > > I took the code from Xiaofeng, cleaned the whitespace, renamed some bits, > > tweaked the debugging, added the udev exec and created a patch for the current tree. > > > > It seems functional now, by simply executing our current udev (dirty hack). > > It reorders the incoming events and if one is missing it delays the > > execution of the following ones up to a maximum of 10 seconds. > > > > Test script is included, but you can't mix hotplug sequence numbers and > > test script numbers, it will result in waiting for the missing numbers :) > > Hey, nobody want's to play with me? > So here I'm chatting with myself :) > > This is the next version with signal handling for resetting the expected > signal number. I changed the behaviour of the timeout to skip all > missing events at once and to proceed with the next event in the queue. > > So it's now possible to use the test script at any time, cause it resets > the daemon, if real hotplug event coming in later all missing nimbers will > be skipped after a timeout of 10 seconds and the queued events are applied. Here is the next updated updated version to apply to the lastet udev. I've added infrastructure for getting the state of the IPC queue in the sender and set the program to exec by the daemon. Also the magic key id is replaced by the usual key generation by path/nr. It looks promising, I use it on my machine and my 4in1 USB-flash-reader connect/disconnect emits the events "randomly" but udevd is able to reorder it and calls our normal udev in the right order.
2004-01-23 11:28:57 +03:00
}