aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2018-12-13 13:28:58 +0100
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2018-12-17 13:50:57 +0100
commitea887be00b7a9374e29bc91fcd3e8fa6ea507eac (patch)
treeb82da3248f6ff518490a104538e70ececc85dff6 /src
parentrfkill: move wait_for_initialized() to shared/ (diff)
downloadsystemd-ea887be00b7a9374e29bc91fcd3e8fa6ea507eac.tar.gz
systemd-ea887be00b7a9374e29bc91fcd3e8fa6ea507eac.tar.bz2
systemd-ea887be00b7a9374e29bc91fcd3e8fa6ea507eac.zip
dissect-image: split out a chunk of dissect_image() out
No functional change, just moving code around.
Diffstat (limited to 'src')
-rw-r--r--src/shared/dissect-image.c204
1 files changed, 119 insertions, 85 deletions
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index 6ea8e4df8..0147c45d8 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -116,6 +116,122 @@ static bool device_is_block(sd_device *d) {
return streq(ss, "block");
}
+
+static int enumerator_for_parent(sd_device *d, sd_device_enumerator **ret) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ int r;
+
+ r = sd_device_enumerator_new(&e);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_allow_uninitialized(e);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_parent(e, d);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_PTR(e);
+ return 0;
+}
+
+/* how many times to wait for the device nodes to appear */
+#define N_DEVICE_NODE_LIST_ATTEMPTS 10
+
+static int wait_for_partitions_to_appear(
+ int fd,
+ sd_device *d,
+ unsigned num_partitions,
+ sd_device_enumerator **ret_enumerator) {
+
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ sd_device *q;
+ unsigned n;
+ int r;
+
+ r = enumerator_for_parent(d, &e);
+ if (r < 0)
+ return r;
+
+ /* Count the partitions enumerated by the kernel */
+ n = 0;
+ FOREACH_DEVICE(e, q) {
+ if (sd_device_get_devnum(q, NULL) < 0)
+ continue;
+ if (!device_is_block(q))
+ continue;
+ if (device_is_mmc_special_partition(q))
+ continue;
+
+ n++;
+ }
+
+ if (n == num_partitions + 1) {
+ *ret_enumerator = TAKE_PTR(e);
+ return 0; /* success! */
+ }
+ if (n > num_partitions + 1)
+ return log_debug_errno(SYNTHETIC_ERRNO(EIO),
+ "blkid and kernel partition lists do not match.");
+
+ /* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running or it
+ * got EBUSY because udev already opened the device. Let's reprobe the device, which is a synchronous
+ * call that waits until probing is complete. */
+
+ for (unsigned j = 0; ; j++) {
+ if (j++ > 20)
+ return -EBUSY;
+
+ if (ioctl(fd, BLKRRPART, 0) >= 0)
+ break;
+ r = -errno;
+ if (r == -EINVAL) {
+ struct loop_info64 info;
+
+ /* If we are running on a loop device that has partition scanning off, return
+ * an explicit recognizable error about this, so that callers can generate a
+ * proper message explaining the situation. */
+
+ if (ioctl(fd, LOOP_GET_STATUS64, &info) >= 0 && (info.lo_flags & LO_FLAGS_PARTSCAN) == 0) {
+ log_debug("Device is a loop device and partition scanning is off!");
+ return -EPROTONOSUPPORT;
+ }
+ }
+ if (r != -EBUSY)
+ return r;
+
+ /* If something else has the device open, such as an udev rule, the ioctl will return
+ * EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a bit,
+ * and try again.
+ *
+ * This is really something they should fix in the kernel! */
+ (void) usleep(50 * USEC_PER_MSEC);
+
+ }
+
+ return -EAGAIN; /* no success yet, try again */
+}
+
+static int loop_wait_for_partitions_to_appear(
+ int fd,
+ sd_device *d,
+ unsigned num_partitions,
+ sd_device_enumerator **ret_enumerator) {
+ int r;
+
+ for (unsigned i = 0; i < N_DEVICE_NODE_LIST_ATTEMPTS; i++) {
+ r = wait_for_partitions_to_appear(fd, d, num_partitions, ret_enumerator);
+ if (r != -EAGAIN)
+ return r;
+ }
+
+ return log_debug_errno(SYNTHETIC_ERRNO(ENXIO),
+ "Kernel partitions dit not appear within %d attempts",
+ N_DEVICE_NODE_LIST_ATTEMPTS);
+}
+
#endif
int dissect_image(
@@ -262,91 +378,9 @@ int dissect_image(
if (r < 0)
return r;
- for (i = 0;; i++) {
- int n, z;
-
- if (i >= 10) {
- log_debug("Kernel partitions never appeared.");
- return -ENXIO;
- }
-
- r = sd_device_enumerator_new(&e);
- if (r < 0)
- return r;
-
- r = sd_device_enumerator_allow_uninitialized(e);
- if (r < 0)
- return r;
-
- r = sd_device_enumerator_add_match_parent(e, d);
- if (r < 0)
- return r;
-
- /* Count the partitions enumerated by the kernel */
- n = 0;
- FOREACH_DEVICE(e, q) {
- if (sd_device_get_devnum(q, NULL) < 0)
- continue;
-
- if (!device_is_block(q))
- continue;
-
- if (device_is_mmc_special_partition(q))
- continue;
- n++;
- }
-
- /* Count the partitions enumerated by blkid */
- z = blkid_partlist_numof_partitions(pl);
- if (n == z + 1)
- break;
- if (n > z + 1) {
- log_debug("blkid and kernel partition list do not match.");
- return -EIO;
- }
- if (n < z + 1) {
- unsigned j = 0;
-
- /* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running
- * or it got EBUSY because udev already opened the device. Let's reprobe the device, which is a
- * synchronous call that waits until probing is complete. */
-
- for (;;) {
- if (j++ > 20)
- return -EBUSY;
-
- if (ioctl(fd, BLKRRPART, 0) < 0) {
- r = -errno;
-
- if (r == -EINVAL) {
- struct loop_info64 info;
-
- /* If we are running on a loop device that has partition scanning off,
- * return an explicit recognizable error about this, so that callers
- * can generate a proper message explaining the situation. */
-
- if (ioctl(fd, LOOP_GET_STATUS64, &info) >= 0 && (info.lo_flags & LO_FLAGS_PARTSCAN) == 0) {
- log_debug("Device is loop device and partition scanning is off!");
- return -EPROTONOSUPPORT;
- }
- }
- if (r != -EBUSY)
- return r;
- } else
- break;
-
- /* If something else has the device open, such as an udev rule, the ioctl will return
- * EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a
- * bit, and try again.
- *
- * This is really something they should fix in the kernel! */
-
- (void) usleep(50 * USEC_PER_MSEC);
- }
- }
-
- e = sd_device_enumerator_unref(e);
- }
+ r = loop_wait_for_partitions_to_appear(fd, d, blkid_partlist_numof_partitions(pl), &e);
+ if (r < 0)
+ return r;
FOREACH_DEVICE(e, q) {
unsigned long long pflags;