[lvm-devel] [PATCH 3/9] Udev integration: add semaphore IPC to wait for udev rule completion
Peter Rajnoha
prajnoha at redhat.com
Mon May 25 12:18:54 UTC 2009
I've added these functions :
dm_udev_notif_enable -- enable wait for udev's completion
dm_udev_notif_disable -- disable wait for udev's completion
dm_udev_notif_is_enabled -- is it enabled? :)
I added the conditional compilation, too, so when the wait for
udev completion is disabled at compilation time, we use only
dummy functions.
I use a global var as enable/disable flag to enable/disable the
wait in runtime. I think it's better this way than having IFs all
around the code. It's cleaner and less complicated...
Peter
diff --git a/libdm/.exported_symbols b/libdm/.exported_symbols
index 2c80b05..ff2e103 100644
--- a/libdm/.exported_symbols
+++ b/libdm/.exported_symbols
@@ -21,6 +21,7 @@ dm_task_get_uuid
dm_task_get_read_ahead
dm_task_set_ro
dm_task_set_newname
+dm_task_set_cookie
dm_task_set_event_nr
dm_task_set_major
dm_task_set_minor
@@ -149,3 +150,11 @@ dm_list_last
dm_list_prev
dm_list_next
dm_list_size
+dm_udev_notif_enable
+dm_udev_notif_disable
+dm_udev_notif_is_enabled
+dm_udev_notif_sem_open
+dm_udev_notif_sem_inc
+dm_udev_notif_sem_dec
+dm_udev_notif_sem_wait_zero
+dm_udev_notif_sem_close
diff --git a/libdm/ioctl/libdm-iface.c b/libdm/ioctl/libdm-iface.c
index 3698eda..935a3ea 100644
--- a/libdm/ioctl/libdm-iface.c
+++ b/libdm/ioctl/libdm-iface.c
@@ -864,6 +864,13 @@ int dm_check_version(void)
return 0;
}
+int dm_cookie_supported(void)
+{
+ return (dm_check_version() &&
+ _dm_version >= 4 &&
+ _dm_version_minor >= 15);
+}
+
void *dm_get_next_target(struct dm_task *dmt, void *next,
uint64_t *start, uint64_t *length,
char **target_type, char **params)
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 09b1036..7674e04 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -155,6 +155,7 @@ int dm_task_set_major(struct dm_task *dmt, int major);
int dm_task_set_uid(struct dm_task *dmt, uid_t uid);
int dm_task_set_gid(struct dm_task *dmt, gid_t gid);
int dm_task_set_mode(struct dm_task *dmt, mode_t mode);
+int dm_task_set_cookie(struct dm_task *dmt, uint32_t cookie);
int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr);
int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char *heads, const char *sectors, const char *start);
int dm_task_set_message(struct dm_task *dmt, const char *message);
@@ -984,4 +985,22 @@ int dm_report_field_uint64(struct dm_report *rh, struct dm_report_field *field,
void dm_report_field_set_value(struct dm_report_field *field, const void *value,
const void *sortvalue);
+int dm_cookie_supported(void);
+
+/*
+ * Functions to set simple notification channel between instances of libdm
+ * code by means of using semaphore identified by a cookie. Primarily used
+ * to provide a way of notification that related udev rule is completed as
+ * a consequence of libdm actions fired before and marked by the value of
+ * the cookie.
+ */
+void dm_udev_notif_enable(void);
+void dm_udev_notif_disable(void);
+int dm_udev_notif_is_enabled(void);
+int dm_udev_notif_sem_open(uint32_t *cookie);
+int dm_udev_notif_sem_inc(uint32_t cookie);
+int dm_udev_notif_sem_dec(uint32_t cookie);
+int dm_udev_notif_sem_wait_zero(uint32_t cookie);
+int dm_udev_notif_sem_close(uint32_t cookie);
+
#endif /* LIB_DEVICE_MAPPER_H */
diff --git a/libdm/libdm-common.c b/libdm/libdm-common.c
index bbb46f5..ef249dc 100644
--- a/libdm/libdm-common.c
+++ b/libdm/libdm-common.c
@@ -24,6 +24,12 @@
#include <sys/ioctl.h>
#include <fcntl.h>
+#ifdef WAITFORUDEV_SUPPORT
+# include <sys/types.h>
+# include <sys/ipc.h>
+# include <sys/sem.h>
+#endif
+
#ifdef linux
# include <linux/fs.h>
#endif
@@ -38,6 +44,10 @@ static char _dm_dir[PATH_MAX] = DEV_DIR DM_DIR;
static int _verbose = 0;
+#ifdef WAITFORUDEV_SUPPORT
+static int _wait_for_udev = 1;
+#endif
+
/*
* Library users can provide their own logging
* function.
@@ -222,6 +232,14 @@ int dm_task_set_mode(struct dm_task *dmt, mode_t mode)
return 1;
}
+int dm_task_set_cookie(struct dm_task *dmt, uint32_t cookie)
+{
+ /* We reuse event_nr field to pass the cookie in.*/
+ dmt->event_nr = cookie;
+
+ return 1;
+}
+
int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
const char *ttype, const char *params)
{
@@ -711,3 +729,200 @@ out:
return r;
}
+#ifndef WAITFORUDEV_SUPPORT
+
+void dm_udev_notif_enable(void)
+{
+}
+
+void dm_udev_notif_disable(void)
+{
+}
+
+int dm_udev_notif_is_enabled(void)
+{
+ return 0;
+}
+
+int dm_udev_notif_sem_open(uint32_t *cookie)
+{
+ *cookie = 0;
+
+ return 1;
+}
+
+int dm_udev_notif_sem_inc(uint32_t cookie)
+{
+ return 1;
+}
+
+int dm_udev_notif_sem_dec(uint32_t cookie)
+{
+ return 1;
+}
+
+int dm_udev_notif_sem_wait_zero(uint32_t cookie)
+{
+ return 1;
+}
+
+int dm_udev_notif_sem_close(uint32_t cookie)
+{
+ return 1;
+}
+
+#else /* WAITFORUDEV_SUPPORT */
+
+void dm_udev_notif_enable(void)
+{
+ _wait_for_udev = 1;
+}
+
+void dm_udev_notif_disable(void)
+{
+ _wait_for_udev = 0;
+}
+
+int dm_udev_notif_is_enabled(void)
+{
+ return _wait_for_udev;
+}
+
+int dm_udev_notif_sem_open(uint32_t *cookie)
+{
+ int semid;
+ int fd;
+ uint32_t gen_cookie;
+
+ if (!dm_udev_notif_is_enabled() || !dm_cookie_supported())
+ return 1;
+
+ if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
+ log_error("Failed to open /dev/urandom to create random cookie value.");
+ return 0;
+ }
+
+ /* Generate random cookie value. Be sure it is unique and != 0. */
+ do {
+ if (read(fd, &gen_cookie, sizeof(gen_cookie)) != sizeof(gen_cookie))
+ goto out;
+
+ if ((semid = semget((key_t) gen_cookie, 1, 0600 | IPC_CREAT | IPC_EXCL)) < 0) {
+ /* if the semaphore key exists, we simply generate another random one */
+ if (errno == EEXIST)
+ gen_cookie = 0;
+ else
+ goto out;
+ }
+ } while (!gen_cookie);
+
+ if (semctl(semid, 0, SETVAL, 0) < 0)
+ goto out;
+
+ if (close(fd))
+ stack;
+ *cookie = gen_cookie;
+
+ return 1;
+
+out:
+ log_error("Failed to create and initialize notification cookie");
+ if (close(fd))
+ stack;
+ return 0;
+}
+
+static int _get_cookie_sem(uint32_t cookie, int *semid)
+{
+ if ((*semid = semget((key_t) cookie, 1, 0)) < 0) {
+ log_error("Could not find notification cookie %" PRIu32 " (0x%x)",
+ cookie, cookie);
+ return 0;
+ }
+
+ return 1;
+}
+
+int dm_udev_notif_sem_inc(uint32_t cookie)
+{
+ int semid;
+ struct sembuf sb = {0, 1, 0};
+
+ if (!dm_udev_notif_is_enabled() || !dm_cookie_supported())
+ return 1;
+
+ if (!_get_cookie_sem(cookie, &semid))
+ return 0;
+
+ if (semop(semid, &sb, 1) < 0) {
+ log_error("Could not set notification cookie %" PRIu32 " (0x%x)",
+ cookie, cookie);
+ return 0;
+ }
+
+ return 1;
+}
+
+int dm_udev_notif_sem_dec(uint32_t cookie)
+{
+ int semid;
+ struct sembuf sb = {0, -1, 0};
+
+ if (!dm_udev_notif_is_enabled() || !dm_cookie_supported())
+ return 1;
+
+ if (!_get_cookie_sem(cookie, &semid))
+ return 0;
+
+ if (semop(semid, &sb, 1) < 0) {
+ log_error("Could not signal waiting process using notification cookie %" PRIu32 " (0x%x)",
+ cookie, cookie);
+ return 0;
+ }
+
+ return 1;
+}
+
+int dm_udev_notif_sem_wait_zero(uint32_t cookie)
+{
+ int semid;
+ struct sembuf sb = {0, 0, 0};
+
+ if (!dm_udev_notif_is_enabled() || !dm_cookie_supported())
+ return 1;
+
+ if (!_get_cookie_sem(cookie, &semid))
+ return 0;
+
+repeat_wait:
+ if (semop(semid, &sb, 1) < 0) {
+ if (errno == EINTR)
+ goto repeat_wait;
+ log_error("Could not set wait state for notification cookie %" PRIu32 " (0x%x)",
+ cookie, cookie);
+ return 0;
+ }
+
+ return 1;
+}
+
+int dm_udev_notif_sem_close(uint32_t cookie)
+{
+ int semid;
+
+ if (!dm_udev_notif_is_enabled() || !dm_cookie_supported())
+ return 1;
+
+ if (!_get_cookie_sem(cookie, &semid))
+ return 0;
+
+ if (semctl(semid, 0, IPC_RMID, cookie) < 0) {
+ log_error("Could not remove notification cookie '%" PRIu32 " (0x%x)",
+ cookie, cookie);
+ return 0;
+ }
+
+ return 1;
+}
+
+#endif /* WAITFORUDEV_SUPPORT */
More information about the lvm-devel
mailing list