From 7e4a0387c4cb02a13d3221035f7c159e71d4b587 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 18 Sep 2022 16:15:54 +0900 Subject: [PATCH 1/6] blockdev-util: split-out fd_get_devnum() No functional changes, just preparation for later commits. --- src/shared/blockdev-util.c | 72 +++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/src/shared/blockdev-util.c b/src/shared/blockdev-util.c index 4402b7a97c..b90a5223cc 100644 --- a/src/shared/blockdev-util.c +++ b/src/shared/blockdev-util.c @@ -20,6 +20,46 @@ #include "missing_magic.h" #include "parse-util.h" +static int fd_get_devnum(int fd, bool backing, dev_t *ret) { + struct stat st; + dev_t devnum; + int r; + + assert(fd >= 0); + assert(ret); + + if (fstat(fd, &st) < 0) + return -errno; + + if (S_ISBLK(st.st_mode)) + devnum = st.st_rdev; + else if (!backing) + return -ENOTBLK; + else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) + return -ENOTBLK; + else if (major(st.st_dev) != 0) + devnum = st.st_dev; + else { + _cleanup_close_ int regfd = -1; + + /* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special + * handing, to get the backing device node. */ + + regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + if (regfd < 0) + return regfd; + + r = btrfs_get_block_device_fd(regfd, &devnum); + if (r == -ENOTTY) /* not btrfs */ + return -ENOTBLK; + if (r < 0) + return r; + } + + *ret = devnum; + return 0; +} + int block_device_is_whole_disk(sd_device *dev) { const char *s; int r; @@ -445,38 +485,14 @@ int path_is_encrypted(const char *path) { int fd_get_whole_disk(int fd, bool backing, dev_t *ret) { dev_t devt; - struct stat st; int r; + assert(fd >= 0); assert(ret); - if (fstat(fd, &st) < 0) - return -errno; - - if (S_ISBLK(st.st_mode)) - devt = st.st_rdev; - else if (!backing) - return -ENOTBLK; - else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) - return -ENOTBLK; - else if (major(st.st_dev) != 0) - devt = st.st_dev; - else { - _cleanup_close_ int regfd = -1; - - /* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special - * handing, to get the backing device node. */ - - regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK); - if (regfd < 0) - return regfd; - - r = btrfs_get_block_device_fd(regfd, &devt); - if (r == -ENOTTY) - return -ENOTBLK; - if (r < 0) - return r; - } + r = fd_get_devnum(fd, backing, &devt); + if (r < 0) + return r; return block_get_whole_disk(devt, ret); } From 446f8db66bf5e0fbf71bd42423d865c207082388 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 20 Sep 2022 08:43:45 +0900 Subject: [PATCH 2/6] blockdev-util: reopen file descriptor only when O_PATH is set Prompted by 13879c54d4f8b912e1f8c57e0ff7b516dd2a6f52. --- src/shared/blockdev-util.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/shared/blockdev-util.c b/src/shared/blockdev-util.c index b90a5223cc..d992168170 100644 --- a/src/shared/blockdev-util.c +++ b/src/shared/blockdev-util.c @@ -40,16 +40,26 @@ static int fd_get_devnum(int fd, bool backing, dev_t *ret) { else if (major(st.st_dev) != 0) devnum = st.st_dev; else { - _cleanup_close_ int regfd = -1; - /* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special * handing, to get the backing device node. */ - regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); - if (regfd < 0) - return regfd; + r = fcntl(fd, F_GETFL); + if (r < 0) + return -errno; - r = btrfs_get_block_device_fd(regfd, &devnum); + if (FLAGS_SET(r, O_PATH)) { + _cleanup_close_ int regfd = -1; + + /* The fstat() above we can execute on an O_PATH fd. But the btrfs ioctl we cannot. + * Hence acquire a "real" fd first, without the O_PATH flag. */ + + regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + if (regfd < 0) + return regfd; + + r = btrfs_get_block_device_fd(regfd, &devnum); + } else + r = btrfs_get_block_device_fd(fd, &devnum); if (r == -ENOTTY) /* not btrfs */ return -ENOTBLK; if (r < 0) From 612fc70fc0f5445817f3f5c033dd3d5b5fd058ea Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 19 Sep 2022 06:27:37 +0900 Subject: [PATCH 3/6] blockdev-util: re-implement block_get_originating() by using sd_device And split out the core logic as block_device_get_originating(). Hopefully, this changes no behavior. Just refactoring and preparation for later commits. --- src/shared/blockdev-util.c | 126 ++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 72 deletions(-) diff --git a/src/shared/blockdev-util.c b/src/shared/blockdev-util.c index d992168170..43bdcda620 100644 --- a/src/shared/blockdev-util.c +++ b/src/shared/blockdev-util.c @@ -119,6 +119,54 @@ int block_device_get_whole_disk(sd_device *dev, sd_device **ret) { return 0; } +static int block_device_get_originating(sd_device *dev, sd_device **ret) { + _cleanup_(sd_device_unrefp) sd_device *first_found = NULL; + const char *suffix; + sd_device *child; + dev_t devnum = 0; /* avoid false maybe-uninitialized warning */ + + /* For the specified block device tries to chase it through the layers, in case LUKS-style DM + * stacking is used, trying to find the next underlying layer. */ + + assert(dev); + assert(ret); + + FOREACH_DEVICE_CHILD_WITH_SUFFIX(dev, child, suffix) { + sd_device *child_whole_disk; + dev_t n; + + if (!path_startswith(suffix, "slaves")) + continue; + + if (block_device_get_whole_disk(child, &child_whole_disk) < 0) + continue; + + if (sd_device_get_devnum(child_whole_disk, &n) < 0) + continue; + + if (!first_found) { + first_found = sd_device_ref(child); + devnum = n; + continue; + } + + /* We found a device backed by multiple other devices. We don't really support automatic + * discovery on such setups, with the exception of dm-verity partitions. In this case there + * are two backing devices: the data partition and the hash partition. We are fine with such + * setups, however, only if both partitions are on the same physical device. Hence, let's + * verify this by iterating over every node in the 'slaves/' directory and comparing them with + * the first that gets returned by readdir(), to ensure they all point to the same device. */ + if (n != devnum) + return -ENOTUNIQ; + } + + if (!first_found) + return -ENOENT; + + *ret = TAKE_PTR(first_found); + return 1; /* found */ +} + int block_get_whole_disk(dev_t d, dev_t *ret) { char p[SYS_BLOCK_PATH_MAX("/partition")]; _cleanup_free_ char *s = NULL; @@ -219,86 +267,20 @@ int get_block_device(const char *path, dev_t *ret) { } int block_get_originating(dev_t dt, dev_t *ret) { - _cleanup_closedir_ DIR *d = NULL; - _cleanup_free_ char *t = NULL; - char p[SYS_BLOCK_PATH_MAX("/slaves")]; - _cleanup_free_ char *first_found = NULL; - const char *q; - dev_t devt; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL, *origin = NULL; int r; - /* For the specified block device tries to chase it through the layers, in case LUKS-style DM stacking is used, - * trying to find the next underlying layer. */ + assert(ret); - xsprintf_sys_block_path(p, "/slaves", dt); - d = opendir(p); - if (!d) - return -errno; - - FOREACH_DIRENT_ALL(de, d, return -errno) { - - if (dot_or_dot_dot(de->d_name)) - continue; - - if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN)) - continue; - - if (first_found) { - _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL; - - /* We found a device backed by multiple other devices. We don't really support - * automatic discovery on such setups, with the exception of dm-verity partitions. In - * this case there are two backing devices: the data partition and the hash - * partition. We are fine with such setups, however, only if both partitions are on - * the same physical device. Hence, let's verify this by iterating over every node - * in the 'slaves/' directory and comparing them with the first that gets returned by - * readdir(), to ensure they all point to the same device. */ - - u = path_join(p, de->d_name, "../dev"); - if (!u) - return -ENOMEM; - - v = path_join(p, first_found, "../dev"); - if (!v) - return -ENOMEM; - - r = read_one_line_file(u, &a); - if (r < 0) - return log_debug_errno(r, "Failed to read %s: %m", u); - - r = read_one_line_file(v, &b); - if (r < 0) - return log_debug_errno(r, "Failed to read %s: %m", v); - - /* Check if the parent device is the same. If not, then the two backing devices are on - * different physical devices, and we don't support that. */ - if (!streq(a, b)) - return -ENOTUNIQ; - } else { - first_found = strdup(de->d_name); - if (!first_found) - return -ENOMEM; - } - } - - if (!first_found) - return -ENOENT; - - q = strjoina(p, "/", first_found, "/dev"); - - r = read_one_line_file(q, &t); + r = sd_device_new_from_devnum(&dev, 'b', dt); if (r < 0) return r; - r = parse_devnum(t, &devt); + r = block_device_get_originating(dev, &origin); if (r < 0) - return -EINVAL; + return r; - if (major(devt) == 0) - return -ENOENT; - - *ret = devt; - return 1; + return sd_device_get_devnum(origin, ret); } int get_block_device_harder_fd(int fd, dev_t *ret) { From fd690a4b7fbb0c823c2b0df4d2096a1b441f7482 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 19 Sep 2022 06:33:26 +0900 Subject: [PATCH 4/6] blockdev-util: introduce block_device_new_from_fd() and block_device_new_from_path() These are possible replacements of get_block_device(), get_block_device_harder(), path_get_whole_disk(), and friends. --- src/shared/blockdev-util.c | 72 +++++++++++++++++++++++++++++++++----- src/shared/blockdev-util.h | 11 ++++++ 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/shared/blockdev-util.c b/src/shared/blockdev-util.c index 43bdcda620..72fad160ed 100644 --- a/src/shared/blockdev-util.c +++ b/src/shared/blockdev-util.c @@ -20,7 +20,7 @@ #include "missing_magic.h" #include "parse-util.h" -static int fd_get_devnum(int fd, bool backing, dev_t *ret) { +static int fd_get_devnum(int fd, BlockDeviceLookupFlag flags, dev_t *ret) { struct stat st; dev_t devnum; int r; @@ -33,7 +33,7 @@ static int fd_get_devnum(int fd, bool backing, dev_t *ret) { if (S_ISBLK(st.st_mode)) devnum = st.st_rdev; - else if (!backing) + else if (!FLAGS_SET(flags, BLOCK_DEVICE_LOOKUP_BACKING)) return -ENOTBLK; else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) return -ENOTBLK; @@ -167,6 +167,65 @@ static int block_device_get_originating(sd_device *dev, sd_device **ret) { return 1; /* found */ } +int block_device_new_from_fd(int fd, BlockDeviceLookupFlag flags, sd_device **ret) { + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + dev_t devnum; + int r; + + assert(fd >= 0); + assert(ret); + + r = fd_get_devnum(fd, flags, &devnum); + if (r < 0) + return r; + + r = sd_device_new_from_devnum(&dev, 'b', devnum); + if (r < 0) + return r; + + if (FLAGS_SET(flags, BLOCK_DEVICE_LOOKUP_ORIGINATING)) { + _cleanup_(sd_device_unrefp) sd_device *dev_origin = NULL; + sd_device *dev_whole_disk; + + r = block_device_get_whole_disk(dev, &dev_whole_disk); + if (r < 0) + return r; + + r = block_device_get_originating(dev_whole_disk, &dev_origin); + if (r < 0 && r != -ENOENT) + return r; + if (r > 0) + device_unref_and_replace(dev, dev_origin); + } + + if (FLAGS_SET(flags, BLOCK_DEVICE_LOOKUP_WHOLE_DISK)) { + sd_device *dev_whole_disk; + + r = block_device_get_whole_disk(dev, &dev_whole_disk); + if (r < 0) + return r; + + *ret = sd_device_ref(dev_whole_disk); + return 0; + } + + *ret = sd_device_ref(dev); + return 0; +} + +int block_device_new_from_path(const char *path, BlockDeviceLookupFlag flags, sd_device **ret) { + _cleanup_close_ int fd = -1; + + assert(path); + assert(ret); + + fd = open(path, O_CLOEXEC|O_PATH); + if (fd < 0) + return -errno; + + return block_device_new_from_fd(fd, flags, ret); +} + int block_get_whole_disk(dev_t d, dev_t *ret) { char p[SYS_BLOCK_PATH_MAX("/partition")]; _cleanup_free_ char *s = NULL; @@ -482,7 +541,7 @@ int fd_get_whole_disk(int fd, bool backing, dev_t *ret) { assert(fd >= 0); assert(ret); - r = fd_get_devnum(fd, backing, &devt); + r = fd_get_devnum(fd, backing ? BLOCK_DEVICE_LOOKUP_BACKING : 0, &devt); if (r < 0) return r; @@ -641,12 +700,7 @@ int block_device_remove_all_partitions(sd_device *dev, int fd) { assert(dev || fd >= 0); if (!dev) { - struct stat st; - - if (fstat(fd, &st) < 0) - return -errno; - - r = sd_device_new_from_stat_rdev(&dev_unref, &st); + r = block_device_new_from_fd(fd, 0, &dev_unref); if (r < 0) return r; diff --git a/src/shared/blockdev-util.h b/src/shared/blockdev-util.h index 1f612157fc..b2c14102ae 100644 --- a/src/shared/blockdev-util.h +++ b/src/shared/blockdev-util.h @@ -14,6 +14,17 @@ #define xsprintf_sys_block_path(buf, suffix, devno) \ xsprintf(buf, "/sys/dev/block/%u:%u%s", major(devno), minor(devno), strempty(suffix)) +typedef enum BlockDeviceLookupFlag { + BLOCK_DEVICE_LOOKUP_WHOLE_DISK = 1 << 0, /* whole block device, e.g. sda, nvme0n1, or loop0. */ + BLOCK_DEVICE_LOOKUP_BACKING = 1 << 1, /* fd may be regular file or directory on file system, in + * which case backing block device is determined. */ + BLOCK_DEVICE_LOOKUP_ORIGINATING = 1 << 2, /* Try to find the underlying layer device for stacked + * block device, e.g. LUKS-style DM. */ +} BlockDeviceLookupFlag; + +int block_device_new_from_fd(int fd, BlockDeviceLookupFlag flag, sd_device **ret); +int block_device_new_from_path(const char *path, BlockDeviceLookupFlag flag, sd_device **ret); + int block_device_is_whole_disk(sd_device *dev); int block_device_get_whole_disk(sd_device *dev, sd_device **ret); From de3b7f168e13cffe6067d5a7b6df4f301c9b05b9 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 19 Sep 2022 09:12:15 +0900 Subject: [PATCH 5/6] loop-util: rename loop_device_open() -> loop_device_open_from_path() No functional changes, just preparation for later commits. --- src/dissect/dissect.c | 2 +- src/gpt-auto-generator/gpt-auto-generator.c | 2 +- src/home/homework-luks.c | 2 +- src/shared/loop-util.c | 2 +- src/shared/loop-util.h | 7 +++++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index 8cdf312f58..6b0616e4bb 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -874,7 +874,7 @@ static int action_umount(const char *path) { return log_error_errno(r, "Failed to get devname of block device " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(devno)); - r = loop_device_open(devname, 0, LOCK_EX, &d); + r = loop_device_open_from_path(devname, 0, LOCK_EX, &d); if (r < 0) return log_error_errno(r, "Failed to open loop device '%s': %m", devname); diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 3155a7cb60..31377d877d 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -647,7 +647,7 @@ static int enumerate_partitions(dev_t devnum) { /* Let's take a LOCK_SH lock on the block device, in case udevd is already running. If we don't take * the lock, udevd might end up issuing BLKRRPART in the middle, and we don't want that, since that * might remove all partitions while we are operating on them. */ - r = loop_device_open(devname, O_RDONLY, LOCK_SH, &loop); + r = loop_device_open_from_path(devname, O_RDONLY, LOCK_SH, &loop); if (r < 0) return log_debug_errno(r, "Failed to open %s: %m", devname); diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index 0369e285a7..c2be8b153f 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -1284,7 +1284,7 @@ int home_setup_luks( return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine backing device for DM %s.", setup->dm_name); if (!setup->loop) { - r = loop_device_open(n, O_RDWR, LOCK_UN, &setup->loop); + r = loop_device_open_from_path(n, O_RDWR, LOCK_UN, &setup->loop); if (r < 0) return log_error_errno(r, "Failed to open loopback device %s: %m", n); } diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index 54251f0fb7..6097d46d29 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -414,7 +414,7 @@ static int loop_device_make_internal( /* If this is already a block device and we are supposed to cover the whole of it * then store an fd to the original open device node — and do not actually create an * unnecessary loopback device for it. */ - return loop_device_open_full(NULL, fd, open_flags, lock_op, ret); + return loop_device_open_from_fd(fd, open_flags, lock_op, ret); } else { r = stat_verify_regular(&st); if (r < 0) diff --git a/src/shared/loop-util.h b/src/shared/loop-util.h index 756041adaa..26b8c89f5f 100644 --- a/src/shared/loop-util.h +++ b/src/shared/loop-util.h @@ -31,8 +31,11 @@ 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_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); +static inline int loop_device_open_from_fd(int fd, int open_flags, int lock_op, LoopDevice **ret) { + return loop_device_open_full(NULL, fd, open_flags, lock_op, ret); +} +static inline int loop_device_open_from_path(const char *path, int open_flags, int lock_op, LoopDevice **ret) { + return loop_device_open_full(path, -1, open_flags, lock_op, ret); } LoopDevice* loop_device_ref(LoopDevice *d); From 4f0ad43e2432f644be8dacc28f9973dfd0f420cd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 18 Sep 2022 12:28:45 +0900 Subject: [PATCH 6/6] loop-util: re-introduce loop_device_open() which takes sd_device object Then, this makes loop_device_open_from_fd() or _from_path() be wrappers of loop_device_open() with block_device_new_from_fd() or _from_path(), respectively. --- src/shared/loop-util.c | 116 ++++++++++++++++++++++++----------------- src/shared/loop-util.h | 10 ++-- 2 files changed, 70 insertions(+), 56 deletions(-) diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index 6097d46d29..84f4e79c07 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -713,56 +713,40 @@ void loop_device_unrelinquish(LoopDevice *d) { d->relinquished = false; } -int loop_device_open_full( - const char *loop_path, - int loop_fd, +int loop_device_open( + sd_device *dev, int open_flags, int lock_op, LoopDevice **ret) { - _cleanup_(sd_device_unrefp) sd_device *dev = NULL; _cleanup_close_ int fd = -1, lock_fd = -1; - _cleanup_free_ char *p = NULL, *backing_file = NULL; + _cleanup_free_ char *node = NULL, *backing_file = NULL; struct loop_info64 info; uint64_t diskseq = 0; - struct stat st; LoopDevice *d; + const char *s; + dev_t devnum; int r, nr = -1; - assert(loop_path || loop_fd >= 0); + assert(dev); assert(IN_SET(open_flags, O_RDWR, O_RDONLY)); assert(ret); - if (loop_fd < 0) { - fd = open(loop_path, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|open_flags); - if (fd < 0) - return -errno; - loop_fd = fd; + /* Even if fd is provided through the argument in loop_device_open_from_fd(), 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 = sd_device_open(dev, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|open_flags); + if (fd < 0) + return fd; + + if ((lock_op & ~LOCK_NB) != LOCK_UN) { + lock_fd = open_lock_fd(fd, lock_op); + if (lock_fd < 0) + return lock_fd; } - if (fstat(loop_fd, &st) < 0) - return -errno; - if (!S_ISBLK(st.st_mode)) - return -ENOTBLK; - - r = sd_device_new_from_stat_rdev(&dev, &st); - if (r < 0) - return r; - - 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) { - const char *s; - + if (ioctl(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)); @@ -776,22 +760,20 @@ int loop_device_open_full( } } - r = fd_get_diskseq(loop_fd, &diskseq); + r = fd_get_diskseq(fd, &diskseq); if (r < 0 && r != -EOPNOTSUPP) return r; - if ((lock_op & ~LOCK_NB) != LOCK_UN) { - lock_fd = open_lock_fd(loop_fd, lock_op); - if (lock_fd < 0) - return lock_fd; - } - - r = sd_device_get_devname(dev, &loop_path); + r = sd_device_get_devnum(dev, &devnum); if (r < 0) return r; - p = strdup(loop_path); - if (!p) + r = sd_device_get_devname(dev, &s); + if (r < 0) + return r; + + node = strdup(s); + if (!node) return -ENOMEM; d = new(LoopDevice, 1); @@ -803,18 +785,54 @@ int loop_device_open_full( .fd = TAKE_FD(fd), .lock_fd = TAKE_FD(lock_fd), .nr = nr, - .node = TAKE_PTR(p), - .dev = TAKE_PTR(dev), + .node = TAKE_PTR(node), + .dev = sd_device_ref(dev), .backing_file = TAKE_PTR(backing_file), .relinquished = true, /* It's not ours, don't try to destroy it when this object is freed */ - .devno = st.st_rdev, + .devno = devnum, .diskseq = diskseq, .uevent_seqnum_not_before = UINT64_MAX, .timestamp_not_before = USEC_INFINITY, }; *ret = d; - return d->fd; + return 0; +} + +int loop_device_open_from_fd( + int fd, + int open_flags, + int lock_op, + LoopDevice **ret) { + + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + int r; + + assert(fd >= 0); + + r = block_device_new_from_fd(fd, 0, &dev); + if (r < 0) + return r; + + return loop_device_open(dev, open_flags, lock_op, ret); +} + +int loop_device_open_from_path( + const char *path, + int open_flags, + int lock_op, + LoopDevice **ret) { + + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + int r; + + assert(path); + + r = block_device_new_from_path(path, 0, &dev); + if (r < 0) + return r; + + return loop_device_open(dev, open_flags, lock_op, ret); } static int resize_partition(int partition_fd, uint64_t offset, uint64_t size) { diff --git a/src/shared/loop-util.h b/src/shared/loop-util.h index 26b8c89f5f..1658cd3592 100644 --- a/src/shared/loop-util.h +++ b/src/shared/loop-util.h @@ -30,13 +30,9 @@ 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_full(const char *loop_path, int loop_fd, int open_flags, int lock_op, LoopDevice **ret); -static inline int loop_device_open_from_fd(int fd, int open_flags, int lock_op, LoopDevice **ret) { - return loop_device_open_full(NULL, fd, open_flags, lock_op, ret); -} -static inline int loop_device_open_from_path(const char *path, int open_flags, int lock_op, LoopDevice **ret) { - return loop_device_open_full(path, -1, open_flags, lock_op, ret); -} +int loop_device_open(sd_device *dev, int open_flags, int lock_op, LoopDevice **ret); +int loop_device_open_from_fd(int fd, int open_flags, int lock_op, LoopDevice **ret); +int loop_device_open_from_path(const char *path, int open_flags, int lock_op, LoopDevice **ret); LoopDevice* loop_device_ref(LoopDevice *d); LoopDevice* loop_device_unref(LoopDevice *d);