From: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
To: linux-hotplug@vger.kernel.org
Subject: [PATCH 3/3] sysfs: add explicit sysfs_cache object
Date: Thu, 04 Sep 2008 14:22:54 +0000 [thread overview]
Message-ID: <48BFEF3E.3070006@tuffmail.co.uk> (raw)
The implicit caching in sysfs is unsuitable for long-lived programs;
it would fill up with stale data. Fortunately libudev doesn't use the
relevant functions, but this is not very clear.
Add an explicit sysfs_cache parameter to the relevant functions
(sysfs_attr_get_value, sysfs_device_get and variants). The parameter
can be NULL for no caching.
sysfs_device objects returned by these functions must now be explicitly
released by calling sysfs_device_cleanup().
This makes traversing parent devices quite hairy, so we hide the details in
udev_device_parent_iter_*.
diff --git a/extras/usb_id/usb_id.c b/extras/usb_id/usb_id.c
index fd4d2f2..f8e38f0 100644
--- a/extras/usb_id/usb_id.c
+++ b/extras/usb_id/usb_id.c
@@ -228,33 +228,34 @@ static int usb_id(const char *devpath)
char if_subclass[NAME_SIZE];
int if_class_num;
int protocol = 0;
+ int retval = 1;
int status;
dbg("devpath %s\n", devpath);
/* get all usb specific information: dev_interface, if_class, dev_usb */
- dev = sysfs_device_get(devpath);
+ dev = sysfs_device_get(NULL, devpath);
if (dev = NULL) {
err("unable to access '%s'\n", devpath);
- return 1;
+ goto out;
}
/* usb interface directory */
- dev_interface = sysfs_device_get_parent_with_subsystem(dev, "usb");
+ dev_interface = sysfs_device_get_parent_with_subsystem(NULL, dev, "usb");
if (dev_interface = NULL) {
info("unable to access usb_interface device of '%s'\n", devpath);
- return 1;
+ goto out;
}
- status = sysfs_attr_get_value(dev_interface->devpath, "bInterfaceClass",
+ status = sysfs_attr_get_value(NULL, dev_interface->devpath, "bInterfaceClass",
if_class, sizeof(if_class));
if (!status) {
info("%s: cannot get bInterfaceClass attribute\n", dev_interface->kernel);
- return 1;
+ goto out;
}
if_class_num = strtoul(if_class, NULL, 16);
if (if_class_num = 8) {
- status = sysfs_attr_get_value(dev_interface->devpath, "bInterfaceSubClass",
+ status = sysfs_attr_get_value(NULL, dev_interface->devpath, "bInterfaceSubClass",
if_subclass, sizeof(if_subclass));
if (!status)
protocol = set_usb_mass_storage_ifsubtype(type_str, if_subclass, sizeof(type_str)-1);
@@ -264,10 +265,10 @@ static int usb_id(const char *devpath)
info("%s: if_class %d protocol %d\n", dev_interface->devpath, if_class_num, protocol);
/* usb device directory */
- dev_usb = sysfs_device_get_parent_with_subsystem(dev_interface, "usb");
+ dev_usb = sysfs_device_get_parent_with_subsystem(NULL, dev_interface, "usb");
if (!dev_usb) {
info("unable to find parent 'usb' device of '%s'\n", devpath);
- return 1;
+ goto out;
}
/* mass storage */
@@ -280,7 +281,7 @@ static int usb_id(const char *devpath)
int host, bus, target, lun;
/* get scsi device */
- dev_scsi = sysfs_device_get_parent_with_subsystem(dev, "scsi");
+ dev_scsi = sysfs_device_get_parent_with_subsystem(NULL, dev, "scsi");
if (dev_scsi = NULL) {
info("unable to find parent 'scsi' device of '%s'\n", devpath);
goto fallback;
@@ -291,7 +292,7 @@ static int usb_id(const char *devpath)
}
/* Generic SPC-2 device */
- status = sysfs_attr_get_value(dev_scsi->devpath, "vendor",
+ status = sysfs_attr_get_value(NULL, dev_scsi->devpath, "vendor",
scsi_vendor, sizeof(scsi_vendor));
if (!status) {
info("%s: cannot get SCSI vendor attribute\n", dev_scsi->kernel);
@@ -299,7 +300,7 @@ static int usb_id(const char *devpath)
}
set_str(vendor_str, scsi_vendor, sizeof(vendor_str)-1);
- status = sysfs_attr_get_value(dev_scsi->devpath, "model",
+ status = sysfs_attr_get_value(NULL, dev_scsi->devpath, "model",
scsi_model, sizeof(scsi_model));
if (!status) {
info("%s: cannot get SCSI model attribute\n", dev_scsi->kernel);
@@ -307,7 +308,7 @@ static int usb_id(const char *devpath)
}
set_str(model_str, scsi_model, sizeof(model_str)-1);
- status = sysfs_attr_get_value(dev_scsi->devpath, "type",
+ status = sysfs_attr_get_value(NULL, dev_scsi->devpath, "type",
scsi_type, sizeof(scsi_type));
if (!status) {
info("%s: cannot get SCSI type attribute\n", dev_scsi->kernel);
@@ -315,7 +316,7 @@ static int usb_id(const char *devpath)
}
set_scsi_type(type_str, scsi_type, sizeof(type_str)-1);
- status = sysfs_attr_get_value(dev_scsi->devpath, "rev",
+ status = sysfs_attr_get_value(NULL, dev_scsi->devpath, "rev",
scsi_rev, sizeof(scsi_rev));
if (!status) {
info("%s: cannot get SCSI revision attribute\n", dev_scsi->kernel);
@@ -337,16 +338,16 @@ fallback:
status = 0;
if (!use_num_info)
- status = sysfs_attr_get_value(dev_usb->devpath, "manufacturer",
+ status = sysfs_attr_get_value(NULL, dev_usb->devpath, "manufacturer",
usb_vendor, sizeof(usb_vendor));
if (!status)
- status = sysfs_attr_get_value(dev_usb->devpath, "idVendor",
+ status = sysfs_attr_get_value(NULL, dev_usb->devpath, "idVendor",
usb_vendor, sizeof(usb_vendor));
if (!status) {
info("No USB vendor information available\n");
- return 1;
+ goto out;
}
set_str(vendor_str, usb_vendor, sizeof(vendor_str)-1);
}
@@ -356,16 +357,16 @@ fallback:
status = 0;
if (!use_num_info)
- status = sysfs_attr_get_value(dev_usb->devpath, "product",
+ status = sysfs_attr_get_value(NULL, dev_usb->devpath, "product",
usb_model, sizeof(usb_model));
if (!status)
- status = sysfs_attr_get_value(dev_usb->devpath, "idProduct",
+ status = sysfs_attr_get_value(NULL, dev_usb->devpath, "idProduct",
usb_model, sizeof(usb_model));
if (!status) {
dbg("No USB model information available\n");
- return 1;
+ goto out;
}
set_str(model_str, usb_model, sizeof(model_str)-1);
}
@@ -373,7 +374,7 @@ fallback:
if (revision_str[0] = '\0') {
char usb_rev[NAME_SIZE];
- status = sysfs_attr_get_value(dev_usb->devpath, "bcdDevice",
+ status = sysfs_attr_get_value(NULL, dev_usb->devpath, "bcdDevice",
usb_rev, sizeof(usb_rev));
if (status)
set_str(revision_str, usb_rev, sizeof(revision_str)-1);
@@ -382,12 +383,20 @@ fallback:
if (serial_str[0] = '\0') {
char usb_serial[NAME_SIZE];
- status = sysfs_attr_get_value(dev_usb->devpath, "serial",
+ status = sysfs_attr_get_value(NULL, dev_usb->devpath, "serial",
usb_serial, sizeof(usb_serial));
if (status)
set_str(serial_str, usb_serial, sizeof(serial_str)-1);
}
- return 0;
+
+ /* success */
+ retval = 0;
+
+out:
+ sysfs_device_cleanup(dev);
+ sysfs_device_cleanup(dev_interface);
+ sysfs_device_cleanup(dev_usb);
+ return retval;
}
int main(int argc, char **argv)
diff --git a/udev/test-udev.c b/udev/test-udev.c
index 07628f7..878c477 100644
--- a/udev/test-udev.c
+++ b/udev/test-udev.c
@@ -62,7 +62,6 @@ static void asmlinkage sig_handler(int signum)
int main(int argc, char *argv[])
{
- struct sysfs_device *dev;
struct udevice *udev;
const char *maj, *min;
struct udev_rules rules;
@@ -133,18 +132,23 @@ int main(int argc, char *argv[])
sysfs_init();
udev_rules_init(&rules, 0);
- dev = sysfs_device_get(devpath);
- if (dev = NULL) {
- info("unable to open '%s'\n", devpath);
- goto fail;
- }
-
udev = udev_device_init();
if (udev = NULL)
goto fail;
+ /* valgrind can only verify sysfs_device_cleanup() calls if cache is disabled */
+#if 0
+ udev->cache = sysfs_cache_init();
+ if (udev->cache = NULL)
+ goto fail;
+#endif
+
/* override built-in sysfs device */
- udev->dev = dev;
+ udev->dev = sysfs_device_get(udev->cache, devpath);
+ if (udev->dev = NULL) {
+ info("unable to open '%s'\n", devpath);
+ goto fail;
+ }
strlcpy(udev->action, action, sizeof(udev->action));
/* get dev_t from environment, which is needed for "remove" to work, "add" works also from sysfs */
@@ -164,8 +168,8 @@ int main(int argc, char *argv[])
if (retval = 0 && !udev->ignore_device && udev_run)
udev_rules_run(udev);
- udev_device_cleanup(udev);
fail:
+ udev_device_cleanup(udev);
udev_rules_cleanup(&rules);
sysfs_cleanup();
selinux_exit();
diff --git a/udev/udev.h b/udev/udev.h
index 28b59db..1037734 100644
--- a/udev/udev.h
+++ b/udev/udev.h
@@ -48,9 +48,13 @@
struct udev_rules;
+struct sysfs_cache {
+ struct list_head dev_list; /* device cache */
+ struct list_head attr_list; /* attribute value cache */
+};
+
struct sysfs_device {
struct list_head node; /* for device cache */
- struct sysfs_device *parent; /* already cached parent*/
char devpath[PATH_SIZE];
char subsystem[NAME_SIZE]; /* $class, $bus, drivers, module */
char kernel[NAME_SIZE]; /* device instance name */
@@ -63,6 +67,7 @@ struct udevice {
struct sysfs_device *dev; /* points to dev_local by default */
struct sysfs_device dev_local;
struct sysfs_device *dev_parent; /* current parent device used for matching */
+ struct sysfs_cache *cache;
char action[NAME_SIZE];
char *devpath_old;
@@ -103,6 +108,9 @@ extern void udev_config_init(void);
/* udev_device.c */
extern struct udevice *udev_device_init(void);
extern void udev_device_cleanup(struct udevice *udev);
+extern void udev_device_parents_iter_init(struct udevice *udev, struct sysfs_device **iter);
+extern void udev_device_parents_iter_next(struct udevice *udev, struct sysfs_device **iter);
+extern void udev_device_parents_iter_cleanup(struct udevice *udev, struct sysfs_device **iter);
extern dev_t udev_device_get_devt(struct udevice *udev);
/* udev_device_event.c */
@@ -112,12 +120,17 @@ extern int udev_device_event(struct udev_rules *rules, struct udevice *udev);
extern char sysfs_path[PATH_SIZE];
extern int sysfs_init(void);
extern void sysfs_cleanup(void);
+extern struct sysfs_cache *sysfs_cache_init(void);
+extern void sysfs_cache_cleanup(struct sysfs_cache *cache);
extern void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
const char *subsystem, const char *driver);
-extern struct sysfs_device *sysfs_device_get(const char *devpath);
-extern struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev);
-extern struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem);
-extern int sysfs_attr_get_value(const char *devpath, const char *attr_name, char *value, size_t len);
+extern struct sysfs_device *sysfs_device_get(struct sysfs_cache *cache, const char *devpath);
+extern struct sysfs_device *sysfs_device_get_parent(struct sysfs_cache *cache, struct sysfs_device *dev);
+extern struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_cache *cache,
+ struct sysfs_device *dev, const char *subsystem);
+extern void sysfs_device_cleanup(struct sysfs_device *dev);
+int sysfs_attr_get_value(struct sysfs_cache *cache, const char *devpath, const char *attr_name,
+ char *value, size_t len);
extern int sysfs_resolve_link(char *path, size_t size);
extern int sysfs_lookup_devpath_by_subsys_id(char *devpath, size_t len, const char *subsystem, const char *id);
diff --git a/udev/udev_device.c b/udev/udev_device.c
index 13000b0..a81d80e 100644
--- a/udev/udev_device.c
+++ b/udev/udev_device.c
@@ -63,19 +63,46 @@ void udev_device_cleanup(struct udevice *udev)
{
if (udev = NULL)
return;
+ if (udev->dev != &udev->dev_local)
+ sysfs_device_cleanup(udev->dev);
+ udev_device_parents_iter_cleanup(udev, &udev->dev_parent);
+ sysfs_cache_cleanup(udev->cache);
name_list_cleanup(&udev->symlink_list);
name_list_cleanup(&udev->run_list);
name_list_cleanup(&udev->env_list);
free(udev);
}
+void udev_device_parents_iter_init(struct udevice *udev, struct sysfs_device **iter)
+{
+ *iter = udev->dev;
+}
+
+void udev_device_parents_iter_next(struct udevice *udev, struct sysfs_device **iter)
+{
+ struct sysfs_device *dev;
+
+ dev = *iter;
+ *iter = sysfs_device_get_parent(udev->cache, dev);
+
+ if (dev != udev->dev)
+ sysfs_device_cleanup(dev);
+}
+
+void udev_device_parents_iter_cleanup(struct udevice *udev, struct sysfs_device **iter)
+{
+ if (*iter != udev->dev)
+ sysfs_device_cleanup(*iter);
+ *iter = NULL;
+}
+
dev_t udev_device_get_devt(struct udevice *udev)
{
char attr[NAME_SIZE];
unsigned int maj, min;
/* read it from sysfs */
- if (sysfs_attr_get_value(udev->dev->devpath, "dev", attr, sizeof(attr))) {
+ if (sysfs_attr_get_value(udev->cache, udev->dev->devpath, "dev", attr, sizeof(attr))) {
if (sscanf(attr, "%u:%u", &maj, &min) = 2)
return makedev(maj, min);
}
diff --git a/udev/udev_node.c b/udev/udev_node.c
index a29c4b7..f489b67 100644
--- a/udev/udev_node.c
+++ b/udev/udev_node.c
@@ -380,7 +380,7 @@ int udev_node_add(struct udevice *udev)
int range;
/* take the maximum registered minor range */
- if (sysfs_attr_get_value(udev->dev->devpath, "range", attr, sizeof(attr))) {
+ if (sysfs_attr_get_value(udev->cache, udev->dev->devpath, "range", attr, sizeof(attr))) {
range = atoi(attr);
if (range > 1)
udev->partitions = range-1;
diff --git a/udev/udev_rules.c b/udev/udev_rules.c
index 53c483a..da7a62a 100644
--- a/udev/udev_rules.c
+++ b/udev/udev_rules.c
@@ -416,43 +416,45 @@ static int import_program_into_env(struct udevice *udev, const char *program)
static int import_parent_into_env(struct udevice *udev, const char *filter)
{
struct sysfs_device *dev_parent;
+ struct udevice *udev_parent;
+ struct name_entry *name_loop;
int rc = -1;
- dev_parent = sysfs_device_get_parent(udev->dev);
- if (dev_parent != NULL) {
- struct udevice *udev_parent;
- struct name_entry *name_loop;
+ dev_parent = sysfs_device_get_parent(udev->cache, udev->dev);
+ if (dev_parent = NULL)
+ goto out;
- dbg("found parent '%s', get the node name\n", dev_parent->devpath);
- udev_parent = udev_device_init();
- if (udev_parent = NULL)
- return -1;
- /* import the udev_db of the parent */
- if (udev_db_get_device(udev_parent, dev_parent->devpath) = 0) {
- dbg("import stored parent env '%s'\n", udev_parent->name);
- list_for_each_entry(name_loop, &udev_parent->env_list, node) {
- char name[NAME_SIZE];
- char *pos;
-
- strlcpy(name, name_loop->name, sizeof(name));
- pos = strchr(name, '=');
- if (pos) {
- pos[0] = '\0';
- pos++;
- if (fnmatch(filter, name, 0) = 0) {
- dbg("import key '%s'\n", name_loop->name);
- name_list_add(&udev->env_list, name_loop->name, 0);
- setenv(name, pos, 1);
- } else
- dbg("skip key '%s'\n", name_loop->name);
- }
+ dbg("found parent '%s', get the node name\n", dev_parent->devpath);
+ udev_parent = udev_device_init();
+ if (udev_parent = NULL)
+ goto out;
+ /* import the udev_db of the parent */
+ if (udev_db_get_device(udev_parent, dev_parent->devpath) = 0) {
+ dbg("import stored parent env '%s'\n", udev_parent->name);
+ list_for_each_entry(name_loop, &udev_parent->env_list, node) {
+ char name[NAME_SIZE];
+ char *pos;
+
+ strlcpy(name, name_loop->name, sizeof(name));
+ pos = strchr(name, '=');
+ if (pos) {
+ pos[0] = '\0';
+ pos++;
+ if (fnmatch(filter, name, 0) = 0) {
+ dbg("import key '%s'\n", name_loop->name);
+ name_list_add(&udev->env_list, name_loop->name, 0);
+ setenv(name, pos, 1);
+ } else
+ dbg("skip key '%s'\n", name_loop->name);
}
- rc = 0;
- } else
- dbg("parent not found in database\n");
- udev_device_cleanup(udev_parent);
- }
+ }
+ rc = 0;
+ } else
+ dbg("parent not found in database\n");
+ udev_device_cleanup(udev_parent);
+out:
+ sysfs_device_cleanup(dev_parent);
return rc;
}
@@ -834,7 +836,7 @@ found:
if (attr_get_by_subsys_id(attr, devpath, sizeof(devpath), &attrib)) {
if (attrib != NULL)
- found = sysfs_attr_get_value(devpath, attrib,
+ found = sysfs_attr_get_value(udev->cache, devpath, attrib,
temp2, sizeof(temp2));
else
break;
@@ -842,20 +844,23 @@ found:
/* try the current device, other matches may have selected */
if (!found && udev->dev_parent != NULL && udev->dev_parent != udev->dev)
- found = sysfs_attr_get_value(udev->dev_parent->devpath, attr,
+ found = sysfs_attr_get_value(udev->cache, udev->dev_parent->devpath, attr,
temp2, sizeof(temp2));
/* look at all devices along the chain of parents */
if (!found) {
- struct sysfs_device *dev_parent = udev->dev;
+ struct sysfs_device *dev_parent;
+ udev_device_parents_iter_init(udev, &dev_parent);
do {
dbg("looking at '%s'\n", dev_parent->devpath);
- found = sysfs_attr_get_value(dev_parent->devpath, attr,
+ found = sysfs_attr_get_value(udev->cache, dev_parent->devpath, attr,
temp2, sizeof(temp2));
if (found)
break;
- dev_parent = sysfs_device_get_parent(dev_parent);
+ udev_device_parents_iter_next(udev, &dev_parent);
} while (dev_parent != NULL);
+
+ udev_device_parents_iter_cleanup(udev, &dev_parent);
}
if (!found)
@@ -876,7 +881,7 @@ found:
{
struct sysfs_device *dev_parent;
- dev_parent = sysfs_device_get_parent(udev->dev);
+ dev_parent = sysfs_device_get_parent(udev->cache, udev->dev);
if (dev_parent != NULL) {
struct udevice *udev_parent;
@@ -891,6 +896,7 @@ found:
dbg("parent not found in database\n");
udev_device_cleanup(udev_parent);
}
+ sysfs_device_cleanup(dev_parent);
}
}
break;
@@ -1142,13 +1148,13 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule)
if (attr_get_by_subsys_id(key_name, devpath, sizeof(devpath), &attrib)) {
if (attrib != NULL)
- found = sysfs_attr_get_value(devpath, attrib,
+ found = sysfs_attr_get_value(udev->cache, devpath, attrib,
val, sizeof(val));
else
goto nomatch;
}
if (!found)
- found = sysfs_attr_get_value(udev->dev->devpath, key_name,
+ found = sysfs_attr_get_value(udev->cache, udev->dev->devpath, key_name,
val, sizeof(val));
if (!found)
goto nomatch;
@@ -1168,7 +1174,8 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule)
}
/* walk up the chain of parent devices and find a match */
- udev->dev_parent = udev->dev;
+ udev_device_parents_iter_cleanup(udev, &udev->dev_parent);
+ udev_device_parents_iter_init(udev, &udev->dev_parent);
while (1) {
/* check for matching kernel device name */
if (match_key("KERNELS", rule, &rule->kernels, udev->dev_parent->kernel))
@@ -1194,10 +1201,10 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule)
size_t len;
int found;
- found = sysfs_attr_get_value(udev->dev_parent->devpath, key_name,
+ found = sysfs_attr_get_value(udev->cache, udev->dev_parent->devpath, key_name,
val, sizeof(val));
if (!found)
- found = sysfs_attr_get_value(udev->dev->devpath, key_name,
+ found = sysfs_attr_get_value(udev->cache, udev->dev->devpath, key_name,
val, sizeof(val));
if (!found)
goto try_parent;
@@ -1221,7 +1228,8 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule)
try_parent:
/* move to parent device */
dbg("try parent sysfs device\n");
- udev->dev_parent = sysfs_device_get_parent(udev->dev_parent);
+ udev_device_parents_iter_next(udev, &udev->dev_parent);
+
if (udev->dev_parent = NULL)
goto nomatch;
dbg("looking at dev_parent->devpath='%s'\n", udev->dev_parent->devpath);
diff --git a/udev/udev_sysfs.c b/udev/udev_sysfs.c
index 2d2457f..4028f7e 100644
--- a/udev/udev_sysfs.c
+++ b/udev/udev_sysfs.c
@@ -31,11 +31,6 @@
char sysfs_path[PATH_SIZE];
-/* device cache */
-static LIST_HEAD(dev_list);
-
-/* attribute value cache */
-static LIST_HEAD(attr_list);
struct sysfs_attr {
struct list_head node;
char path[PATH_SIZE];
@@ -55,27 +50,48 @@ int sysfs_init(void)
strlcpy(sysfs_path, "/sys", sizeof(sysfs_path));
dbg("sysfs_path='%s'\n", sysfs_path);
- INIT_LIST_HEAD(&dev_list);
- INIT_LIST_HEAD(&attr_list);
return 0;
}
void sysfs_cleanup(void)
{
+}
+
+struct sysfs_cache *sysfs_cache_init()
+{
+ struct sysfs_cache *cache;
+
+ cache = malloc(sizeof(struct sysfs_cache));
+ if (cache = NULL)
+ return NULL;
+
+ INIT_LIST_HEAD(&cache->dev_list);
+ INIT_LIST_HEAD(&cache->attr_list);
+
+ return cache;
+}
+
+void sysfs_cache_cleanup(struct sysfs_cache *cache)
+{
struct sysfs_attr *attr_loop;
struct sysfs_attr *attr_temp;
struct sysfs_device *dev_loop;
struct sysfs_device *dev_temp;
- list_for_each_entry_safe(attr_loop, attr_temp, &attr_list, node) {
+ if (cache = NULL)
+ return;
+
+ list_for_each_entry_safe(attr_loop, attr_temp, &cache->attr_list, node) {
list_del(&attr_loop->node);
free(attr_loop);
}
- list_for_each_entry_safe(dev_loop, dev_temp, &dev_list, node) {
+ list_for_each_entry_safe(dev_loop, dev_temp, &cache->dev_list, node) {
list_del(&dev_loop->node);
free(dev_loop);
}
+
+ free(cache);
}
void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
@@ -144,7 +160,7 @@ int sysfs_resolve_link(char *devpath, size_t size)
return 0;
}
-struct sysfs_device *sysfs_device_get(const char *devpath)
+struct sysfs_device *sysfs_device_get(struct sysfs_cache *cache, const char *devpath)
{
char path[PATH_SIZE];
char devpath_real[PATH_SIZE];
@@ -173,12 +189,14 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
return NULL;
/* look for device already in cache (we never put an untranslated path in the cache) */
- list_for_each_entry(dev_loop, &dev_list, node) {
+ if (cache != NULL) {
+ list_for_each_entry(dev_loop, &cache->dev_list, node) {
if (strcmp(dev_loop->devpath, devpath_real) = 0) {
dbg("found in cache '%s'\n", dev_loop->devpath);
return dev_loop;
}
}
+ }
/* if we got a link, resolve it to the real device */
strlcpy(path, sysfs_path, sizeof(path));
@@ -192,13 +210,15 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
return NULL;
/* now look for device in cache after path translation */
- list_for_each_entry(dev_loop, &dev_list, node) {
+ if (cache != NULL) {
+ list_for_each_entry(dev_loop, &cache->dev_list, node) {
if (strcmp(dev_loop->devpath, devpath_real) = 0) {
dbg("found in cache '%s'\n", dev_loop->devpath);
return dev_loop;
}
}
}
+ }
/* it is a new device */
dbg("new uncached device '%s'\n", devpath_real);
@@ -252,23 +272,22 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
strlcpy(dev->driver, &pos[1], sizeof(dev->driver));
}
- dbg("add to cache 'devpath=%s', subsystem='%s', driver='%s'\n", dev->devpath, dev->subsystem, dev->driver);
- list_add(&dev->node, &dev_list);
+ dbg("cache 'devpath=%s', subsystem='%s', driver='%s'\n", dev->devpath, dev->subsystem, dev->driver);
+ if (cache != NULL)
+ list_add(&dev->node, &cache->dev_list);
+ else
+ INIT_LIST_HEAD(&dev->node);
return dev;
}
-struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
+struct sysfs_device *sysfs_device_get_parent(struct sysfs_cache *cache, struct sysfs_device *dev)
{
char parent_devpath[PATH_SIZE];
char *pos;
dbg("open '%s'\n", dev->devpath);
- /* look if we already know the parent */
- if (dev->parent != NULL)
- return dev->parent;
-
strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
dbg("'%s'\n", parent_devpath);
@@ -295,9 +314,8 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
if (pos = NULL || pos = parent_devpath)
return NULL;
- /* get parent and remember it */
- dev->parent = sysfs_device_get(parent_devpath);
- return dev->parent;
+ /* get parent */
+ return sysfs_device_get(cache, parent_devpath);
device_link:
strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
@@ -305,25 +323,38 @@ device_link:
if (sysfs_resolve_link(parent_devpath, sizeof(parent_devpath)) != 0)
return NULL;
- /* get parent and remember it */
- dev->parent = sysfs_device_get(parent_devpath);
- return dev->parent;
+ /* get parent */
+ return sysfs_device_get(cache, parent_devpath);
}
-struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem)
+struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_cache *cache,
+ struct sysfs_device *dev, const char *subsystem)
{
struct sysfs_device *dev_parent;
- dev_parent = sysfs_device_get_parent(dev);
+ dev_parent = sysfs_device_get_parent(cache, dev);
while (dev_parent != NULL) {
if (strcmp(dev_parent->subsystem, subsystem) = 0)
return dev_parent;
- dev_parent = sysfs_device_get_parent(dev_parent);
+ dev_parent = sysfs_device_get_parent(cache, dev_parent);
}
return NULL;
}
-int sysfs_attr_get_value(const char *devpath, const char *attr_name, char *value, size_t len)
+void sysfs_device_cleanup(struct sysfs_device *dev)
+{
+ if (dev = NULL)
+ return;
+
+ /* device is on a dev_list - will be freed by sysfs_cache_cleanup() */
+ if (!list_empty(&dev->node))
+ return;
+
+ free(dev);
+}
+
+int sysfs_attr_get_value(struct sysfs_cache *cache, const char *devpath, const char *attr_name,
+ char *value, size_t len)
{
char path_full[PATH_SIZE];
const char *path;
@@ -345,7 +376,8 @@ int sysfs_attr_get_value(const char *devpath, const char *attr_name, char *value
strlcat(path_full, attr_name, sizeof(path_full));
/* look for attribute in cache */
- list_for_each_entry(attr_loop, &attr_list, node) {
+ if (cache != NULL) {
+ list_for_each_entry(attr_loop, &cache->attr_list, node) {
if (strcmp(attr_loop->path, path) = 0) {
dbg("found in cache '%s'\n", attr_loop->path);
if (!attr_loop->value)
@@ -364,7 +396,8 @@ int sysfs_attr_get_value(const char *devpath, const char *attr_name, char *value
memset(attr, 0x00, sizeof(struct sysfs_attr));
strlcpy(attr->path, path, sizeof(attr->path));
dbg("add to cache '%s'\n", path_full);
- list_add(&attr->node, &attr_list);
+ list_add(&attr->node, &cache->attr_list);
+ }
if (lstat(path_full, &statbuf) != 0) {
dbg("stat '%s' failed: %s\n", path_full, strerror(errno));
@@ -417,9 +450,11 @@ int sysfs_attr_get_value(const char *devpath, const char *attr_name, char *value
remove_trailing_chars(val, '\n');
out:
- strlcpy(attr->value_local, val, sizeof(attr->value_local));
- attr->value = attr->value_local;
- dbg("cache '%s' with link value '%s'\n", path_full, attr->value);
+ if (cache != NULL) {
+ strlcpy(attr->value_local, val, sizeof(attr->value_local));
+ attr->value = attr->value_local;
+ dbg("cache '%s' with link value '%s'\n", path_full, attr->value);
+ }
if (strlcpy(value, val, len) > len-1)
return 0;
diff --git a/udev/udevinfo.c b/udev/udevinfo.c
index b76d11d..50d1bef 100644
--- a/udev/udevinfo.c
+++ b/udev/udevinfo.c
@@ -66,7 +66,7 @@ static void print_all_attributes(const char *devpath, const char *key)
if (S_ISLNK(statbuf.st_mode))
continue;
- if (!sysfs_attr_get_value(devpath, dent->d_name, value, sizeof(value)))
+ if (!sysfs_attr_get_value(NULL, devpath, dent->d_name, value, sizeof(value)))
continue;
len = strlen(value);
dbg("attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
@@ -89,7 +89,7 @@ static int print_device_chain(const char *devpath)
{
struct sysfs_device *dev;
- dev = sysfs_device_get(devpath);
+ dev = sysfs_device_get(NULL, devpath);
if (dev = NULL)
return -1;
@@ -109,9 +109,14 @@ static int print_device_chain(const char *devpath)
/* walk up the chain of devices */
while (1) {
- dev = sysfs_device_get_parent(dev);
- if (dev = NULL)
+ struct sysfs_device *dev_parent;
+
+ dev_parent = sysfs_device_get_parent(NULL, dev);
+ if (dev_parent = NULL)
break;
+ sysfs_device_cleanup(dev);
+ dev = dev_parent;
+
printf(" looking at parent device '%s':\n", dev->devpath);
printf(" KERNELS=\"%s\"\n", dev->kernel);
printf(" SUBSYSTEMS=\"%s\"\n", dev->subsystem);
@@ -120,6 +125,7 @@ static int print_device_chain(const char *devpath)
print_all_attributes(dev->devpath, "ATTRS");
}
+ sysfs_device_cleanup(dev);
return 0;
}
diff --git a/udev/udevtest.c b/udev/udevtest.c
index 63603aa..cf96019 100644
--- a/udev/udevtest.c
+++ b/udev/udevtest.c
@@ -78,7 +78,6 @@ int udevtest(int argc, char *argv[])
const char *subsystem = NULL;
const char *devpath = NULL;
struct udevice *udev;
- struct sysfs_device *dev;
struct udev_rules rules = {};
int retval;
int rc = 0;
@@ -150,25 +149,30 @@ int udevtest(int argc, char *argv[])
if (strncmp(devpath, sysfs_path, strlen(sysfs_path)) = 0)
devpath = &devpath[strlen(sysfs_path)];
- dev = sysfs_device_get(devpath);
- if (dev = NULL) {
- fprintf(stderr, "unable to open device '%s'\n", devpath);
+ udev = udev_device_init();
+ if (udev = NULL) {
+ fprintf(stderr, "error initializing device\n");
rc = 2;
goto exit;
}
- udev = udev_device_init();
- if (udev = NULL) {
- fprintf(stderr, "error initializing device\n");
+ udev->cache = sysfs_cache_init();
+ if (udev->cache = NULL) {
+ fprintf(stderr, "error initializing sysfs cache\n");
rc = 3;
goto exit;
}
+ /* override built-in sysfs device */
+ udev->dev = sysfs_device_get(udev->cache, devpath);
+ if (udev->dev = NULL) {
+ fprintf(stderr, "unable to open device '%s'\n", devpath);
+ rc = 4;
+ goto exit;
+ }
if (subsystem != NULL)
- strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem));
+ strlcpy(udev->dev->subsystem, subsystem, sizeof(udev->dev->subsystem));
- /* override built-in sysfs device */
- udev->dev = dev;
strlcpy(udev->action, action, sizeof(udev->action));
udev->devt = udev_device_get_devt(udev);
@@ -198,9 +202,9 @@ int udevtest(int argc, char *argv[])
info("run: '%s'\n", program);
}
}
- udev_device_cleanup(udev);
exit:
+ udev_device_cleanup(udev);
udev_rules_cleanup(&rules);
sysfs_cleanup();
return rc;
next reply other threads:[~2008-09-04 14:22 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-04 14:22 Alan Jenkins [this message]
2008-09-09 13:04 ` [PATCH 3/3] sysfs: add explicit sysfs_cache object Alan Jenkins
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=48BFEF3E.3070006@tuffmail.co.uk \
--to=alan-jenkins@tuffmail.co.uk \
--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).