* [PATCH 1/2] libudev: modify sysfs attr caching behavior
@ 2011-03-03 9:17 Thomas Egerer
0 siblings, 0 replies; only message in thread
From: Thomas Egerer @ 2011-03-03 9:17 UTC (permalink / raw)
To: linux-hotplug
In order to get a complete list of sysfs attributes for a given
udev_device a complete list of all sysfs attributes is created on first
access (with values being empty). Values themselves are filled in, as
soon as a particular sysfs attribute is read.
Signed-off-by: Thomas Egerer <thomas.egerer@secunet.com>
---
libudev/libudev-device.c | 145 ++++++++++++++++++++++++++++++++--------------
1 files changed, 101 insertions(+), 44 deletions(-)
diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c
index 16bee19..5baff49 100644
--- a/libudev/libudev-device.c
+++ b/libudev/libudev-device.c
@@ -78,6 +78,7 @@ struct udev_device {
bool devlinks_uptodate;
bool envp_uptodate;
bool tags_uptodate;
+ bool sysattrs_cached;
bool driver_set;
bool info_loaded;
bool db_loaded;
@@ -1136,6 +1137,79 @@ void udev_device_set_usec_initialized(struct udev_device
*udev_device, unsigned
udev_device->usec_initialized = usec_initialized;
}
+static int cache_sysattrs(struct udev_device *udev_device)
+{
+ struct udev_list_entry *list_entry;
+ struct dirent *entry;
+ DIR *dir;
+ int num = 0;
+
+ if (udev_device = NULL)
+ return -1;
+ /* caching already done? */
+ if (true = udev_device->sysattrs_cached)
+ return 0;
+
+ dir = opendir(udev_device_get_syspath(udev_device));
+ if (!dir) {
+ dbg(udev_device->udev, "sysfs dir '%s' can not be opened\n",
+ udev_device_get_syspath(udev_device));
+ return -1;
+ }
+
+ while (NULL != (entry = readdir(dir))) {
+ char path[UTIL_PATH_SIZE];
+ struct stat statbuf;
+
+ /* only handle symlinks and regular files */
+ if (DT_LNK != entry->d_type && DT_REG != entry->d_type)
+ continue;
+
+ util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device),
+ "/", entry->d_name, NULL);
+ if (0 != lstat(path, &statbuf))
+ continue;
+
+ if (0 = (statbuf.st_mode & S_IRUSR))
+ continue;
+
+ if (DT_LNK = entry->d_type) {
+ /* symlink */
+ char target[UTIL_NAME_SIZE];
+ int len;
+ char *pos;
+
+ /* these values are cached immediately */
+ if (strcmp(entry->d_name, "driver") != 0 &&
+ strcmp(entry->d_name, "subsystem") != 0 &&
+ strcmp(entry->d_name, "module") != 0)
+ continue;
+
+ len = readlinkat(dirfd(dir), entry->d_name, target, sizeof(target));
+ if (len <= 0 || len = sizeof(target))
+ continue;
+ target[len] = '\0';
+
+ pos = strrchr(target, '/');
+ if (pos != NULL) {
+ pos = &pos[1];
+ dbg(udev_device->udev, "cache '%s' with link value '%s'\n", entry->d_name,
pos);
+ list_entry = udev_list_entry_add(udev_device->udev,
+ &udev_device->sysattr_list, entry->d_name, pos, 1, 0);
+ }
+ } else {
+ /* regular file */
+ dbg(udev_device->udev, "cache '%s' empty sysattr\n", entry->d_name);
+ list_entry = udev_list_entry_add(udev_device->udev,
+ &udev_device->sysattr_list, entry->d_name, NULL, 0, 0);
+ }
+ ++num;
+ }
+
+ udev_device->sysattrs_cached = true;
+ return num;
+}
+
/**
* udev_device_get_sysattr_value:
* @udev_device: udev device
@@ -1143,6 +1217,9 @@ void udev_device_set_usec_initialized(struct udev_device
*udev_device, unsigned
*
* The retrieved value is cached in the device. Repeated calls will return the same
* value and not open the attribute again.
+ * Upon first call a list of available sysfs attributes is assembled and saved in
+ * sysattr_list -- while the actual value of the sysattr is -- except for
symlinks --
+ * not read.
*
* Returns: the content of a sys attribute file, or #NULL if there is no sys
attribute value.
**/
@@ -1151,66 +1228,46 @@ const char *udev_device_get_sysattr_value(struct
udev_device *udev_device, const
struct udev_list_entry *list_entry;
char path[UTIL_PATH_SIZE];
char value[4096];
- struct stat statbuf;
int fd;
ssize_t size;
const char *val = NULL;
+ bool found = false;
if (udev_device = NULL)
return NULL;
if (sysattr = NULL)
return NULL;
- /* look for possibly already cached result */
+ /* perform initial caching of sysattr list */
+ if (!udev_device->sysattrs_cached) {
+ int ret;
+ ret = cache_sysattrs(udev_device);
+ if (0 > ret)
+ return NULL;
+ }
+
+ /* does the desired sysattr exist? */
udev_list_entry_foreach(list_entry,
udev_list_get_entry(&udev_device->sysattr_list)) {
if (strcmp(udev_list_entry_get_name(list_entry), sysattr) = 0) {
- dbg(udev_device->udev, "got '%s' (%s) from cache\n",
- sysattr, udev_list_entry_get_value(list_entry));
- return udev_list_entry_get_value(list_entry);
+ found = true;
+ val = udev_list_entry_get_value(list_entry);
+ break;
}
}
- util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/",
sysattr, NULL);
- if (lstat(path, &statbuf) != 0) {
- dbg(udev_device->udev, "no attribute '%s', keep negative entry\n", path);
- udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr,
NULL, 0, 0);
- goto out;
+ if (false = found) {
+ dbg(udev_device->udev, "no attribute '%s/%s' found\n",
+ udev_device_get_syspath(udev_device), sysattr);
+ return NULL;
}
- if (S_ISLNK(statbuf.st_mode)) {
- char target[UTIL_NAME_SIZE];
- int len;
- char *pos;
-
- /* some core links return the last element of the target path */
- if (strcmp(sysattr, "driver") != 0 &&
- strcmp(sysattr, "subsystem") != 0 &&
- strcmp(sysattr, "module") != 0)
- goto out;
-
- len = readlink(path, target, sizeof(target));
- if (len <= 0 || len = sizeof(target))
- goto out;
- target[len] = '\0';
-
- pos = strrchr(target, '/');
- if (pos != NULL) {
- pos = &pos[1];
- dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, pos);
- list_entry = udev_list_entry_add(udev_device->udev,
&udev_device->sysattr_list, sysattr, pos, 0, 0);
- val = udev_list_entry_get_value(list_entry);
- }
-
- goto out;
+ if (NULL != val) {
+ dbg(udev_device->udev, "got '%s' (%s) from cache\n",
+ sysattr, udev_list_entry_get_value(list_entry));
+ return val;
}
- /* skip directories */
- if (S_ISDIR(statbuf.st_mode))
- goto out;
-
- /* skip non-readable files */
- if ((statbuf.st_mode & S_IRUSR) = 0)
- goto out;
+ util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/",
sysattr, NULL);
/* read attribute value */
fd = open(path, O_RDONLY|O_CLOEXEC);
@@ -1225,11 +1282,11 @@ const char *udev_device_get_sysattr_value(struct
udev_device *udev_device, const
if (size = sizeof(value))
goto out;
- /* got a valid value, store it in cache and return it */
+ /* got a valid value, update in cache and return it */
value[size] = '\0';
util_remove_trailing_chars(value, '\n');
dbg(udev_device->udev, "'%s' has attribute value '%s'\n", path, value);
- list_entry = udev_list_entry_add(udev_device->udev,
&udev_device->sysattr_list, sysattr, value, 0, 0);
+ list_entry = udev_list_entry_add(udev_device->udev,
&udev_device->sysattr_list, sysattr, value, 1, 0);
val = udev_list_entry_get_value(list_entry);
out:
return val;
--
1.7.2.2
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2011-03-03 9:17 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-03 9:17 [PATCH 1/2] libudev: modify sysfs attr caching behavior Thomas Egerer
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.