diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-01-19 20:21:57 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-01-19 20:24:10 +0100 |
commit | 2fbe4296c5ba5bcce3ac845f196c60a88e3181fe (patch) | |
tree | eed01094fccb68bae04536f654852a1c5123f363 /src/nspawn | |
parent | 0716faad4a846d5f3cdce4bf37648d3254b9332f (diff) |
inspawn: wait until udev has probed a loopback device before making us of it
Diffstat (limited to 'src/nspawn')
-rw-r--r-- | src/nspawn/nspawn.c | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index e2ce9fbc55..e71d9a88ad 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -43,6 +43,8 @@ #include <linux/veth.h> #include <sys/personality.h> #include <linux/loop.h> +#include <poll.h> +#include <sys/file.h> #ifdef HAVE_SELINUX #include <selinux/selinux.h> @@ -2557,6 +2559,63 @@ static int setup_image(char **device_path, int *loop_nr) { return r; } +static int wait_for_block_device(struct udev *udev, dev_t devnum, struct udev_device **ret) { + _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL; + int r; + + assert(udev); + assert(ret); + + for (;;) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + struct pollfd pfd = { + .events = POLLIN + }; + + d = udev_device_new_from_devnum(udev, 'b', devnum); + if (!d) + return log_oom(); + + r = udev_device_get_is_initialized(d); + if (r < 0) + return log_error_errno(r, "Failed to check if device is initialized: %m"); + if (r > 0) { + *ret = d; + d = NULL; + return 0; + } + d = udev_device_unref(d); + + if (!monitor) { + monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (!monitor) + return log_oom(); + + r = udev_monitor_filter_add_match_subsystem_devtype(monitor, "block", NULL); + if (r < 0) + return log_error_errno(r, "Failed to add block match: %m"); + + r = udev_monitor_enable_receiving(monitor); + if (r < 0) + return log_error_errno(r, "Failed to turn on monitor: %m"); + + continue; + } + + pfd.fd = udev_monitor_get_fd(monitor); + if (pfd.fd < 0) + return log_error_errno(r, "Failed to get udev monitor fd: %m"); + + r = poll(&pfd, 1, -1); + if (r < 0) + return log_error_errno(errno, "Failed to wait for device initialization: %m"); + + d = udev_monitor_receive_device(monitor); + } + + return 0; +} + #define PARTITION_TABLE_BLURB \ "Note that the disk image needs to either contain only a single MBR partition of\n" \ "type 0x83 that is marked bootable, or follow\n" \ @@ -2659,9 +2718,9 @@ static int dissect_image( if (fstat(fd, &st) < 0) return log_error_errno(errno, "Failed to stat block device: %m"); - d = udev_device_new_from_devnum(udev, 'b', st.st_rdev); - if (!d) - return log_oom(); + r = wait_for_block_device(udev, st.st_rdev, &d); + if (r < 0) + return r; e = udev_enumerate_new(udev); if (!e) |