summaryrefslogtreecommitdiff
path: root/src/libudev/libudev-queue.c
diff options
context:
space:
mode:
authorKay Sievers <kay@vrfy.org>2014-04-12 22:35:50 -0700
committerKay Sievers <kay@vrfy.org>2014-04-13 17:12:14 -0700
commit9ea28c55a2488e6cd4a44ac5786f12b71ad5bc9f (patch)
tree3aeccb80e1b72169b8bc4836b5a6d1a76130ebe3 /src/libudev/libudev-queue.c
parenta163b64c4b08e8a4ad39a9a295acf3d1634024a3 (diff)
udev: remove seqnum API and all assumptions about seqnums
The way the kernel namespaces have been implemented breaks assumptions udev made regarding uevent sequence numbers. Creating devices in a namespace "steals" uevents and its sequence numbers from the host. It confuses the "udevadmin settle" logic, which might block until util a timeout is reached, even when no uevent is pending. Remove any assumptions about sequence numbers and deprecate libudev's API exposing these numbers; none of that can reliably be used anymore when namespaces are involved.
Diffstat (limited to 'src/libudev/libudev-queue.c')
-rw-r--r--src/libudev/libudev-queue.c302
1 files changed, 23 insertions, 279 deletions
diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c
index 2cb4d67121..eb0e096f84 100644
--- a/src/libudev/libudev-queue.c
+++ b/src/libudev/libudev-queue.c
@@ -24,8 +24,6 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
@@ -36,10 +34,7 @@
* SECTION:libudev-queue
* @short_description: access to currently active events
*
- * The udev daemon processes events asynchronously. All events which do not have
- * interdependencies run in parallel. This exports the current state of the
- * event processing queue, and the current event sequence numbers from the kernel
- * and the udev daemon.
+ * This exports the current state of the udev processing queue.
*/
/**
@@ -50,7 +45,6 @@
struct udev_queue {
struct udev *udev;
int refcount;
- struct udev_list queue_list;
};
/**
@@ -72,9 +66,9 @@ _public_ struct udev_queue *udev_queue_new(struct udev *udev)
udev_queue = new0(struct udev_queue, 1);
if (udev_queue == NULL)
return NULL;
+
udev_queue->refcount = 1;
udev_queue->udev = udev;
- udev_list_init(udev, &udev_queue->queue_list, false);
return udev_queue;
}
@@ -90,6 +84,7 @@ _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
{
if (udev_queue == NULL)
return NULL;
+
udev_queue->refcount++;
return udev_queue;
}
@@ -107,10 +102,11 @@ _public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
{
if (udev_queue == NULL)
return NULL;
+
udev_queue->refcount--;
if (udev_queue->refcount > 0)
return NULL;
- udev_list_cleanup(&udev_queue->queue_list);
+
free(udev_queue);
return NULL;
}
@@ -130,141 +126,30 @@ _public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
return udev_queue->udev;
}
-unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
-{
- unsigned long long int seqnum;
- int fd;
- char buf[32];
- ssize_t len;
-
- fd = open("/sys/kernel/uevent_seqnum", O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- return 0;
- len = read(fd, buf, sizeof(buf));
- close(fd);
- if (len <= 2)
- return 0;
- buf[len-1] = '\0';
- seqnum = strtoull(buf, NULL, 10);
- return seqnum;
-}
-
/**
* udev_queue_get_kernel_seqnum:
* @udev_queue: udev queue context
*
- * Get the current kernel event sequence number.
+ * This function is deprecated.
*
- * Returns: the sequence number.
+ * Returns: 0.
**/
_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
{
- unsigned long long int seqnum;
-
- if (udev_queue == NULL)
- return -EINVAL;
-
- seqnum = udev_get_kernel_seqnum(udev_queue->udev);
- return seqnum;
-}
-
-int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
-{
- if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
- return -1;
-
return 0;
}
-ssize_t udev_queue_skip_devpath(FILE *queue_file)
-{
- unsigned short int len;
-
- if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
- char *devpath = alloca(len);
-
- /* use fread to skip, fseek might drop buffered data */
- if (fread(devpath, 1, len, queue_file) == len)
- return len;
- }
-
- return -1;
-}
-
-ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
-{
- unsigned short int read_bytes = 0;
- unsigned short int len;
-
- if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
- return -1;
-
- read_bytes = (len < size - 1) ? len : size - 1;
- if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
- return -1;
- devpath[read_bytes] = '\0';
-
- /* if devpath was too long, skip unread characters */
- if (read_bytes != len) {
- unsigned short int skip_bytes = len - read_bytes;
- char *buf = alloca(skip_bytes);
-
- if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
- return -1;
- }
-
- return read_bytes;
-}
-
-static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
-{
- FILE *queue_file;
-
- queue_file = fopen("/run/udev/queue.bin", "re");
- if (queue_file == NULL)
- return NULL;
-
- if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
- udev_err(udev_queue->udev, "corrupt queue file\n");
- fclose(queue_file);
- return NULL;
- }
-
- return queue_file;
-}
-
/**
* udev_queue_get_udev_seqnum:
* @udev_queue: udev queue context
*
- * Get the last known udev event sequence number.
+ * This function is deprecated.
*
- * Returns: the sequence number.
+ * Returns: 0.
**/
_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
{
- unsigned long long int seqnum_udev;
- FILE *queue_file;
-
- queue_file = open_queue_file(udev_queue, &seqnum_udev);
- if (queue_file == NULL)
- return 0;
-
- for (;;) {
- unsigned long long int seqnum;
- ssize_t devpath_len;
-
- if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
- break;
- devpath_len = udev_queue_skip_devpath(queue_file);
- if (devpath_len < 0)
- break;
- if (devpath_len > 0)
- seqnum_udev = seqnum;
- }
-
- fclose(queue_file);
- return seqnum_udev;
+ return 0;
}
/**
@@ -277,15 +162,7 @@ _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *ud
**/
_public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
{
- unsigned long long int seqnum_start;
- FILE *queue_file;
-
- queue_file = open_queue_file(udev_queue, &seqnum_start);
- if (queue_file == NULL)
- return 0;
-
- fclose(queue_file);
- return 1;
+ return access("/run/udev/control", F_OK) >= 0;
}
/**
@@ -298,48 +175,7 @@ _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
**/
_public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
{
- unsigned long long int seqnum_kernel;
- unsigned long long int seqnum_udev = 0;
- int queued = 0;
- int is_empty = 0;
- FILE *queue_file;
-
- if (udev_queue == NULL)
- return -EINVAL;
- queue_file = open_queue_file(udev_queue, &seqnum_udev);
- if (queue_file == NULL)
- return 1;
-
- for (;;) {
- unsigned long long int seqnum;
- ssize_t devpath_len;
-
- if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
- break;
- devpath_len = udev_queue_skip_devpath(queue_file);
- if (devpath_len < 0)
- break;
-
- if (devpath_len > 0) {
- queued++;
- seqnum_udev = seqnum;
- } else {
- queued--;
- }
- }
-
- if (queued > 0)
- goto out;
-
- seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
- if (seqnum_udev < seqnum_kernel)
- goto out;
-
- is_empty = 1;
-
-out:
- fclose(queue_file);
- return is_empty;
+ return access("/run/udev/queue", F_OK) >= 0;
}
/**
@@ -348,63 +184,15 @@ out:
* @start: first event sequence number
* @end: last event sequence number
*
- * Check if udev is currently processing any events in a given sequence number range.
+ * This function is deprecated, it just returns the result of
+ * udev_queue_get_queue_is_empty().
*
- * Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
+ * Returns: a flag indicating if udev is currently handling events.
**/
_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
unsigned long long int start, unsigned long long int end)
{
- unsigned long long int seqnum;
- ssize_t devpath_len;
- int unfinished;
- FILE *queue_file;
-
- if (udev_queue == NULL)
- return -EINVAL;
- queue_file = open_queue_file(udev_queue, &seqnum);
- if (queue_file == NULL)
- return 1;
- if (start < seqnum)
- start = seqnum;
- if (start > end) {
- fclose(queue_file);
- return 1;
- }
- if (end - start > INT_MAX - 1) {
- fclose(queue_file);
- return -EOVERFLOW;
- }
-
- /*
- * we might start with 0, and handle the initial seqnum
- * only when we find an entry in the queue file
- **/
- unfinished = end - start;
-
- do {
- if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
- break;
- devpath_len = udev_queue_skip_devpath(queue_file);
- if (devpath_len < 0)
- break;
-
- /*
- * we might start with an empty or re-build queue file, where
- * the initial seqnum is not recorded as finished
- */
- if (start == seqnum && devpath_len > 0)
- unfinished++;
-
- if (devpath_len == 0) {
- if (seqnum >= start && seqnum <= end)
- unfinished--;
- }
- } while (unfinished > 0);
-
- fclose(queue_file);
-
- return (unfinished == 0);
+ return udev_queue_get_queue_is_empty(udev_queue);
}
/**
@@ -412,69 +200,25 @@ _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_
* @udev_queue: udev queue context
* @seqnum: sequence number
*
- * Check if udev is currently processing a given sequence number.
+ * This function is deprecated, it just returns the result of
+ * udev_queue_get_queue_is_empty().
*
- * Returns: a flag indicating if the given sequence number is currently active.
+ * Returns: a flag indicating if udev is currently handling events.
**/
_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
{
- if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
- return 0;
-
- return 1;
+ return udev_queue_get_queue_is_empty(udev_queue);
}
/**
* udev_queue_get_queued_list_entry:
* @udev_queue: udev queue context
*
- * Get the first entry of the list of queued events.
+ * This function is deprecated.
*
- * Returns: a udev_list_entry.
+ * Returns: NULL.
**/
_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
{
- unsigned long long int seqnum;
- FILE *queue_file;
-
- if (udev_queue == NULL)
- return NULL;
- udev_list_cleanup(&udev_queue->queue_list);
-
- queue_file = open_queue_file(udev_queue, &seqnum);
- if (queue_file == NULL)
- return NULL;
-
- for (;;) {
- char syspath[UTIL_PATH_SIZE];
- char *s;
- size_t l;
- ssize_t len;
- char seqnum_str[32];
- struct udev_list_entry *list_entry;
-
- if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
- break;
- snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
-
- s = syspath;
- l = strpcpy(&s, sizeof(syspath), "/sys");
- len = udev_queue_read_devpath(queue_file, s, l);
- if (len < 0)
- break;
-
- if (len > 0) {
- udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str);
- } else {
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
- if (streq(seqnum_str, udev_list_entry_get_value(list_entry))) {
- udev_list_entry_delete(list_entry);
- break;
- }
- }
- }
- }
- fclose(queue_file);
-
- return udev_list_get_entry(&udev_queue->queue_list);
+ return NULL;
}