* [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 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).