Previously, ignore_device option had existed until udev 147. But that was removed after below commit.
cdae488a3fbca5a61b3f8ea0651730cfa2da9cb0 remove "ignore_device" There is no way to ignore an event these days. Libudev events can not be suppressed. It only prevents RUN keys from being executed, which results in an inconsistent behavior in current setups. http://cgit.freedesktop.org/systemd/systemd/commit/?id=cdae488a3fbca5a61b3f8ea0651730cfa2da9cb0 In mobile(maybe also embedded) world, power and memory management are big issue. That can not be compromised. If there are no tasks who receive such uevents from udev monitor(not kernel monitor) then the uevents are useless. Each uevent will may cause each fork() if there is no idle worker. In our system, there is a special daemon who directly linked with kernel monitor. (That is similar with system server of android.) He receive event data from kernel monitor. And some of events are only treated by him. Especially, backlight and power_supply(battery) events are. In every change state of LCD, backlight events were occurred. In desktop environment, this event may be occurred one or twice per hour. (Sure, it can configurable.) And, in every battery percentage changing, power_supply events were happen. (I couldn't see this on my fedora when using ac-power. I'm not sure it because of full charged stated.) Anyway, both of them are more frequently happen in mobile world. In our worst case, a uevent(a kind of thermistor) was happen each 10 second. If udev is in idle state, udev will fork to process that event. After processing(may be 3 sec), the worker will be terminated. There are no workers during 7 seconds. And worker will be forked again by the uevent. Yeah, it is a terrible repetition of our system. I want to skip this kind of events just after retrieving from netlink without worker fork. This patch will filter-out(I could not find suitable vocabulary because of we already using "filter".) subsystem:devtype events what be listed in udev.conf. If we want to skip whole of subsystem then subsystem can only be specified.
>From ccf8ddd0e6e276f5c36789109ec19fed1d63e3bf Mon Sep 17 00:00:00 2001 From: WaLyong Cho <[email protected]> Date: Mon, 11 Nov 2013 15:07:20 +0900 Subject: [PATCH] udev: add exclusive event filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If tasks receive uevents from kernel monitor (not udev monitor) and there are no tasks who receive event from udev monitor, then events can be useless in udev monitor. Those uevents will cause each fork(), so performance regression will occur. To solve this, udev filter-out is added what is similar with previous filter. Unfortunately, previous filter can use socket filter but the filter-out cannot use socket filter. So filter-out is performed in user level. Filter-out is defined at udev.conf and it will have <subsystem>:<devtype> form. And multiple field can be specified with comma(��,��) separator. devtype can be omitted and then it deems to NULL. In this case, regardless of event�셲 devtype, if subsystem matched the uevents will are filtered-out. If devtype also exist, then just only filtered-out when matched both of them. Change-Id: I159a68ce74743342c81e963bbaba0b76279a5608 Signed-off-by: WaLyong Cho <[email protected]> --- src/libudev/libudev-monitor.c | 72 ++++++++++++++++++- src/libudev/libudev-private.h | 5 ++ src/libudev/libudev.c | 157 ++++++++++++++++++++++------------------- src/udev/udev.conf | 1 + src/udev/udevd.c | 8 +++ 5 files changed, 169 insertions(+), 74 deletions(-) diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c index 0212792..61f1177 100644 --- a/src/libudev/libudev-monitor.c +++ b/src/libudev/libudev-monitor.c @@ -57,6 +57,7 @@ struct udev_monitor { union sockaddr_union snl_destination; socklen_t addrlen; struct udev_list filter_subsystem_list; + struct udev_list filter_out_subsystem_list; struct udev_list filter_tag_list; bool bound; }; @@ -101,6 +102,7 @@ static struct udev_monitor *udev_monitor_new(struct udev *udev) udev_monitor->refcount = 1; udev_monitor->udev = udev; udev_list_init(udev, &udev_monitor->filter_subsystem_list, false); + udev_list_init(udev, &udev_monitor->filter_out_subsystem_list, false); udev_list_init(udev, &udev_monitor->filter_tag_list, true); return udev_monitor; } @@ -306,6 +308,32 @@ _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) return err; } +int udev_monitor_filter_out_update(struct udev_monitor *udev_monitor, const char* args) +{ + char *state, *word; + size_t len; + int r; + + assert(args); + + FOREACH_WORD_SEPARATOR(word, len, args, ", ", state) { + _cleanup_free_ char *subsystem, *devtype = NULL, *copy; + size_t len_sub; + + copy = strndup(word, len); + len_sub = strcspn(copy, ":"); + subsystem = strndup(copy, len_sub); + if (len != len_sub) + devtype = strdup(copy+len_sub+1); + if (!subsystem) + return -ENOMEM; + r = udev_monitor_filter_out_add_match_subsystem_devtype(udev_monitor, subsystem, devtype); + if (r < 0) + return r; + } + return 0; +} + int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender) { udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid; @@ -420,6 +448,7 @@ _public_ struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monit if (udev_monitor->sock >= 0) close(udev_monitor->sock); udev_list_cleanup(&udev_monitor->filter_subsystem_list); + udev_list_cleanup(&udev_monitor->filter_out_subsystem_list); udev_list_cleanup(&udev_monitor->filter_tag_list); free(udev_monitor); return NULL; @@ -460,7 +489,7 @@ static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device * struct udev_list_entry *list_entry; if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL) - goto tag; + goto filter_out; udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) { const char *subsys = udev_list_entry_get_name(list_entry); const char *dsubsys = udev_device_get_subsystem(udev_device); @@ -472,15 +501,36 @@ static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device * devtype = udev_list_entry_get_value(list_entry); if (devtype == NULL) - goto tag; + goto filter_out; ddevtype = udev_device_get_devtype(udev_device); if (ddevtype == NULL) continue; if (streq(ddevtype, devtype)) - goto tag; + goto filter_out; } return 0; +filter_out: + if (udev_list_get_entry(&udev_monitor->filter_out_subsystem_list) == NULL) + goto tag; + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_out_subsystem_list)) { + const char *subsys = udev_list_entry_get_name(list_entry); + const char *dsubsys = udev_device_get_subsystem(udev_device); + const char *devtype; + const char *ddevtype; + + if (streq(dsubsys, subsys)) { + devtype = udev_list_entry_get_value(list_entry); + if (devtype == NULL) + return 0; + ddevtype = udev_device_get_devtype(udev_device); + if (ddevtype == NULL) + goto tag; + if (streq(ddevtype, devtype)) + return 0; + } + } + tag: if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) return 1; @@ -742,6 +792,17 @@ _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor return 0; } +int udev_monitor_filter_out_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) +{ + if (udev_monitor == NULL) + return -EINVAL; + if (subsystem == NULL) + return -EINVAL; + if (udev_list_entry_add(&udev_monitor->filter_out_subsystem_list, subsystem, devtype) == NULL) + return -ENOMEM; + return 0; +} + /** * udev_monitor_filter_add_match_tag: * @udev_monitor: the monitor @@ -780,3 +841,8 @@ _public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) udev_list_cleanup(&udev_monitor->filter_subsystem_list); return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); } + +void udev_monitor_filter_out_remove(struct udev_monitor *udev_monitor) +{ + udev_list_cleanup(&udev_monitor->filter_out_subsystem_list); +} diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h index 18bc853..c463ad2 100644 --- a/src/libudev/libudev-private.h +++ b/src/libudev/libudev-private.h @@ -52,6 +52,7 @@ void udev_log(struct udev *udev, int udev_get_rules_path(struct udev *udev, char **path[], usec_t *ts_usec[]); struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value); struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev); +int udev_config_parse(struct udev *udev, const char *name, char *value); /* libudev-device.c */ struct udev_device *udev_device_new(struct udev *udev); @@ -98,6 +99,10 @@ int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct int udev_monitor_send_device(struct udev_monitor *udev_monitor, struct udev_monitor *destination, struct udev_device *udev_device); struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd); +int udev_monitor_filter_out_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, + const char *subsystem, const char *devtype); +int udev_monitor_filter_out_update(struct udev_monitor *udev_monitor, const char* list); +void udev_monitor_filter_out_remove(struct udev_monitor *udev_monitor); /* libudev-list.c */ struct udev_list_node { diff --git a/src/libudev/libudev.c b/src/libudev/libudev.c index bc73a5a..f66fd6a 100644 --- a/src/libudev/libudev.c +++ b/src/libudev/libudev.c @@ -118,7 +118,7 @@ _public_ struct udev *udev_new(void) { struct udev *udev; const char *env; - FILE *f; + char *udev_log_level; udev = calloc(1, sizeof(struct udev)); if (udev == NULL) @@ -128,76 +128,11 @@ _public_ struct udev *udev_new(void) udev->log_priority = LOG_INFO; udev_list_init(udev, &udev->properties_list, true); - f = fopen("/etc/udev/udev.conf", "re"); - if (f != NULL) { - char line[UTIL_LINE_SIZE]; - int line_nr = 0; - - while (fgets(line, sizeof(line), f)) { - size_t len; - char *key; - char *val; - - line_nr++; - - /* find key */ - key = line; - while (isspace(key[0])) - key++; - - /* comment or empty line */ - if (key[0] == '#' || key[0] == '\0') - continue; - - /* split key/value */ - val = strchr(key, '='); - if (val == NULL) { - udev_err(udev, "missing <key>=<value> in /etc/udev/udev.conf[%i]; skip line\n", line_nr); - continue; - } - val[0] = '\0'; - val++; - - /* find value */ - while (isspace(val[0])) - val++; - - /* terminate key */ - len = strlen(key); - if (len == 0) - continue; - while (isspace(key[len-1])) - len--; - key[len] = '\0'; - - /* terminate value */ - len = strlen(val); - if (len == 0) - continue; - while (isspace(val[len-1])) - len--; - val[len] = '\0'; - - if (len == 0) - continue; - - /* unquote */ - if (val[0] == '"' || val[0] == '\'') { - if (val[len-1] != val[0]) { - udev_err(udev, "inconsistent quoting in /etc/udev/udev.conf[%i]; skip line\n", line_nr); - continue; - } - val[len-1] = '\0'; - val++; - } - - if (streq(key, "udev_log")) { - udev_set_log_priority(udev, util_log_priority(val)); - continue; - } - } - fclose(f); - } + /* parse udev_log in udev.conf */ + udev_log_level = calloc(1,UTIL_LINE_SIZE); + if (udev_config_parse(udev, "udev_log", udev_log_level)) + udev_set_log_priority(udev, util_log_priority(udev_log_level)); + free(udev_log_level); /* environment overrides config */ env = secure_getenv("UDEV_LOG"); @@ -312,3 +247,83 @@ struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev) { return udev_list_get_entry(&udev->properties_list); } + +int udev_config_parse(struct udev *udev, const char *name, char *value) +{ + FILE *f; + + if (udev == NULL) + return 0; + + f = fopen("/etc/udev/udev.conf", "re"); + if (f != NULL) { + char line[UTIL_LINE_SIZE]; + int line_nr = 0; + + while (fgets(line, sizeof(line), f)) { + size_t len; + char *key; + char *val; + + line_nr++; + + /* find key */ + key = line; + while (isspace(key[0])) + key++; + + /* comment or empty line */ + if (key[0] == '#' || key[0] == '\0') + continue; + + /* split key/value */ + val = strchr(key, '='); + if (val == NULL) { + udev_err(udev, "missing <key>=<value> in /etc/udev/udev.conf[%i]; skip line\n", line_nr); + continue; + } + val[0] = '\0'; + val++; + + /* find value */ + while (isspace(val[0])) + val++; + + /* terminate key */ + len = strlen(key); + if (len == 0) + continue; + while (isspace(key[len-1])) + len--; + key[len] = '\0'; + + /* terminate value */ + len = strlen(val); + if (len == 0) + continue; + while (isspace(val[len-1])) + len--; + val[len] = '\0'; + + if (len == 0) + continue; + + /* unquote */ + if (val[0] == '"' || val[0] == '\'') { + if (val[len-1] != val[0]) { + udev_err(udev, "inconsistent quoting in /etc/udev/udev.conf[%i]; skip line\n", line_nr); + continue; + } + val[len-1] = '\0'; + val++; + } + + if (streq(key, name)) { + strncpy(value,val,len); + return 1; + } + } + fclose(f); + } + return 0; +} diff --git a/src/udev/udev.conf b/src/udev/udev.conf index f39253e..16f41bb 100644 --- a/src/udev/udev.conf +++ b/src/udev/udev.conf @@ -1,3 +1,4 @@ # see udev(7) for details #udev_log="info" +#udev_ignore= diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 559d33e..39e11e9 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -919,6 +919,7 @@ int main(int argc, char *argv[]) struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_worker; struct udev_ctrl_connection *ctrl_conn = NULL; int rc = 1; + char *udev_ignore; udev = udev_new(); if (udev == NULL) @@ -1078,6 +1079,13 @@ int main(int argc, char *argv[]) udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024); + /* parse udev_ignore in udev.conf */ + udev_ignore = calloc(1,UTIL_LINE_SIZE); + if (udev_config_parse(udev, "udev_ignore", udev_ignore)) + if (udev_monitor_filter_out_update(monitor, udev_ignore) < 0) + log_debug("error filter out update\n"); + free(udev_ignore); + /* create queue file before signalling 'ready', to make sure we block 'settle' */ udev_queue_export = udev_queue_export_new(udev); if (udev_queue_export == NULL) { -- 1.7.9.5
_______________________________________________ systemd-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/systemd-devel
