All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] multipath: enable getting uevents through libudev
@ 2012-04-03 23:42 Benjamin Marzinski
  2012-04-04 11:12 ` Zdenek Kabelac
  0 siblings, 1 reply; 3+ messages in thread
From: Benjamin Marzinski @ 2012-04-03 23:42 UTC (permalink / raw)
  To: device-mapper development; +Cc: Christophe Varoqui

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,
+					value);
+			if (pos + bytes >= end) {
+				condlog(2, "buffer overflow for uevent");
+				break;
+			}
+			uev->envp[i] = pos;
+			pos += bytes;
+			*pos = '\0';
+			pos++;
+			if (strcmp(name, "DEVPATH") == 0)
+				uev->devpath = uev->envp[i] + 8;
+			if (strcmp(name, "ACTION") == 0)
+				uev->action = uev->envp[i] + 7;
+			i++;
+			if (i == HOTPLUG_NUM_ENVP - 1)
+				break;
+		}
+		udev_device_unref(dev);
+		uev->envp[i] = NULL;
+
+		condlog(3, "uevent '%s' from '%s'", uev->action, uev->devpath);
+		uev->kernel = strrchr(uev->devpath, '/');
+		if (uev->kernel)
+			uev->kernel++;
+
+		/* print payload environment */
+		for (i = 0; uev->envp[i] != NULL; i++)
+			condlog(5, "%s", uev->envp[i]);
+
+		/*
+ 		 * Queue uevent and poke service pthread.
+ 		 */
+		pthread_mutex_lock(uevq_lockp);
+		list_add_tail(&uev->node, &uevq);
+		pthread_cond_signal(uev_condp);
+		pthread_mutex_unlock(uevq_lockp);
+	}
+out:
+	if (monitor)
+		udev_monitor_unref(monitor);
+	if (udev)
+		udev_unref(udev);
+	if (need_failback)
+		err = failback_listen();
+	pthread_cleanup_pop(1);
 	pthread_mutex_destroy(uevq_lockp);
 	pthread_cond_destroy(uev_condp);
-
-	return 1;
+	return err;
 }
 
 extern int

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] multipath: enable getting uevents through libudev
  2012-04-03 23:42 [PATCH] multipath: enable getting uevents through libudev Benjamin Marzinski
@ 2012-04-04 11:12 ` Zdenek Kabelac
  2012-04-09 20:18   ` Benjamin Marzinski
  0 siblings, 1 reply; 3+ messages in thread
From: Zdenek Kabelac @ 2012-04-04 11:12 UTC (permalink / raw)
  To: device-mapper development; +Cc: Christophe Varoqui

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

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] multipath: enable getting uevents through libudev
  2012-04-04 11:12 ` Zdenek Kabelac
@ 2012-04-09 20:18   ` Benjamin Marzinski
  0 siblings, 0 replies; 3+ messages in thread
From: Benjamin Marzinski @ 2012-04-09 20:18 UTC (permalink / raw)
  To: Zdenek Kabelac; +Cc: device-mapper development, Christophe Varoqui

On Wed, Apr 04, 2012 at 01:12:45PM +0200, Zdenek Kabelac wrote:
> 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)

Looking at the udev code and the Libudev reference manual, most of my
checking decisions seem reasonable. I do more checking that udevd and
udevadm do. But I suppose it doesn't hurt to do some more.

I don't see how, given my previous checking, udev_monitor_get_fd() could
fail, but that function can return a failure, and it's no pain to check it.

Also, udev_list_entry_get_name() and udev_list_entry_get_value() can
return NULL, although I don't think it's possible here given that I
check and have a reference on the device, udev_list_entry_foreach()
cannot return a NULL list_entry, and I'm looking at a list of properties
which AFAIK must have a value. None of the udev code checks for NULL
here itself. But again, there's no compelling reason not to check for
NULL.

I'll resend this patch with the additional checks. 

-Ben

>
> Zdenek

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-04-09 20:18 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-04-03 23:42 [PATCH] multipath: enable getting uevents through libudev Benjamin Marzinski
2012-04-04 11:12 ` Zdenek Kabelac
2012-04-09 20:18   ` Benjamin Marzinski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.