From: Kay Sievers <kay.sievers@vrfy.org>
To: linux-hotplug@vger.kernel.org
Subject: [adventure] replace /sbin/hotplug by udevd
Date: Thu, 18 Nov 2004 00:27:26 +0000 [thread overview]
Message-ID: <20041118002726.GA4281@vrfy.org> (raw)
[-- Attachment #1: Type: text/plain, Size: 2166 bytes --]
!!! Please, don't try this if you don't know how to bring your !!!
!!! system back if it does not boot anymore cause of a broken udev. !!!
This experimental patch changes udevd/udev to handle the _whole_ hotplug
event from the kernel up to the multiplexing of /etc/hotplug.d/. It
should solve most of the current shortcomings of the hotplug event handling:
- sysfs if not fully populated at event time
- at device disconnect/reconnect, the "remove" may beat the "add"
- an event may already work on the same DEVPATH
- the hotplug scripts don't know the device node name
- the total count of event processes can't be controlled
The architecture is very similar to udevd today, only that we wait for
_all_ sysfs devices internally and then also calls /etc/hotplug/* from
the forked udev process.
/sbin/hotplug is replaced by /sbin/udevsend. The kernel just calls this
small binary to place the event into the udevd daemon. We may also use
the netlink uevent in the future, so no fork at all is done from the
kernel for a hotplug event.
The daemon listens, reorders events and forks an instance for every event,
which:
-waits for sysfs (also for /sys/devices/*)
-creates/removes the device node
-exports interesting values to its environment
-calls/multiplexes /etc/hotplug.d/*
-calls/multiplexes /etc/dev.d/* (we don't really need that anymore)
-exits
This way get all what todays hotplug events can dream of:
-fully populated sysfs
-events in the right order (SEQNUM)
-delayed events for the _same_ DEVPATH, all others run in parallel
-all interesting values to the environment
-device node ready and its name available
-possibly limit the total count of events processes (not implemented now)
One single hotplug event for the creation of a partition now looks like this:
ACTION=add
SUBSYSTEM=block
DEVPATH=/block/sda/sda1
SEQNUM=1027
DEVNAME=/dev/sda1
PHYSDEVPATH=/devices/pci0000:00/0000:00:1d.1/usb3/3-1/3-1:1.0/host0/target0:0:0/0:0:0:0
PHYSDEVBUS=scsi
PHYSDEVDRIVER=sd
This patch applies on top of udev v045. /proc/sys/kernel/hotplug should be
set to /sbin/udevsend.
Any thoughts,
Kay
[-- Attachment #2: udev-as-hotplugd-02.patch --]
[-- Type: text/plain, Size: 11617 bytes --]
===== dev_d.c 1.20 vs edited =====
--- 1.20/dev_d.c 2004-11-11 22:32:18 +01:00
+++ edited/dev_d.c 2004-11-16 00:47:59 +01:00
@@ -37,6 +37,11 @@ static int run_program(const char *filen
int fd;
struct udevice *udev = data;
+ if (strstr(filename, "udev.hotplug") != NULL) {
+ dbg("prevent loop, don't call link pointing to ourself");
+ return 0;
+ }
+
dbg("running %s", filename);
pid = fork();
@@ -96,13 +101,17 @@ void dev_d_execute(struct udevice *udev,
temp = strchr(temp, '/');
}
- snprintf(dirname, PATH_MAX, "%s/%s", basedir, udev->name);
- dirname[PATH_MAX-1] = '\0';
- call_foreach_file(run_program, dirname, suffix, udev);
-
- snprintf(dirname, PATH_MAX, "%s/%s", basedir, udev->subsystem);
- dirname[PATH_MAX-1] = '\0';
- call_foreach_file(run_program, dirname, suffix, udev);
+ if (udev->name[0] != '\0') {
+ snprintf(dirname, PATH_MAX, "%s/%s", basedir, udev->name);
+ dirname[PATH_MAX-1] = '\0';
+ call_foreach_file(run_program, dirname, suffix, udev);
+ }
+
+ if (udev->subsystem[0] != '\0') {
+ snprintf(dirname, PATH_MAX, "%s/%s", basedir, udev->subsystem);
+ dirname[PATH_MAX-1] = '\0';
+ call_foreach_file(run_program, dirname, suffix, udev);
+ }
snprintf(dirname, PATH_MAX, "%s/default", basedir);
dirname[PATH_MAX-1] = '\0';
===== udev.c 1.82 vs edited =====
--- 1.82/udev.c 2004-11-13 06:51:09 +01:00
+++ edited/udev.c 2004-11-16 15:00:15 +01:00
@@ -4,6 +4,7 @@
* Userspace devfs
*
* Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
*
* 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
@@ -68,66 +69,19 @@ int main(int argc, char *argv[], char *e
{
struct sigaction act;
struct sysfs_class_device *class_dev;
+ struct sysfs_device *devices_dev;
struct udevice udev;
char path[SYSFS_PATH_MAX];
int retval = -EINVAL;
- enum {
- ADD,
- REMOVE,
- UDEVSTART,
- } act_type;
+ const char *error;
+ const char *action = getenv("ACTION");
+ const char *devpath = getenv("DEVPATH");
+ const char *subsystem = argv[1];
dbg("version %s", UDEV_VERSION);
logging_init("udev");
udev_init_config();
- if (strstr(argv[0], "udevstart") || (argv[1] != NULL && strstr(argv[1], "udevstart"))) {
- act_type = UDEVSTART;
- } else {
- const char *action = getenv("ACTION");
- const char *devpath = getenv("DEVPATH");
- const char *subsystem = argv[1];
-
- if (!action) {
- dbg("no action?");
- goto exit;
- }
- if (strcmp(action, "add") == 0) {
- act_type = ADD;
- } else if (strcmp(action, "remove") == 0) {
- act_type = REMOVE;
- } else {
- dbg("no action '%s' for us", action);
- goto exit;
- }
-
- if (!devpath) {
- dbg("no devpath?");
- goto exit;
- }
- dbg("looking at '%s'", devpath);
-
- /* we only care about class devices and block stuff */
- if (!strstr(devpath, "class") && !strstr(devpath, "block")) {
- dbg("not a block or class device");
- goto exit;
- }
-
- if (!subsystem) {
- dbg("no subsystem");
- goto exit;
- }
-
- udev_set_values(&udev, devpath, subsystem, action);
-
- /* skip blacklisted subsystems */
- if (udev.type != 'n' && subsystem_expect_no_dev(subsystem)) {
- dbg("don't care about '%s' devices", subsystem);
- goto exit;
- };
-
- }
-
/* set signal handlers */
act.sa_handler = (void (*) (int))sig_handler;
sigemptyset (&act.sa_mask);
@@ -137,51 +91,104 @@ int main(int argc, char *argv[], char *e
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
- /* trigger timout to interrupt blocking syscalls */
+ /* trigger timeout to interrupt blocking syscalls */
alarm(ALARM_TIMEOUT);
- switch(act_type) {
- case UDEVSTART:
- dbg("udevstart");
+ udev_set_values(&udev, devpath, subsystem, action);
+
+ if (strstr(argv[0], "udevstart") || (argv[1] != NULL && strstr(argv[1], "udevstart"))) {
+ dbg("event: udevstart");
udev_log = 0;
namedev_init();
retval = udev_start();
- break;
- case ADD:
- dbg("udev add");
-
- /* open the device */
- snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_path, udev.devpath);
- class_dev = sysfs_open_class_device_path(path);
- if (class_dev == NULL) {
- dbg ("sysfs_open_class_device_path failed");
- break;
- }
- dbg("opened class_dev->name='%s'", class_dev->name);
+ goto exit;
+ }
- /* init rules */
- namedev_init();
+ if (!action) {
+ dbg("no action");
+ goto hotplug;
+ }
+
+ if (!subsystem) {
+ dbg("no subsystem");
+ goto hotplug;
+ }
+
+ if (!devpath) {
+ dbg("no devpath");
+ goto hotplug;
+ }
+
+ if ((strncmp(devpath, "/block/", 7) == 0) || (strncmp(devpath, "/class/", 7) == 0)) {
+ if (strcmp(action, "add") == 0) {
+ /* wait for sysfs and possibly add node */
+ dbg("event: udev add");
+
+ /* skip blacklisted subsystems */
+ if (udev.type != 'n' && subsystem_expect_no_dev(udev.subsystem)) {
+ dbg("don't care about '%s' devices", udev.subsystem);
+ goto hotplug;
+ };
+
+ snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_path, udev.devpath);
+ class_dev = wait_class_device_open(path);
+ if (class_dev == NULL) {
+ dbg ("sysfs_open_class_device_path failed");
+ goto hotplug;
+ }
+ dbg("opened class_dev->name='%s'", class_dev->name);
+
+ wait_for_class_device(class_dev, &error);
+
+ /* init rules, permissions */
+ namedev_init();
+
+ /* name, create node, store in db */
+ retval = udev_add_device(&udev, class_dev);
+
+ /* run dev.d/ scripts if we created a node or changed a netif name */
+ if (udev.devname[0] != '\0') {
+ setenv("DEVNAME", udev.devname, 1);
+ dev_d_execute(&udev, DEVD_DIR, DEVD_SUFFIX);
+ }
- /* name, create node, store in db */
- retval = udev_add_device(&udev, class_dev);
+ sysfs_close_class_device(class_dev);
+ } else if (strcmp(action, "remove") == 0) {
+ /* possibly remove a node */
+ dbg("event: udev remove");
- /* run dev.d/ scripts if we created a node or changed a netif name */
- if (udev.devname[0] != '\0') {
- setenv("DEVNAME", udev.devname, 1);
+ /* get node from db, delete it */
+ retval = udev_remove_device(&udev);
+
+ /* run scripts */
dev_d_execute(&udev, DEVD_DIR, DEVD_SUFFIX);
}
+ } else if ((strncmp(devpath, "/devices/", 9) == 0)) {
+ if (strcmp(action, "add") == 0) {
+ /* wait for sysfs */
+ dbg("event: devices add");
- sysfs_close_class_device(class_dev);
- break;
- case REMOVE:
- dbg("udev remove");
+ snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_path, devpath);
+ devices_dev = wait_devices_device_open(path);
+ if (!devices_dev) {
+ dbg("error: devices device unavailable (probably remove has beaten us)");
+ goto hotplug;
+ }
+ dbg("devices device opened '%s'", path);
- /* get node from db, delete it*/
- retval = udev_remove_device(&udev);
+ wait_for_devices_device(devices_dev, &error);
- /* run scripts */
- dev_d_execute(&udev, DEVD_DIR, DEVD_SUFFIX);
+ sysfs_close_device(devices_dev);
+ } else if (strcmp(action, "remove") == 0) {
+ dbg("event: devices remove");
+ }
+ } else {
+ dbg("event: unhandled");
}
+
+hotplug:
+ /* call the hotplug scripts */
+ dev_d_execute(&udev, HOTPLUGD_DIR, HOTPLUG_SUFFIX);
exit:
logging_close();
===== udev.h 1.72 vs edited =====
--- 1.72/udev.h 2004-11-13 06:43:23 +01:00
+++ edited/udev.h 2004-11-16 00:29:14 +01:00
@@ -44,6 +44,9 @@
#define DEVD_DIR "/etc/dev.d"
#define DEVD_SUFFIX ".dev"
+#define HOTPLUGD_DIR "/etc/hotplug.d"
+#define HOTPLUG_SUFFIX ".hotplug"
+
struct udevice {
char devpath[DEVPATH_SIZE];
char subsystem[SUBSYSTEM_SIZE];
===== udev_lib.c 1.16 vs edited =====
--- 1.16/udev_lib.c 2004-11-13 04:36:46 +01:00
+++ edited/udev_lib.c 2004-11-16 01:54:09 +01:00
@@ -40,37 +40,32 @@
#define CLASS_PATH "/class/"
#define NET_PATH "/class/net/"
-char get_device_type(const char *path, const char *subsystem)
-{
- if (strcmp(subsystem, "block") == 0)
- return 'b';
-
- if (strcmp(subsystem, "net") == 0)
- return 'n';
-
- if (strncmp(path, BLOCK_PATH, strlen(BLOCK_PATH)) == 0 &&
- strlen(path) > strlen(BLOCK_PATH))
- return 'b';
-
- if (strncmp(path, NET_PATH, strlen(NET_PATH)) == 0 &&
- strlen(path) > strlen(NET_PATH))
- return 'n';
-
- if (strncmp(path, CLASS_PATH, strlen(CLASS_PATH)) == 0 &&
- strlen(path) > strlen(CLASS_PATH))
- return 'c';
-
- return '\0';
-}
void udev_set_values(struct udevice *udev, const char* devpath,
const char *subsystem, const char* action)
{
memset(udev, 0x00, sizeof(struct udevice));
- strfieldcpy(udev->devpath, devpath);
- strfieldcpy(udev->subsystem, subsystem);
- strfieldcpy(udev->action, action);
- udev->type = get_device_type(devpath, subsystem);
+ if (devpath)
+ strfieldcpy(udev->devpath, devpath);
+ if (subsystem)
+ strfieldcpy(udev->subsystem, subsystem);
+ if (action)
+ strfieldcpy(udev->action, action);
+
+ if (strcmp(udev->subsystem, "block") == 0)
+ udev->type = 'b';
+
+ if (strcmp(udev->subsystem, "net") == 0)
+ udev->type = 'n';
+
+ if (strncmp(udev->devpath, "/block/", 7) == 0)
+ udev->type = 'b';
+
+ if (strncmp(udev->devpath, "/class/net/", 11) == 0)
+ udev->type = 'n';
+
+ if (strncmp(udev->devpath, "/class/", 7) == 0)
+ udev->type = 'c';
}
int kernel_release_satisfactory(int version, int patchlevel, int sublevel)
===== udev_lib.h 1.16 vs edited =====
--- 1.16/udev_lib.h 2004-11-13 04:36:46 +01:00
+++ edited/udev_lib.h 2004-11-16 01:23:01 +01:00
@@ -76,7 +76,6 @@ do { \
# define asmlinkage /* nothing */
#endif
-extern char get_device_type(const char *path, const char *subsystem);
extern void udev_set_values(struct udevice *udev, const char* devpath,
const char *subsystem, const char* action);
extern int kernel_release_satisfactory(int version, int patchlevel, int sublevel);
===== udevd.c 1.47 vs edited =====
--- 1.47/udevd.c 2004-11-11 22:18:28 +01:00
+++ edited/udevd.c 2004-11-16 02:35:46 +01:00
@@ -153,9 +153,14 @@ static void udev_run(struct hotplug_msg
static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg)
{
struct hotplug_msg *loop_msg;
- list_for_each_entry(loop_msg, &running_list, list)
- if (strncmp(loop_msg->devpath, msg->devpath, sizeof(loop_msg->devpath)) == 0)
+ list_for_each_entry(loop_msg, &running_list, list) {
+ if (loop_msg->devpath == NULL || msg->devpath == NULL)
+ continue;
+
+ if (strcmp(loop_msg->devpath, msg->devpath) == 0)
return loop_msg;
+ }
+
return NULL;
}
===== udevinfo.c 1.32 vs edited =====
--- 1.32/udevinfo.c 2004-11-12 21:33:25 +01:00
+++ edited/udevinfo.c 2004-11-16 01:22:40 +01:00
@@ -125,10 +125,6 @@ static int print_device_chain(const char
struct sysfs_device *sysfs_dev;
struct sysfs_device *sysfs_dev_parent;
int retval = 0;
- char type;
-
- type = get_device_type(path, "");
- dbg("device type is %c", type);
/* get the class dev */
class_dev = sysfs_open_class_device_path(path);
@@ -144,16 +140,10 @@ static int print_device_chain(const char
"to match the device for which the node will be created.\n"
"\n");
- if (type == 'b' || type =='c') {
- /* read the 'dev' file for major/minor*/
- attr = sysfs_get_classdev_attr(class_dev, "dev");
- if (attr == NULL) {
- printf("couldn't get the \"dev\" file\n");
- retval = -1;
- goto exit;
- }
+ /* look for the 'dev' file */
+ attr = sysfs_get_classdev_attr(class_dev, "dev");
+ if (attr == NULL)
printf("device '%s' has major:minor %s", class_dev->path, attr->value);
- }
/* open sysfs class device directory and print all attributes */
printf(" looking at class device '%s':\n", class_dev->path);
next reply other threads:[~2004-11-18 0:27 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-11-18 0:27 Kay Sievers [this message]
2004-11-18 1:25 ` [adventure] replace /sbin/hotplug by udevd Greg KH
2004-11-18 4:04 ` Kevin P. Fleming
2004-11-18 6:40 ` Stefan Schweizer
2004-11-18 23:47 ` Kay Sievers
2004-11-19 0:03 ` Kay Sievers
2004-11-19 0:55 ` Greg KH
2004-11-19 1:11 ` Kay Sievers
2004-11-19 7:27 ` Greg KH
2004-11-19 16:03 ` Kay Sievers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20041118002726.GA4281@vrfy.org \
--to=kay.sievers@vrfy.org \
--cc=linux-hotplug@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).