From: kay.sievers@vrfy.org Date: Fri, 15 Oct 2004 03:36:07 +0000 (-0700) Subject: [PATCH] remove sleeps from udev as it is external now X-Git-Tag: 039~15 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=707680b1cf08369da365de1a5e06089621ff8c77 [PATCH] remove sleeps from udev as it is external now Here we remove all the sysfs sleep loops from udev as wait_for_sysfs will do this for us and any other hotplug user. We still keep a small blacklist of subsystems we don't care about but any missing entry here will no longer lead to a spinning udev waiting for files. --- diff --git a/namedev.c b/namedev.c index 8a4436363..39f033726 100644 --- a/namedev.c +++ b/namedev.c @@ -346,69 +346,6 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize, } } -/* - * Note, we can have multiple files for different busses in here due - * to the mess that USB has for its device tree... - */ -static struct bus_file { - char *bus; - char *file; -} bus_files[] = { - { .bus = "scsi", .file = "vendor" }, - { .bus = "usb", .file = "idVendor" }, - { .bus = "usb", .file = "iInterface" }, - { .bus = "usb-serial", .file = "detach_state" }, - { .bus = "ide", .file = "detach_state" }, - { .bus = "pci", .file = "vendor" }, - {} -}; - -static void wait_for_device_to_initialize(struct sysfs_device *sysfs_device) -{ - /* sleep until we see the file for this specific bus type show up this - * is needed because we can easily out-run the kernel in looking for - * these files before the paticular subsystem has created them in the - * sysfs tree properly. - * - * And people thought that the /sbin/hotplug event system was going to - * be slow, poo on you for arguing that before even testing it... - */ - struct bus_file *b = &bus_files[0]; - struct sysfs_attribute *tmpattr; - int found = 0; - int loop = WAIT_FOR_FILE_SECONDS * WAIT_FOR_FILE_RETRY_FREQ; - - while (1) { - if (b->bus == NULL) { - if (!found) - break; - /* give the kernel a chance to create the file */ - usleep(1000 * 1000 / WAIT_FOR_FILE_RETRY_FREQ); - --loop; - if (loop == 0) - break; - b = &bus_files[0]; - } - if (strcmp(sysfs_device->bus, b->bus) == 0) { - found = 1; - dbg("looking for file '%s' on bus '%s'", b->file, b->bus); - tmpattr = sysfs_get_device_attr(sysfs_device, b->file); - if (tmpattr) { - /* found it! */ - goto exit; - } - dbg("can't find '%s' file", b->file); - } - ++b; - } - if (!found) - dbg("did not find bus type '%s' on list of bus_id_files, " - "please report to ", - sysfs_device->bus); -exit: - return; /* here to prevent compiler warning... */ -} - static void fix_kernel_name(struct udevice *udev) { char *temp = udev->kernel_name; @@ -650,108 +587,6 @@ static int match_place(struct config_device *dev, struct sysfs_class_device *cla return 0; } -static int whitelist_search(struct sysfs_class_device *class_dev) -{ - char *sysblock = "/sys/block"; - int i; - - static char *list[] = { - "nb", - "ram", - "loop", - "fd", - "md", - "dos_cd", - "double", - "flash", - "msd", - "rflash", - "rom", - "rrom", - "sbpcd", - "pcd", - "pf", - "scd", - "ubd", - NULL, - }; - - if (strncmp(class_dev->path, sysblock, strlen(sysblock))) - return 0; - - for (i=0; list[i] != NULL; i++) - if (!strncmp(class_dev->name, list[i], strlen(list[i]))) - return 1; - - return 0; -} - -static struct sysfs_device *get_sysfs_device(struct sysfs_class_device *class_dev) -{ - struct sysfs_device *sysfs_device; - struct sysfs_class_device *class_dev_parent; - int loop; - - /* Figure out where the device symlink is at. For char devices this will - * always be in the class_dev->path. But for block devices, it's different. - * The main block device will have the device symlink in it's path, but - * all partitions have the symlink in its parent directory. - * But we need to watch out for block devices that do not have parents, yet - * look like a partition (fd0, loop0, etc.) They all do not have a device - * symlink yet. We do sit and spin on waiting for them right now unless - * they happen to be in the whitelist in which case we exit. - */ - class_dev_parent = sysfs_get_classdev_parent(class_dev); - if (class_dev_parent != NULL) - dbg("given class device has a parent, use this instead"); - - loop = WAIT_FOR_FILE_SECONDS * WAIT_FOR_FILE_RETRY_FREQ; - while (loop--) { - if (udev_sleep) { - if (whitelist_search(class_dev)) { - sysfs_device = NULL; - goto exit; - } - usleep(1000 * 1000 / WAIT_FOR_FILE_RETRY_FREQ); - } - - if (class_dev_parent) - sysfs_device = sysfs_get_classdev_device(class_dev_parent); - else - sysfs_device = sysfs_get_classdev_device(class_dev); - if (sysfs_device != NULL) - goto device_found; - } - dbg("timed out waiting for device symlink, continuing on anyway..."); - -device_found: - /* We have another issue with just the wait above - the sysfs part of - * the kernel may not be quick enough to have created the link to the - * device under the "bus" subsystem. Due to this, the sysfs_device->bus - * will not contain the actual bus name :( - */ - if (sysfs_device) { - if (sysfs_device->bus[0] != '\0') - goto bus_found; - - while (loop--) { - if (udev_sleep) - usleep(1000 * 1000 / WAIT_FOR_FILE_RETRY_FREQ); - sysfs_get_device_bus(sysfs_device); - - if (sysfs_device->bus[0] != '\0') - goto bus_found; - } - dbg("timed out waiting to find the device bus, continuing on anyway"); - goto exit; -bus_found: - dbg("device %s is registered with bus '%s'", - sysfs_device->name, sysfs_device->bus); - } -exit: - return sysfs_device; -} - static int match_rule(struct config_device *dev, struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device) { while (1) { @@ -859,6 +694,7 @@ try_parent: int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *udev) { + struct sysfs_class_device *class_dev_parent; struct sysfs_device *sysfs_device = NULL; struct config_device *dev; struct perm_device *perm; @@ -866,17 +702,26 @@ int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *ud char *pos; udev->mode = 0; + dbg("class_dev->name='%s'", class_dev->name); + + /* Figure out where the "device"-symlink is at. For char devices this will + * always be in the class_dev->path. On block devices, only the main block + * device will have the device symlink in it's path. All partition devices + * need to look at the symlink in its parent directory. + */ + class_dev_parent = sysfs_get_classdev_parent(class_dev); + if (class_dev_parent != NULL) { + dbg("given class device has a parent, use this instead"); + sysfs_device = sysfs_get_classdev_device(class_dev_parent); + } else { + sysfs_device = sysfs_get_classdev_device(class_dev); + } - /* find the sysfs_device associated with this class device */ - sysfs_device = get_sysfs_device(class_dev); if (sysfs_device) { - dbg("sysfs_device->path='%s'", sysfs_device->path); - dbg("sysfs_device->bus_id='%s'", sysfs_device->bus_id); - dbg("sysfs_device->bus='%s'", sysfs_device->bus); + dbg("found /device-device: path='%s', bus_id='%s', bus='%s'", + sysfs_device->path, sysfs_device->bus_id, sysfs_device->bus); strfieldcpy(udev->bus_id, sysfs_device->bus_id); - wait_for_device_to_initialize(sysfs_device); } - dbg("class_dev->name = '%s'", class_dev->name); strfieldcpy(udev->kernel_name, class_dev->name); fix_kernel_name(udev); diff --git a/udev.8.in b/udev.8.in index 9c22f8aa6..c842e7bef 100644 --- a/udev.8.in +++ b/udev.8.in @@ -20,13 +20,6 @@ Overrides the default location of the .B udev config file. .TP -.B UDEV_NO_SLEEP -The default behavior of -.B udev -is to wait until all the sysfs files of the device chain are populated. If set, -.B udev -will continue, regardless of the state of the device representation. -.TP .B UDEV_NO_DEVD The default behavior of .B udev diff --git a/udev.c b/udev.c index a13f7013b..d98a01739 100644 --- a/udev.c +++ b/udev.c @@ -75,14 +75,34 @@ static void asmlinkage sig_handler(int signum) } } -static char *subsystem_blacklist[] = { - "scsi_host", - "scsi_device", - "usb_host", - "pci_bus", - "pcmcia_socket", - "" -}; +/* list of subsystems we don't care about. not listing such systems here + * is not critical, but it makes it faster as we don't look for the "dev" file + */ +static int subsystem_without_dev(const char *subsystem) +{ + char *subsystem_blacklist[] = { + "scsi_host", + "scsi_device", + "usb_host", + "pci_bus", + "pcmcia_socket", + "bluetooth", + "i2c-adapter", + "pci_bus", + "ieee1394", + "ieee1394_host", + "ieee1394_node", + NULL + }; + char **subsys; + + for (subsys = subsystem_blacklist; *subsys != NULL; subsys++) { + if (strcmp(subsystem, *subsys) == 0) + return 1; + } + + return 0; +} int main(int argc, char *argv[], char *envp[]) { @@ -92,7 +112,6 @@ int main(int argc, char *argv[], char *envp[]) char *action; char *devpath = ""; char *subsystem = ""; - int i; int retval = -EINVAL; enum { ADD, @@ -143,20 +162,16 @@ int main(int argc, char *argv[], char *envp[]) } /* skip blacklisted subsystems */ - i = 0; - while (subsystem_blacklist[i][0] != '\0') { - if (strcmp(subsystem, subsystem_blacklist[i]) == 0) { - dbg("don't care about '%s' devices", subsystem); - goto exit; - } - i++; - } + if (subsystem_without_dev(subsystem)) { + dbg("don't care about '%s' devices", subsystem); + exit(0); + }; } /* set signal handlers */ act.sa_handler = (void (*) (int))sig_handler; sigemptyset (&act.sa_mask); - /* alarm must interrupt syscalls*/ + /* alarm must not restart syscalls*/ sigaction(SIGALRM, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); @@ -172,7 +187,6 @@ int main(int argc, char *argv[], char *envp[]) case UDEVSTART: dbg("udevstart"); namedev_init(); - udev_sleep = 0; retval = udev_start(); break; case ADD: diff --git a/udev.h b/udev.h index d66e9f626..642b30b51 100644 --- a/udev.h +++ b/udev.h @@ -27,8 +27,6 @@ #include "libsysfs/sysfs/libsysfs.h" #define ALARM_TIMEOUT 30 -#define WAIT_FOR_FILE_SECONDS 10 -#define WAIT_FOR_FILE_RETRY_FREQ 10 #define COMMENT_CHARACTER '#' #define NAME_SIZE 256 @@ -90,7 +88,6 @@ extern char default_mode_str[MODE_SIZE]; extern char default_owner_str[OWNER_SIZE]; extern char default_group_str[GROUP_SIZE]; extern int udev_log; -extern int udev_sleep; extern int udev_dev_d; #endif diff --git a/udev_add.c b/udev_add.c index 78c78a110..08257609a 100644 --- a/udev_add.c +++ b/udev_add.c @@ -52,14 +52,9 @@ #include "selinux.h" -/* - * Right now the major/minor of a device is stored in a file called - * "dev" in sysfs. - * The number is stored as: - * MM:mm - * MM is the major - * mm is the minor - * The value is in decimal. +/* + * the major/minor of a device is stored in a file called "dev" + * The number is stored in decimal values in the format: M:m */ static int get_major_minor(struct sysfs_class_device *class_dev, struct udevice *udev) { @@ -345,35 +340,6 @@ exit: return class_dev; } -/* wait for the "dev" file to show up in the directory in sysfs. - * If it doesn't happen in about 10 seconds, give up. - */ -static int sleep_for_file(const char *path, char* file) -{ - char filename[SYSFS_PATH_MAX + 6]; - int loop = WAIT_FOR_FILE_SECONDS * WAIT_FOR_FILE_RETRY_FREQ; - int retval; - - strfieldcpy(filename, sysfs_path); - strfieldcat(filename, path); - strfieldcat(filename, file); - - while (loop--) { - struct stat buf; - - dbg("looking for '%s'", filename); - retval = stat(filename, &buf); - if (retval == 0) - goto exit; - - /* sleep to give the kernel a chance to create the dev file */ - usleep(1000 * 1000 / WAIT_FOR_FILE_RETRY_FREQ); - } - retval = -ENODEV; -exit: - return retval; -} - static int rename_net_if(struct udevice *dev, int fake) { int sk; @@ -408,25 +374,11 @@ int udev_add_device(const char *path, const char *subsystem, int fake) struct udevice dev; char devpath[DEVPATH_SIZE]; char *pos; - int retval; + int retval = 0; memset(&dev, 0x00, sizeof(dev)); dev.type = get_device_type(path, subsystem); - switch (dev.type) { - case 'b': - case 'c': - retval = sleep_for_file(path, "/dev"); - break; - - case 'n': - retval = sleep_for_file(path, "/address"); - break; - - default: - dbg("unknown device type '%c'", dev.type); - return -1; - } class_dev = get_class_dev(path); if (class_dev == NULL) @@ -435,8 +387,8 @@ int udev_add_device(const char *path, const char *subsystem, int fake) if (dev.type == 'b' || dev.type == 'c') { retval = get_major_minor(class_dev, &dev); if (retval != 0) { - dbg("get_major_minor failed"); - goto exit; + dbg("no dev-file found, do nothing"); + goto close; } } @@ -484,6 +436,7 @@ int udev_add_device(const char *path, const char *subsystem, int fake) exit: selinux_restore(); +close: sysfs_close_class_device(class_dev); return retval; diff --git a/udev_config.c b/udev_config.c index ba2b3d2b8..ae755f39f 100644 --- a/udev_config.c +++ b/udev_config.c @@ -50,7 +50,6 @@ char default_mode_str[MODE_SIZE]; char default_owner_str[OWNER_SIZE]; char default_group_str[GROUP_SIZE]; int udev_log; -int udev_sleep; int udev_dev_d; @@ -79,11 +78,6 @@ static void init_variables(void) strfieldcpy(udev_permissions_filename, UDEV_PERMISSION_FILE); udev_log = string_is_true(UDEV_LOG_DEFAULT); - udev_sleep = 1; - env = getenv("UDEV_NO_SLEEP"); - if (env && string_is_true(env)) - udev_sleep = 0; - udev_dev_d = 1; env = getenv("UDEV_NO_DEVD"); if (env && string_is_true(env))