]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: always take BSD lock when whole block device is opened
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 12 Apr 2023 17:43:52 +0000 (02:43 +0900)
committerLennart Poettering <lennart@poettering.net>
Thu, 13 Apr 2023 07:07:00 +0000 (09:07 +0200)
Fixes #27236.

src/partition/repart.c

index 725cad1f4a5035ba91453cd5e6ddc8866a6a8dc8..23ad58f4439ead5c626a0a8be1b53af8bfbb6a07 100644 (file)
@@ -1998,6 +1998,28 @@ static int derive_uuid(sd_id128_t base, const char *token, sd_id128_t *ret) {
         return 0;
 }
 
+static int context_open_and_lock_backing_fd(Context *context, const char *node) {
+        _cleanup_close_ int fd = -EBADF;
+
+        assert(context);
+        assert(node);
+
+        if (context->backing_fd >= 0)
+                return 0;
+
+        fd = open(node, O_RDONLY|O_CLOEXEC);
+        if (fd < 0)
+                return log_error_errno(errno, "Failed to open device '%s': %m", node);
+
+        /* Tell udev not to interfere while we are processing the device */
+        if (flock(fd, arg_dry_run ? LOCK_SH : LOCK_EX) < 0)
+                return log_error_errno(errno, "Failed to lock device '%s': %m", node);
+
+        log_debug("Device %s opened and locked.", node);
+        context->backing_fd = TAKE_FD(fd);
+        return 1;
+}
+
 static int context_load_partition_table(Context *context) {
         _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
         _cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
@@ -2026,11 +2048,9 @@ static int context_load_partition_table(Context *context) {
         else {
                 uint32_t ssz;
 
-                if (context->backing_fd < 0) {
-                        context->backing_fd = open(context->node, O_RDONLY|O_CLOEXEC);
-                        if (context->backing_fd < 0)
-                                return log_error_errno(errno, "Failed to open device '%s': %m", context->node);
-                }
+                r = context_open_and_lock_backing_fd(context, context->node);
+                if (r < 0)
+                        return r;
 
                 /* Auto-detect sector size if not specified. */
                 r = probe_sector_size_prefer_ioctl(context->backing_fd, &ssz);
@@ -2075,13 +2095,9 @@ static int context_load_partition_table(Context *context) {
 
         if (context->backing_fd < 0) {
                 /* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */
-                context->backing_fd = fd_reopen(fdisk_get_devfd(c), O_RDONLY|O_CLOEXEC);
-                if (context->backing_fd < 0)
-                        return log_error_errno(context->backing_fd, "Failed to duplicate fdisk fd: %m");
-
-                /* Tell udev not to interfere while we are processing the device */
-                if (flock(context->backing_fd, arg_dry_run ? LOCK_SH : LOCK_EX) < 0)
-                        return log_error_errno(errno, "Failed to lock block device: %m");
+                r = context_open_and_lock_backing_fd(context, FORMAT_PROC_FD_PATH(fdisk_get_devfd(c)));
+                if (r < 0)
+                        return r;
         }
 
         /* The offsets/sizes libfdisk returns to us will be in multiple of the sector size of the
@@ -6198,7 +6214,7 @@ static int acquire_root_devno(
                 char **ret,
                 int *ret_fd) {
 
-        _cleanup_free_ char *found_path = NULL;
+        _cleanup_free_ char *found_path = NULL, *node = NULL;
         dev_t devno, fd_devno = MODE_INVALID;
         _cleanup_close_ int fd = -EBADF;
         struct stat st;
@@ -6253,13 +6269,22 @@ static int acquire_root_devno(
         if (r < 0)
                 log_debug_errno(r, "Failed to find whole disk block device for '%s', ignoring: %m", p);
 
-        r = devname_from_devnum(S_IFBLK, devno, ret);
+        r = devname_from_devnum(S_IFBLK, devno, &node);
         if (r < 0)
                 return log_debug_errno(r, "Failed to determine canonical path for '%s': %m", p);
 
         /* Only if we still look at the same block device we can reuse the fd. Otherwise return an
          * invalidated fd. */
-        *ret_fd = fd_devno != MODE_INVALID && fd_devno == devno ? TAKE_FD(fd) : -1;
+        if (fd_devno != MODE_INVALID && fd_devno == devno) {
+                /* Tell udev not to interfere while we are processing the device */
+                if (flock(fd, arg_dry_run ? LOCK_SH : LOCK_EX) < 0)
+                        return log_error_errno(errno, "Failed to lock device '%s': %m", node);
+
+                *ret_fd = TAKE_FD(fd);
+        } else
+                *ret_fd = -EBADF;
+
+        *ret = TAKE_PTR(node);
         return 0;
 }