]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
loop-util: introduce loop_device_open_full()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 4 Sep 2022 17:48:01 +0000 (02:48 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 4 Sep 2022 18:29:06 +0000 (03:29 +0900)
src/shared/loop-util.c
src/shared/loop-util.h

index c376244cb7a2dba93b12f2d48ef59e3880b111b0..4114ea1f4d6b7c72e91e01f6927800a43a897bf4 100644 (file)
@@ -791,41 +791,55 @@ void loop_device_unrelinquish(LoopDevice *d) {
         d->relinquished = false;
 }
 
-int loop_device_open(
+int loop_device_open_full(
                 const char *loop_path,
+                int loop_fd,
                 int open_flags,
                 int lock_op,
                 LoopDevice **ret) {
 
-        _cleanup_close_ int loop_fd = -1, lock_fd = -1;
+        _cleanup_close_ int fd = -1, lock_fd = -1;
         _cleanup_free_ char *p = NULL;
         struct loop_info64 info;
         uint64_t diskseq = 0;
         struct stat st;
         LoopDevice *d;
-        int nr;
+        int r, nr = -1;
 
-        assert(loop_path);
+        assert(loop_path || loop_fd >= 0);
         assert(IN_SET(open_flags, O_RDWR, O_RDONLY));
         assert(ret);
 
-        loop_fd = open(loop_path, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|open_flags);
-        if (loop_fd < 0)
-                return -errno;
+        if (loop_fd < 0) {
+                fd = open(loop_path, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|open_flags);
+                if (fd < 0)
+                        return -errno;
+                loop_fd = fd;
+        }
 
         if (fstat(loop_fd, &st) < 0)
                 return -errno;
         if (!S_ISBLK(st.st_mode))
                 return -ENOTBLK;
 
+        if (fd < 0) {
+                /* If loop_fd is provided through the argument, then we reopen the inode here, instead of
+                 * keeping just a dup() clone of it around, since we want to ensure that the O_DIRECT
+                 * flag of the handle we keep is off, we have our own file index, and have the right
+                 * read/write mode in effect.*/
+                fd = fd_reopen(loop_fd, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|open_flags);
+                if (fd < 0)
+                        return fd;
+                loop_fd = fd;
+        }
+
         if (ioctl(loop_fd, LOOP_GET_STATUS64, &info) >= 0) {
 #if HAVE_VALGRIND_MEMCHECK_H
                 /* Valgrind currently doesn't know LOOP_GET_STATUS64. Remove this once it does */
                 VALGRIND_MAKE_MEM_DEFINED(&info, sizeof(info));
 #endif
                 nr = info.lo_number;
-        } else
-                nr = -1;
+        }
 
         r = fd_get_diskseq(loop_fd, &diskseq);
         if (r < 0 && r != -EOPNOTSUPP)
@@ -837,16 +851,28 @@ int loop_device_open(
                         return lock_fd;
         }
 
-        p = strdup(loop_path);
-        if (!p)
-                return -ENOMEM;
+        if (loop_path) {
+                /* If loop_path is provided, then honor it. */
+                p = strdup(loop_path);
+                if (!p)
+                        return -ENOMEM;
+        } else if (nr >= 0) {
+                /* This is a loopback block device. Use its index. */
+                if (asprintf(&p, "/dev/loop%i", nr) < 0)
+                        return -ENOMEM;
+        } else {
+                /* This is a non-loopback block device. Let's get the path to the device node. */
+                r = devname_from_stat_rdev(&st, &p);
+                if (r < 0)
+                        return r;
+        }
 
         d = new(LoopDevice, 1);
         if (!d)
                 return -ENOMEM;
 
         *d = (LoopDevice) {
-                .fd = TAKE_FD(loop_fd),
+                .fd = TAKE_FD(fd),
                 .lock_fd = TAKE_FD(lock_fd),
                 .nr = nr,
                 .node = TAKE_PTR(p),
index bdbdac60eb0169c5e95d5310ae7848ac8a2940fb..89fcbc00a0ef01c12878a01594eb535213b920c6 100644 (file)
@@ -25,7 +25,10 @@ struct LoopDevice {
 
 int loop_device_make(int fd, int open_flags, uint64_t offset, uint64_t size, uint32_t loop_flags, int lock_op, LoopDevice **ret);
 int loop_device_make_by_path(const char *path, int open_flags, uint32_t loop_flags, int lock_op, LoopDevice **ret);
-int loop_device_open(const char *loop_path, int open_flags, int lock_op, LoopDevice **ret);
+int loop_device_open_full(const char *loop_path, int loop_fd, int open_flags, int lock_op, LoopDevice **ret);
+static inline int loop_device_open(const char *loop_path, int open_flags, int lock_op, LoopDevice **ret) {
+        return loop_device_open_full(loop_path, -1, open_flags, lock_op, ret);
+}
 
 LoopDevice* loop_device_unref(LoopDevice *d);
 DEFINE_TRIVIAL_CLEANUP_FUNC(LoopDevice*, loop_device_unref);