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

Reply via email to