[dm-devel] [PATCH] multipath: enable getting uevents through libudev
Zdenek Kabelac
zkabelac at redhat.com
Wed Apr 4 11:12:45 UTC 2012
Dne 4.4.2012 01:42, Benjamin Marzinski napsal(a):
> udev is removing support for RUN+="socket:..." rules. For now, I've kept
> all the existing uevent code, but I've added a new method for getting the
> uevent information using libudev that will be tried first.
>
> Signed-off-by: Benjamin Marzinski<bmarzins at redhat.com>
> ---
> libmultipath/Makefile | 2
> libmultipath/uevent.c | 151 ++++++++++++++++++++++++++++++++++++++++++++------
> 2 files changed, 134 insertions(+), 19 deletions(-)
>
> Index: multipath-tools-120123/libmultipath/Makefile
> ===================================================================
> --- multipath-tools-120123.orig/libmultipath/Makefile
> +++ multipath-tools-120123/libmultipath/Makefile
> @@ -7,7 +7,7 @@ include ../Makefile.inc
> SONAME=0
> DEVLIB = libmultipath.so
> LIBS = $(DEVLIB).$(SONAME)
> -LIBDEPS = -lpthread -ldl -ldevmapper
> +LIBDEPS = -lpthread -ldl -ldevmapper -ludev
>
> OBJS = memory.o parser.o vector.o devmapper.o callout.o \
> hwtable.o blacklist.o util.o dmparser.o config.o \
> Index: multipath-tools-120123/libmultipath/uevent.c
> ===================================================================
> --- multipath-tools-120123.orig/libmultipath/uevent.c
> +++ multipath-tools-120123/libmultipath/uevent.c
> @@ -39,6 +39,7 @@
> #include<pthread.h>
> #include<limits.h>
> #include<sys/mman.h>
> +#include<libudev.h>
> #include<errno.h>
>
> #include "memory.h"
> @@ -161,7 +162,7 @@ int uevent_dispatch(int (*uev_trigger)(s
> return 0;
> }
>
> -int uevent_listen(void)
> +int failback_listen(void)
> {
> int sock;
> struct sockaddr_nl snl;
> @@ -173,20 +174,6 @@ int uevent_listen(void)
> int rcvszsz = sizeof(rcvsz);
> unsigned int *prcvszsz = (unsigned int *)&rcvszsz;
> const int feature_on = 1;
> -
> - /*
> - * Queue uevents for service by dedicated thread so that the uevent
> - * listening thread does not block on multipathd locks (vecs->lock)
> - * thereby not getting to empty the socket's receive buffer queue
> - * often enough.
> - */
> - INIT_LIST_HEAD(&uevq);
> -
> - pthread_mutex_init(uevq_lockp, NULL);
> - pthread_cond_init(uev_condp, NULL);
> -
> - pthread_cleanup_push(uevq_stop, NULL);
> -
> /*
> * First check whether we have a udev socket
> */
> @@ -382,13 +369,141 @@ int uevent_listen(void)
>
> exit:
> close(sock);
> + return 1;
> +}
>
> - pthread_cleanup_pop(1);
> +int uevent_listen(void)
> +{
> + int err;
> + struct udev *udev = NULL;
> + struct udev_monitor *monitor = NULL;
> + int fd, socket_flags;
> + int need_failback = 0;
> + /*
> + * Queue uevents for service by dedicated thread so that the uevent
> + * listening thread does not block on multipathd locks (vecs->lock)
> + * thereby not getting to empty the socket's receive buffer queue
> + * often enough.
> + */
> + INIT_LIST_HEAD(&uevq);
> +
> + pthread_mutex_init(uevq_lockp, NULL);
> + pthread_cond_init(uev_condp, NULL);
> + pthread_cleanup_push(uevq_stop, NULL);
> +
> + udev = udev_new();
> + if (!udev) {
> + condlog(2, "failed to create udev context");
> + need_failback = 1;
> + goto out;
> + }
> + monitor = udev_monitor_new_from_netlink(udev, "udev");
> + if (!monitor) {
> + condlog(2, "failed to create udev monitor");
> + need_failback = 1;
> + goto out;
> + }
> + if (udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024))
> + condlog(2, "failed to increase buffer size");
> + fd = udev_monitor_get_fd(monitor);
> + socket_flags = fcntl(fd, F_GETFL);
> + if (socket_flags< 0) {
> + condlog(2, "failed to get monitor socket flags : %s",
> + strerror(errno));
> + need_failback = 1;
> + goto out;
> + }
> + if (fcntl(fd, F_SETFL, socket_flags& ~O_NONBLOCK)< 0) {
> + condlog(2, "failed to set monitor socket flags : %s",
> + strerror(errno));
> + need_failback = 1;
> + goto out;
> + }
> + err = udev_monitor_filter_add_match_subsystem_devtype(monitor, "block",
> + NULL);
> + if (err)
> + condlog(2, "failed to create filter : %s\n", strerror(-err));
> + err = udev_monitor_enable_receiving(monitor);
> + if (err) {
> + condlog(2, "failed to enable receiving : %s\n", strerror(-err));
> + need_failback = 1;
> + goto out;
> + }
> + while (1) {
> + int i = 0;
> + char *pos, *end;
> + struct uevent *uev;
> + struct udev_device *dev;
> + struct udev_list_entry *list_entry;
> +
> + dev = udev_monitor_receive_device(monitor);
> + if (!dev) {
> + condlog(0, "failed getting udev device");
> + continue;
> + }
>
> + uev = alloc_uevent();
> + if (!uev) {
> + condlog(1, "lost uevent, oom");
> + continue;
> + }
> + pos = uev->buffer;
> + end = pos + HOTPLUG_BUFFER_SIZE + OBJECT_SIZE - 1;
> + udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(dev)) {
> + const char *name, *value;
> + int bytes;
> +
> + name = udev_list_entry_get_name(list_entry);
> + value = udev_list_entry_get_value(list_entry);
> + bytes = snprintf(pos, end - pos, "%s=%s", name,
I'd recommend to validate all input going from libudev agains NULL pointers:
(i.e. look at https://bugzilla.redhat.com/show_bug.cgi?id=809576)
Zdenek
More information about the dm-devel
mailing list