[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.
This commit is contained in:
kay.sievers@vrfy.org 2004-10-14 20:36:07 -07:00 committed by Greg KH
parent 32935a50ea
commit 707680b1cf
6 changed files with 59 additions and 263 deletions

193
namedev.c
View file

@ -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 <linux-hotplug-devel@lists.sourceforge.net>",
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);
/* 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);
strfieldcpy(udev->bus_id, sysfs_device->bus_id);
wait_for_device_to_initialize(sysfs_device);
/* 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);
}
if (sysfs_device) {
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);
}
dbg("class_dev->name = '%s'", class_dev->name);
strfieldcpy(udev->kernel_name, class_dev->name);
fix_kernel_name(udev);

View file

@ -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

52
udev.c
View file

@ -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:

3
udev.h
View file

@ -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

View file

@ -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;

View file

@ -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))