[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [dm-devel] [PATCH] multipath: enable getting uevents through libudev



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 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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]