| /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| |
| #if HAVE_VALGRIND_MEMCHECK_H |
| #include <valgrind/memcheck.h> |
| #endif |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <linux/blkpg.h> |
| #include <linux/fs.h> |
| #include <linux/loop.h> |
| #include <sys/file.h> |
| #include <sys/ioctl.h> |
| #include <unistd.h> |
| |
| #include "sd-device.h" |
| |
| #include "alloc-util.h" |
| #include "blockdev-util.h" |
| #include "data-fd-util.h" |
| #include "device-util.h" |
| #include "devnum-util.h" |
| #include "dissect-image.h" |
| #include "env-util.h" |
| #include "errno-util.h" |
| #include "fd-util.h" |
| #include "fileio.h" |
| #include "loop-util.h" |
| #include "missing_loop.h" |
| #include "parse-util.h" |
| #include "path-util.h" |
| #include "random-util.h" |
| #include "stat-util.h" |
| #include "stdio-util.h" |
| #include "string-util.h" |
| #include "tmpfile-util.h" |
| |
| static void cleanup_clear_loop_close(int *fd) { |
| if (*fd < 0) |
| return; |
| |
| (void) ioctl(*fd, LOOP_CLR_FD); |
| (void) safe_close(*fd); |
| } |
| |
| static int loop_is_bound(int fd) { |
| struct loop_info64 info; |
| |
| assert(fd >= 0); |
| |
| if (ioctl(fd, LOOP_GET_STATUS64, &info) < 0) { |
| if (errno == ENXIO) |
| return false; /* not bound! */ |
| |
| return -errno; |
| } |
| |
| return true; /* bound! */ |
| } |
| |
| static int get_current_uevent_seqnum(uint64_t *ret) { |
| _cleanup_free_ char *p = NULL; |
| int r; |
| |
| r = read_full_virtual_file("/sys/kernel/uevent_seqnum", &p, NULL); |
| if (r < 0) |
| return log_debug_errno(r, "Failed to read current uevent sequence number: %m"); |
| |
| r = safe_atou64(strstrip(p), ret); |
| if (r < 0) |
| return log_debug_errno(r, "Failed to parse current uevent sequence number: %s", p); |
| |
| return 0; |
| } |
| |
| static int open_lock_fd(int primary_fd, int operation) { |
| _cleanup_close_ int lock_fd = -EBADF; |
| |
| assert(primary_fd >= 0); |
| assert(IN_SET(operation & ~LOCK_NB, LOCK_SH, LOCK_EX)); |
| |
| lock_fd = fd_reopen(primary_fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); |
| if (lock_fd < 0) |
| return lock_fd; |
| |
| if (flock(lock_fd, operation) < 0) |
| return -errno; |
| |
| return TAKE_FD(lock_fd); |
| } |
| |
| static int loop_configure_verify_direct_io(int fd, const struct loop_config *c) { |
| assert(fd); |
| assert(c); |
| |
| if (FLAGS_SET(c->info.lo_flags, LO_FLAGS_DIRECT_IO)) { |
| struct loop_info64 info; |
| |
| if (ioctl(fd, LOOP_GET_STATUS64, &info) < 0) |
| return log_debug_errno(errno, "Failed to issue LOOP_GET_STATUS64: %m"); |
| |
| #if HAVE_VALGRIND_MEMCHECK_H |
| VALGRIND_MAKE_MEM_DEFINED(&info, sizeof(info)); |
| #endif |
| |
| /* On older kernels (<= 5.3) it was necessary to set the block size of the loopback block |
| * device to the logical block size of the underlying file system. Since there was no nice |
| * way to query the value, we are not bothering to do this however. On newer kernels the |
| * block size is propagated automatically and does not require intervention from us. We'll |
| * check here if enabling direct IO worked, to make this easily debuggable however. |
| * |
| * (Should anyone really care and actually wants direct IO on old kernels: it might be worth |
| * enabling direct IO with iteratively larger block sizes until it eventually works.) */ |
| if (!FLAGS_SET(info.lo_flags, LO_FLAGS_DIRECT_IO)) |
| log_debug("Could not enable direct IO mode, proceeding in buffered IO mode."); |
| } |
| |
| return 0; |
| } |
| |
| static int loop_configure_verify(int fd, const struct loop_config *c) { |
| bool broken = false; |
| int r; |
| |
| assert(fd >= 0); |
| assert(c); |
| |
| if (c->block_size != 0) { |
| uint32_t ssz; |
| |
| r = blockdev_get_sector_size(fd, &ssz); |
| if (r < 0) |
| return r; |
| |
| if (ssz != c->block_size) { |
| log_debug("LOOP_CONFIGURE didn't honour requested block size %" PRIu32 ", got %" PRIu32 " instead. Ignoring.", c->block_size, ssz); |
| broken = true; |
| } |
| } |
| |
| if (c->info.lo_sizelimit != 0) { |
| /* Kernel 5.8 vanilla doesn't properly propagate the size limit into the |
| * block device. If it's used, let's immediately check if it had the desired |
| * effect hence. And if not use classic LOOP_SET_STATUS64. */ |
| uint64_t z; |
| |
| if (ioctl(fd, BLKGETSIZE64, &z) < 0) |
| return -errno; |
| |
| if (z != c->info.lo_sizelimit) { |
| log_debug("LOOP_CONFIGURE is broken, doesn't honour .info.lo_sizelimit. Falling back to LOOP_SET_STATUS64."); |
| broken = true; |
| } |
| } |
| |
| if (FLAGS_SET(c->info.lo_flags, LO_FLAGS_PARTSCAN)) { |
| /* Kernel 5.8 vanilla doesn't properly propagate the partition scanning flag |
| * into the block device. Let's hence verify if things work correctly here |
| * before returning. */ |
| |
| r = blockdev_partscan_enabled(fd); |
| if (r < 0) |
| return r; |
| if (r == 0) { |
| log_debug("LOOP_CONFIGURE is broken, doesn't honour LO_FLAGS_PARTSCAN. Falling back to LOOP_SET_STATUS64."); |
| broken = true; |
| } |
| } |
| |
| r = loop_configure_verify_direct_io(fd, c); |
| if (r < 0) |
| return r; |
| |
| return !broken; |
| } |
| |
| static int loop_configure_fallback(int fd, const struct loop_config *c) { |
| struct loop_info64 info_copy; |
| int r; |
| |
| assert(fd >= 0); |
| assert(c); |
| |
| /* Only some of the flags LOOP_CONFIGURE can set are also settable via LOOP_SET_STATUS64, hence mask |
| * them out. */ |
| info_copy = c->info; |
| info_copy.lo_flags &= LOOP_SET_STATUS_SETTABLE_FLAGS; |
| |
| /* Since kernel commit 5db470e229e22b7eda6e23b5566e532c96fb5bc3 (kernel v5.0) the LOOP_SET_STATUS64 |
| * ioctl can return EAGAIN in case we change the info.lo_offset field, if someone else is accessing the |
| * block device while we try to reconfigure it. This is a pretty common case, since udev might |
| * instantly start probing the device as soon as we attach an fd to it. Hence handle it in two ways: |
| * first, let's take the BSD lock to ensure that udev will not step in between the point in |
| * time where we attach the fd and where we reconfigure the device. Secondly, let's wait 50ms on |
| * EAGAIN and retry. The former should be an efficient mechanism to avoid we have to wait 50ms |
| * needlessly if we are just racing against udev. The latter is protection against all other cases, |
| * i.e. peers that do not take the BSD lock. */ |
| |
| for (unsigned n_attempts = 0;;) { |
| if (ioctl(fd, LOOP_SET_STATUS64, &info_copy) >= 0) |
| break; |
| |
| if (errno != EAGAIN || ++n_attempts >= 64) |
| return log_debug_errno(errno, "Failed to configure loopback block device: %m"); |
| |
| /* Sleep some random time, but at least 10ms, at most 250ms. Increase the delay the more |
| * failed attempts we see */ |
| (void) usleep(UINT64_C(10) * USEC_PER_MSEC + |
| random_u64_range(UINT64_C(240) * USEC_PER_MSEC * n_attempts/64)); |
| } |
| |
| /* Work around a kernel bug, where changing offset/size of the loopback device doesn't correctly |
| * invalidate the buffer cache. For details see: |
| * |
| * https://android.googlesource.com/platform/system/apex/+/bef74542fbbb4cd629793f4efee8e0053b360570 |
| * |
| * This was fixed in kernel 5.0, see: |
| * |
| * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5db470e229e22b7eda6e23b5566e532c96fb5bc3 |
| * |
| * We'll run the work-around here in the legacy LOOP_SET_STATUS64 codepath. In the LOOP_CONFIGURE |
| * codepath above it should not be necessary. */ |
| if (c->info.lo_offset != 0 || c->info.lo_sizelimit != 0) |
| if (ioctl(fd, BLKFLSBUF, 0) < 0) |
| log_debug_errno(errno, "Failed to issue BLKFLSBUF ioctl, ignoring: %m"); |
| |
| /* If a block size is requested then try to configure it. If that doesn't work, ignore errors, but |
| * afterwards, let's validate what is in effect, and if it doesn't match what we want, fail */ |
| if (c->block_size != 0) { |
| uint32_t ssz; |
| |
| if (ioctl(fd, LOOP_SET_BLOCK_SIZE, (unsigned long) c->block_size) < 0) |
| log_debug_errno(errno, "Failed to set sector size, ignoring: %m"); |
| |
| r = blockdev_get_sector_size(fd, &ssz); |
| if (r < 0) |
| return log_debug_errno(r, "Failed to read sector size: %m"); |
| if (ssz != c->block_size) |
| return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Sector size of loopback device doesn't match what we requested, refusing."); |
| } |
| |
| /* LO_FLAGS_DIRECT_IO is a flags we need to configure via explicit ioctls. */ |
| if (FLAGS_SET(c->info.lo_flags, LO_FLAGS_DIRECT_IO)) |
| if (ioctl(fd, LOOP_SET_DIRECT_IO, 1UL) < 0) |
| log_debug_errno(errno, "Failed to enable direct IO mode, ignoring: %m"); |
| |
| return loop_configure_verify_direct_io(fd, c); |
| } |
| |
| static int loop_configure( |
| int nr, |
| int open_flags, |
| int lock_op, |
| const struct loop_config *c, |
| LoopDevice **ret) { |
| |
| static bool loop_configure_broken = false; |
| |
| _cleanup_(sd_device_unrefp) sd_device *dev = NULL; |
| _cleanup_(cleanup_clear_loop_close) int loop_with_fd = -EBADF; /* This must be declared before lock_fd. */ |
| _cleanup_close_ int fd = -EBADF, lock_fd = -EBADF; |
| _cleanup_free_ char *node = NULL; |
| uint64_t diskseq = 0, seqnum = UINT64_MAX; |
| usec_t timestamp = USEC_INFINITY; |
| dev_t devno; |
| int r; |
| |
| assert(nr >= 0); |
| assert(c); |
| assert(ret); |
| |
| if (asprintf(&node, "/dev/loop%i", nr) < 0) |
| return -ENOMEM; |
| |
| r = sd_device_new_from_devname(&dev, node); |
| if (r < 0) |
| return r; |
| |
| r = sd_device_get_devnum(dev, &devno); |
| if (r < 0) |
| return r; |
| |
| fd = sd_device_open(dev, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|open_flags); |
| if (fd < 0) |
| return fd; |
| |
| /* Let's lock the device before we do anything. We take the BSD lock on a second, separately opened |
| * fd for the device. udev after all watches for close() events (specifically IN_CLOSE_WRITE) on |
| * block devices to reprobe them, hence by having a separate fd we will later close() we can ensure |
| * we trigger udev after everything is done. If we'd lock our own fd instead and keep it open for a |
| * long time udev would possibly never run on it again, even though the fd is unlocked, simply |
| * because we never close() it. It also has the nice benefit we can use the _cleanup_close_ logic to |
| * automatically release the lock, after we are done. */ |
| lock_fd = open_lock_fd(fd, LOCK_EX); |
| if (lock_fd < 0) |
| return lock_fd; |
| |
| /* Let's see if backing file is really unattached. Someone may already attach a backing file without |
| * taking BSD lock. */ |
| r = loop_is_bound(fd); |
| if (r < 0) |
| return r; |
| if (r > 0) |
| return -EBUSY; |
| |
| /* Let's see if the device is really detached, i.e. currently has no associated partition block |
| * devices. On various kernels (such as 5.8) it is possible to have a loopback block device that |
| * superficially is detached but still has partition block devices associated for it. Let's then |
| * manually remove the partitions via BLKPG, and tell the caller we did that via EUCLEAN, so they try |
| * again. */ |
| r = block_device_remove_all_partitions(dev, fd); |
| if (r < 0) |
| return r; |
| if (r > 0) |
| /* Removed all partitions. Let's report this to the caller, to try again, and count this as |
| * an attempt. */ |
| return -EUCLEAN; |
| |
| if (!loop_configure_broken) { |
| /* Acquire uevent seqnum immediately before attaching the loopback device. This allows |
| * callers to ignore all uevents with a seqnum before this one, if they need to associate |
| * uevent with this attachment. Doing so isn't race-free though, as uevents that happen in |
| * the window between this reading of the seqnum, and the LOOP_CONFIGURE call might still be |
| * mistaken as originating from our attachment, even though might be caused by an earlier |
| * use. But doing this at least shortens the race window a bit. */ |
| r = get_current_uevent_seqnum(&seqnum); |
| if (r < 0) |
| return r; |
| |
| timestamp = now(CLOCK_MONOTONIC); |
| |
| if (ioctl(fd, LOOP_CONFIGURE, c) < 0) { |
| /* Do fallback only if LOOP_CONFIGURE is not supported, propagate all other |
| * errors. Note that the kernel is weird: non-existing ioctls currently return EINVAL |
| * rather than ENOTTY on loopback block devices. They should fix that in the kernel, |
| * but in the meantime we accept both here. */ |
| if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL) |
| return -errno; |
| |
| loop_configure_broken = true; |
| } else { |
| loop_with_fd = TAKE_FD(fd); |
| |
| r = loop_configure_verify(loop_with_fd, c); |
| if (r < 0) |
| return r; |
| if (r == 0) { |
| /* LOOP_CONFIGURE doesn't work. Remember that. */ |
| loop_configure_broken = true; |
| |
| /* We return EBUSY here instead of retrying immediately with LOOP_SET_FD, |
| * because LOOP_CLR_FD is async: if the operation cannot be executed right |
| * away it just sets the autoclear flag on the device. This means there's a |
| * good chance we cannot actually reuse the loopback device right-away. Hence |
| * let's assume it's busy, avoid the trouble and let the calling loop call us |
| * again with a new, likely unused device. */ |
| return -EBUSY; |
| } |
| } |
| } |
| |
| if (loop_configure_broken) { |
| /* Let's read the seqnum again, to shorten the window. */ |
| r = get_current_uevent_seqnum(&seqnum); |
| if (r < 0) |
| return r; |
| |
| timestamp = now(CLOCK_MONOTONIC); |
| |
| if (ioctl(fd, LOOP_SET_FD, c->fd) < 0) |
| return -errno; |
| |
| loop_with_fd = TAKE_FD(fd); |
| |
| r = loop_configure_fallback(loop_with_fd, c); |
| if (r < 0) |
| return r; |
| } |
| |
| r = fd_get_diskseq(loop_with_fd, &diskseq); |
| if (r < 0 && r != -EOPNOTSUPP) |
| return r; |
| |
| switch (lock_op & ~LOCK_NB) { |
| case LOCK_EX: /* Already in effect */ |
| break; |
| case LOCK_SH: /* Downgrade */ |
| if (flock(lock_fd, lock_op) < 0) |
| return -errno; |
| break; |
| case LOCK_UN: /* Release */ |
| lock_fd = safe_close(lock_fd); |
| break; |
| default: |
| assert_not_reached(); |
| } |
| |
| LoopDevice *d = new(LoopDevice, 1); |
| if (!d) |
| return -ENOMEM; |
| |
| *d = (LoopDevice) { |
| .n_ref = 1, |
| .fd = TAKE_FD(loop_with_fd), |
| .lock_fd = TAKE_FD(lock_fd), |
| .node = TAKE_PTR(node), |
| .nr = nr, |
| .devno = devno, |
| .dev = TAKE_PTR(dev), |
| .diskseq = diskseq, |
| .uevent_seqnum_not_before = seqnum, |
| .timestamp_not_before = timestamp, |
| .sector_size = c->block_size, |
| }; |
| |
| *ret = TAKE_PTR(d); |
| return 0; |
| } |
| |
| static int loop_device_make_internal( |
| const char *path, |
| int fd, |
| int open_flags, |
| uint64_t offset, |
| uint64_t size, |
| uint32_t sector_size, |
| uint32_t loop_flags, |
| int lock_op, |
| LoopDevice **ret) { |
| |
| _cleanup_(loop_device_unrefp) LoopDevice *d = NULL; |
| _cleanup_close_ int direct_io_fd = -EBADF, control = -EBADF; |
| _cleanup_free_ char *backing_file = NULL; |
| struct loop_config config; |
| int r, f_flags; |
| struct stat st; |
| |
| assert(fd >= 0); |
| assert(ret); |
| assert(IN_SET(open_flags, O_RDWR, O_RDONLY)); |
| |
| if (fstat(fd, &st) < 0) |
| return -errno; |
| |
| if (S_ISBLK(st.st_mode)) { |
| if (offset == 0 && IN_SET(size, 0, UINT64_MAX)) |
| /* 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_from_fd(fd, open_flags, lock_op, ret); |
| } else { |
| r = stat_verify_regular(&st); |
| if (r < 0) |
| return r; |
| } |
| |
| if (path) { |
| r = path_make_absolute_cwd(path, &backing_file); |
| if (r < 0) |
| return r; |
| |
| path_simplify(backing_file); |
| } else { |
| r = fd_get_path(fd, &backing_file); |
| if (r < 0) |
| return r; |
| } |
| |
| f_flags = fcntl(fd, F_GETFL); |
| if (f_flags < 0) |
| return -errno; |
| |
| if (FLAGS_SET(loop_flags, LO_FLAGS_DIRECT_IO) != FLAGS_SET(f_flags, O_DIRECT)) { |
| /* If LO_FLAGS_DIRECT_IO is requested, then make sure we have the fd open with O_DIRECT, as |
| * that's required. Conversely, if it's off require that O_DIRECT is off too (that's because |
| * new kernels will implicitly enable LO_FLAGS_DIRECT_IO if O_DIRECT is set). |
| * |
| * Our intention here is that LO_FLAGS_DIRECT_IO is the primary knob, and O_DIRECT derived |
| * from that automatically. */ |
| |
| direct_io_fd = fd_reopen(fd, (FLAGS_SET(loop_flags, LO_FLAGS_DIRECT_IO) ? O_DIRECT : 0)|O_CLOEXEC|O_NONBLOCK|open_flags); |
| if (direct_io_fd < 0) { |
| if (!FLAGS_SET(loop_flags, LO_FLAGS_DIRECT_IO)) |
| return log_debug_errno(errno, "Failed to reopen file descriptor without O_DIRECT: %m"); |
| |
| /* Some file systems might not support O_DIRECT, let's gracefully continue without it then. */ |
| log_debug_errno(errno, "Failed to enable O_DIRECT for backing file descriptor for loopback device. Continuing without."); |
| loop_flags &= ~LO_FLAGS_DIRECT_IO; |
| } else |
| fd = direct_io_fd; /* From now on, operate on our new O_DIRECT fd */ |
| } |
| |
| control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); |
| if (control < 0) |
| return -errno; |
| |
| if (sector_size == 0) |
| /* If no sector size is specified, default to the classic default */ |
| sector_size = 512; |
| else if (sector_size == UINT32_MAX) { |
| |
| if (S_ISBLK(st.st_mode)) |
| /* If the sector size is specified as UINT32_MAX we'll propagate the sector size of |
| * the underlying block device. */ |
| r = blockdev_get_sector_size(fd, §or_size); |
| else { |
| _cleanup_close_ int non_direct_io_fd = -1; |
| int probe_fd; |
| |
| assert(S_ISREG(st.st_mode)); |
| |
| /* If sector size is specified as UINT32_MAX, we'll try to probe the right sector |
| * size of the image in question by looking for the GPT partition header at various |
| * offsets. This of course only works if the image already has a disk label. |
| * |
| * So here we actually want to read the file contents ourselves. This is quite likely |
| * not going to work if we managed to enable O_DIRECT, because in such a case there |
| * are some pretty strict alignment requirements to offset, size and target, but |
| * there's no way to query what alignment specifically is actually required. Hence, |
| * let's avoid the mess, and temporarily open an fd without O_DIRECT for the probing |
| * logic. */ |
| |
| if (FLAGS_SET(loop_flags, LO_FLAGS_DIRECT_IO)) { |
| non_direct_io_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK); |
| if (non_direct_io_fd < 0) |
| return non_direct_io_fd; |
| |
| probe_fd = non_direct_io_fd; |
| } else |
| probe_fd = fd; |
| |
| r = probe_sector_size(probe_fd, §or_size); |
| } |
| if (r < 0) |
| return r; |
| } |
| |
| config = (struct loop_config) { |
| .fd = fd, |
| .block_size = sector_size, |
| .info = { |
| /* Use the specified flags, but configure the read-only flag from the open flags, and force autoclear */ |
| .lo_flags = (loop_flags & ~LO_FLAGS_READ_ONLY) | ((open_flags & O_ACCMODE) == O_RDONLY ? LO_FLAGS_READ_ONLY : 0) | LO_FLAGS_AUTOCLEAR, |
| .lo_offset = offset, |
| .lo_sizelimit = size == UINT64_MAX ? 0 : size, |
| }, |
| }; |
| |
| /* Loop around LOOP_CTL_GET_FREE, since at the moment we attempt to open the returned device it might |
| * be gone already, taken by somebody else racing against us. */ |
| for (unsigned n_attempts = 0;;) { |
| int nr; |
| |
| /* Let's take a lock on the control device first. On a busy system, where many programs |
| * attempt to allocate a loopback device at the same time, we might otherwise keep looping |
| * around relatively heavy operations: asking for a free loopback device, then opening it, |
| * validating it, attaching something to it. Let's serialize this whole operation, to make |
| * unnecessary busywork less likely. Note that this is just something we do to optimize our |
| * own code (and whoever else decides to use LOCK_EX locks for this), taking this lock is not |
| * necessary, it just means it's less likely we have to iterate through this loop again and |
| * again if our own code races against our own code. |
| * |
| * Note: our lock protocol is to take the /dev/loop-control lock first, and the block device |
| * lock second, if both are taken, and always in this order, to avoid ABBA locking issues. */ |
| if (flock(control, LOCK_EX) < 0) |
| return -errno; |
| |
| nr = ioctl(control, LOOP_CTL_GET_FREE); |
| if (nr < 0) |
| return -errno; |
| |
| r = loop_configure(nr, open_flags, lock_op, &config, &d); |
| if (r >= 0) |
| break; |
| |
| /* -ENODEV or friends: Somebody might've gotten the same number from the kernel, used the |
| * device, and called LOOP_CTL_REMOVE on it. Let's retry with a new number. |
| * -EBUSY: a file descriptor is already bound to the loopback block device. |
| * -EUCLEAN: some left-over partition devices that were cleaned up. */ |
| if (!ERRNO_IS_DEVICE_ABSENT(r) && !IN_SET(r, -EBUSY, -EUCLEAN)) |
| return r; |
| |
| /* OK, this didn't work, let's try again a bit later, but first release the lock on the |
| * control device */ |
| if (flock(control, LOCK_UN) < 0) |
| return -errno; |
| |
| if (++n_attempts >= 64) /* Give up eventually */ |
| return -EBUSY; |
| |
| /* Wait some random time, to make collision less likely. Let's pick a random time in the |
| * range 0ms…250ms, linearly scaled by the number of failed attempts. */ |
| (void) usleep(random_u64_range(UINT64_C(10) * USEC_PER_MSEC + |
| UINT64_C(240) * USEC_PER_MSEC * n_attempts/64)); |
| } |
| |
| d->backing_file = TAKE_PTR(backing_file); |
| |
| log_debug("Successfully acquired %s, devno=%u:%u, nr=%i, diskseq=%" PRIu64, |
| d->node, |
| major(d->devno), minor(d->devno), |
| d->nr, |
| d->diskseq); |
| |
| *ret = TAKE_PTR(d); |
| return 0; |
| } |
| |
| static uint32_t loop_flags_mangle(uint32_t loop_flags) { |
| int r; |
| |
| r = getenv_bool("SYSTEMD_LOOP_DIRECT_IO"); |
| if (r < 0 && r != -ENXIO) |
| log_debug_errno(r, "Failed to parse $SYSTEMD_LOOP_DIRECT_IO, ignoring: %m"); |
| |
| return UPDATE_FLAG(loop_flags, LO_FLAGS_DIRECT_IO, r != 0); /* Turn on LO_FLAGS_DIRECT_IO by default, unless explicitly configured to off. */ |
| } |
| |
| int loop_device_make( |
| int fd, |
| int open_flags, |
| uint64_t offset, |
| uint64_t size, |
| uint32_t sector_size, |
| uint32_t loop_flags, |
| int lock_op, |
| LoopDevice **ret) { |
| |
| assert(fd >= 0); |
| assert(ret); |
| |
| return loop_device_make_internal( |
| NULL, |
| fd, |
| open_flags, |
| offset, |
| size, |
| sector_size, |
| loop_flags_mangle(loop_flags), |
| lock_op, |
| ret); |
| } |
| |
| int loop_device_make_by_path( |
| const char *path, |
| int open_flags, |
| uint32_t sector_size, |
| uint32_t loop_flags, |
| int lock_op, |
| LoopDevice **ret) { |
| |
| int r, basic_flags, direct_flags, rdwr_flags; |
| _cleanup_close_ int fd = -EBADF; |
| bool direct = false; |
| |
| assert(path); |
| assert(ret); |
| assert(open_flags < 0 || IN_SET(open_flags, O_RDWR, O_RDONLY)); |
| |
| /* Passing < 0 as open_flags here means we'll try to open the device writable if we can, retrying |
| * read-only if we cannot. */ |
| |
| loop_flags = loop_flags_mangle(loop_flags); |
| |
| /* Let's open with O_DIRECT if we can. But not all file systems support that, hence fall back to |
| * non-O_DIRECT mode automatically, if it fails. */ |
| |
| basic_flags = O_CLOEXEC|O_NONBLOCK|O_NOCTTY; |
| direct_flags = FLAGS_SET(loop_flags, LO_FLAGS_DIRECT_IO) ? O_DIRECT : 0; |
| rdwr_flags = open_flags >= 0 ? open_flags : O_RDWR; |
| |
| fd = open(path, basic_flags|direct_flags|rdwr_flags); |
| if (fd < 0 && direct_flags != 0) /* If we had O_DIRECT on, and things failed with that, let's immediately try again without */ |
| fd = open(path, basic_flags|rdwr_flags); |
| else |
| direct = direct_flags != 0; |
| if (fd < 0) { |
| r = -errno; |
| |
| /* Retry read-only? */ |
| if (open_flags >= 0 || !(ERRNO_IS_PRIVILEGE(r) || r == -EROFS)) |
| return r; |
| |
| fd = open(path, basic_flags|direct_flags|O_RDONLY); |
| if (fd < 0 && direct_flags != 0) /* as above */ |
| fd = open(path, basic_flags|O_RDONLY); |
| else |
| direct = direct_flags != 0; |
| if (fd < 0) |
| return r; /* Propagate original error */ |
| |
| open_flags = O_RDONLY; |
| } else if (open_flags < 0) |
| open_flags = O_RDWR; |
| |
| log_debug("Opened '%s' in %s access mode%s, with O_DIRECT %s%s.", |
| path, |
| open_flags == O_RDWR ? "O_RDWR" : "O_RDONLY", |
| open_flags != rdwr_flags ? " (O_RDWR was requested but not allowed)" : "", |
| direct ? "enabled" : "disabled", |
| direct != (direct_flags != 0) ? " (O_DIRECT was requested but not supported)" : ""); |
| |
| return loop_device_make_internal(path, fd, open_flags, 0, 0, sector_size, loop_flags, lock_op, ret); |
| } |
| |
| int loop_device_make_by_path_memory( |
| const char *path, |
| int open_flags, |
| uint32_t sector_size, |
| uint32_t loop_flags, |
| int lock_op, |
| LoopDevice **ret) { |
| |
| _cleanup_close_ int fd = -EBADF, mfd = -EBADF; |
| _cleanup_free_ char *fn = NULL; |
| struct stat st; |
| int r; |
| |
| assert(path); |
| assert(IN_SET(open_flags, O_RDWR, O_RDONLY)); |
| assert(ret); |
| |
| loop_flags &= ~LO_FLAGS_DIRECT_IO; /* memfds don't support O_DIRECT, hence LO_FLAGS_DIRECT_IO can't be used either */ |
| |
| fd = open(path, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_RDONLY); |
| if (fd < 0) |
| return -errno; |
| |
| if (fstat(fd, &st) < 0) |
| return -errno; |
| |
| if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode)) |
| return -EBADF; |
| |
| r = path_extract_filename(path, &fn); |
| if (r < 0) |
| return r; |
| |
| mfd = memfd_clone_fd(fd, fn, open_flags|O_CLOEXEC); |
| if (mfd < 0) |
| return mfd; |
| |
| fd = safe_close(fd); /* Let's close the original early */ |
| |
| return loop_device_make_internal(NULL, mfd, open_flags, 0, 0, sector_size, loop_flags, lock_op, ret); |
| } |
| |
| static LoopDevice* loop_device_free(LoopDevice *d) { |
| _cleanup_close_ int control = -EBADF; |
| int r; |
| |
| if (!d) |
| return NULL; |
| |
| /* Release any lock we might have on the device first. We want to open+lock the /dev/loop-control |
| * device below, but our lock protocol says that if both control and block device locks are taken, |
| * the control lock needs to be taken first, the block device lock second — in order to avoid ABBA |
| * locking issues. Moreover, we want to issue LOOP_CLR_FD on the block device further down, and that |
| * would fail if we had another fd open to the device. */ |
| d->lock_fd = safe_close(d->lock_fd); |
| |
| /* Let's open the control device early, and lock it, so that we can release our block device and |
| * delete it in a synchronized fashion, and allocators won't needlessly see the block device as free |
| * while we are about to delete it. */ |
| if (!LOOP_DEVICE_IS_FOREIGN(d) && !d->relinquished) { |
| control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); |
| if (control < 0) |
| log_debug_errno(errno, "Failed to open loop control device, cannot remove loop device '%s', ignoring: %m", strna(d->node)); |
| else if (flock(control, LOCK_EX) < 0) |
| log_debug_errno(errno, "Failed to lock loop control device, ignoring: %m"); |
| } |
| |
| /* Then let's release the loopback block device */ |
| if (d->fd >= 0) { |
| /* Implicitly sync the device, since otherwise in-flight blocks might not get written */ |
| if (fsync(d->fd) < 0) |
| log_debug_errno(errno, "Failed to sync loop block device, ignoring: %m"); |
| |
| if (!LOOP_DEVICE_IS_FOREIGN(d) && !d->relinquished) { |
| /* We are supposed to clear the loopback device. Let's do this synchronously: lock |
| * the device, manually remove all partitions and then clear it. This should ensure |
| * udev doesn't concurrently access the devices, and we can be reasonably sure that |
| * once we are done here the device is cleared and all its partition children |
| * removed. Note that we lock our primary device fd here (and not a separate locking |
| * fd, as we do during allocation, since we want to keep the lock all the way through |
| * the LOOP_CLR_FD, but that call would fail if we had more than one fd open.) */ |
| |
| if (flock(d->fd, LOCK_EX) < 0) |
| log_debug_errno(errno, "Failed to lock loop block device, ignoring: %m"); |
| |
| r = block_device_remove_all_partitions(d->dev, d->fd); |
| if (r < 0) |
| log_debug_errno(r, "Failed to remove partitions of loopback block device, ignoring: %m"); |
| |
| if (ioctl(d->fd, LOOP_CLR_FD) < 0) |
| log_debug_errno(errno, "Failed to clear loop device, ignoring: %m"); |
| } |
| |
| safe_close(d->fd); |
| } |
| |
| /* Now that the block device is released, let's also try to remove it */ |
| if (control >= 0) |
| for (unsigned n_attempts = 0;;) { |
| if (ioctl(control, LOOP_CTL_REMOVE, d->nr) >= 0) |
| break; |
| if (errno != EBUSY || ++n_attempts >= 64) { |
| log_debug_errno(errno, "Failed to remove device %s: %m", strna(d->node)); |
| break; |
| } |
| (void) usleep(50 * USEC_PER_MSEC); |
| } |
| |
| free(d->node); |
| sd_device_unref(d->dev); |
| free(d->backing_file); |
| return mfree(d); |
| } |
| |
| DEFINE_TRIVIAL_REF_UNREF_FUNC(LoopDevice, loop_device, loop_device_free); |
| |
| void loop_device_relinquish(LoopDevice *d) { |
| assert(d); |
| |
| /* Don't attempt to clean up the loop device anymore from this point on. Leave the clean-ing up to the kernel |
| * itself, using the loop device "auto-clear" logic we already turned on when creating the device. */ |
| |
| d->relinquished = true; |
| } |
| |
| void loop_device_unrelinquish(LoopDevice *d) { |
| assert(d); |
| d->relinquished = false; |
| } |
| |
| int loop_device_open( |
| sd_device *dev, |
| int open_flags, |
| int lock_op, |
| LoopDevice **ret) { |
| |
| _cleanup_close_ int fd = -EBADF, lock_fd = -EBADF; |
| _cleanup_free_ char *node = NULL, *backing_file = NULL; |
| struct loop_info64 info; |
| uint64_t diskseq = 0; |
| LoopDevice *d; |
| const char *s; |
| dev_t devnum; |
| int r, nr = -1; |
| |
| assert(dev); |
| assert(IN_SET(open_flags, O_RDWR, O_RDONLY)); |
| assert(ret); |
| |
| /* 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 (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)); |
| #endif |
| nr = info.lo_number; |
| |
| if (sd_device_get_sysattr_value(dev, "loop/backing_file", &s) >= 0) { |
| backing_file = strdup(s); |
| if (!backing_file) |
| return -ENOMEM; |
| } |
| } |
| |
| r = fd_get_diskseq(fd, &diskseq); |
| if (r < 0 && r != -EOPNOTSUPP) |
| return r; |
| |
| uint32_t sector_size; |
| r = blockdev_get_sector_size(fd, §or_size); |
| if (r < 0) |
| return r; |
| |
| r = sd_device_get_devnum(dev, &devnum); |
| if (r < 0) |
| return r; |
| |
| r = sd_device_get_devname(dev, &s); |
| if (r < 0) |
| return r; |
| |
| node = strdup(s); |
| if (!node) |
| return -ENOMEM; |
| |
| d = new(LoopDevice, 1); |
| if (!d) |
| return -ENOMEM; |
| |
| *d = (LoopDevice) { |
| .n_ref = 1, |
| .fd = TAKE_FD(fd), |
| .lock_fd = TAKE_FD(lock_fd), |
| .nr = nr, |
| .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 = devnum, |
| .diskseq = diskseq, |
| .uevent_seqnum_not_before = UINT64_MAX, |
| .timestamp_not_before = USEC_INFINITY, |
| .sector_size = sector_size, |
| }; |
| |
| *ret = d; |
| 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) { |
| char sysfs[STRLEN("/sys/dev/block/:/partition") + 2*DECIMAL_STR_MAX(dev_t) + 1]; |
| _cleanup_free_ char *buffer = NULL; |
| uint64_t current_offset, current_size, partno; |
| _cleanup_close_ int whole_fd = -EBADF; |
| struct stat st; |
| dev_t devno; |
| int r; |
| |
| assert(partition_fd >= 0); |
| |
| /* Resizes the partition the loopback device refer to (assuming it refers to one instead of an actual |
| * loopback device), and changes the offset, if needed. This is a fancy wrapper around |
| * BLKPG_RESIZE_PARTITION. */ |
| |
| if (fstat(partition_fd, &st) < 0) |
| return -errno; |
| |
| assert(S_ISBLK(st.st_mode)); |
| |
| xsprintf(sysfs, "/sys/dev/block/" DEVNUM_FORMAT_STR "/partition", DEVNUM_FORMAT_VAL(st.st_rdev)); |
| r = read_one_line_file(sysfs, &buffer); |
| if (r == -ENOENT) /* not a partition, cannot resize */ |
| return -ENOTTY; |
| if (r < 0) |
| return r; |
| r = safe_atou64(buffer, &partno); |
| if (r < 0) |
| return r; |
| |
| xsprintf(sysfs, "/sys/dev/block/" DEVNUM_FORMAT_STR "/start", DEVNUM_FORMAT_VAL(st.st_rdev)); |
| |
| buffer = mfree(buffer); |
| r = read_one_line_file(sysfs, &buffer); |
| if (r < 0) |
| return r; |
| r = safe_atou64(buffer, ¤t_offset); |
| if (r < 0) |
| return r; |
| if (current_offset > UINT64_MAX/512U) |
| return -EINVAL; |
| current_offset *= 512U; |
| |
| if (ioctl(partition_fd, BLKGETSIZE64, ¤t_size) < 0) |
| return -EINVAL; |
| |
| if (size == UINT64_MAX && offset == UINT64_MAX) |
| return 0; |
| if (current_size == size && current_offset == offset) |
| return 0; |
| |
| xsprintf(sysfs, "/sys/dev/block/" DEVNUM_FORMAT_STR "/../dev", DEVNUM_FORMAT_VAL(st.st_rdev)); |
| |
| buffer = mfree(buffer); |
| r = read_one_line_file(sysfs, &buffer); |
| if (r < 0) |
| return r; |
| r = parse_devnum(buffer, &devno); |
| if (r < 0) |
| return r; |
| |
| whole_fd = r = device_open_from_devnum(S_IFBLK, devno, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY, NULL); |
| if (r < 0) |
| return r; |
| |
| return block_device_resize_partition( |
| whole_fd, |
| partno, |
| offset == UINT64_MAX ? current_offset : offset, |
| size == UINT64_MAX ? current_size : size); |
| } |
| |
| int loop_device_refresh_size(LoopDevice *d, uint64_t offset, uint64_t size) { |
| struct loop_info64 info; |
| |
| assert(d); |
| assert(d->fd >= 0); |
| |
| /* Changes the offset/start of the loop device relative to the beginning of the underlying file or |
| * block device. If this loop device actually refers to a partition and not a loopback device, we'll |
| * try to adjust the partition offsets instead. |
| * |
| * If either offset or size is UINT64_MAX we won't change that parameter. */ |
| |
| if (d->nr < 0) /* not a loopback device */ |
| return resize_partition(d->fd, offset, size); |
| |
| if (ioctl(d->fd, LOOP_GET_STATUS64, &info) < 0) |
| return -errno; |
| |
| #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 |
| |
| if (size == UINT64_MAX && offset == UINT64_MAX) |
| return 0; |
| if (info.lo_sizelimit == size && info.lo_offset == offset) |
| return 0; |
| |
| if (size != UINT64_MAX) |
| info.lo_sizelimit = size; |
| if (offset != UINT64_MAX) |
| info.lo_offset = offset; |
| |
| return RET_NERRNO(ioctl(d->fd, LOOP_SET_STATUS64, &info)); |
| } |
| |
| int loop_device_flock(LoopDevice *d, int operation) { |
| assert(IN_SET(operation & ~LOCK_NB, LOCK_UN, LOCK_SH, LOCK_EX)); |
| assert(d); |
| |
| /* When unlocking just close the lock fd */ |
| if ((operation & ~LOCK_NB) == LOCK_UN) { |
| d->lock_fd = safe_close(d->lock_fd); |
| return 0; |
| } |
| |
| /* If we had no lock fd so far, create one and lock it right-away */ |
| if (d->lock_fd < 0) { |
| assert(d->fd >= 0); |
| |
| d->lock_fd = open_lock_fd(d->fd, operation); |
| if (d->lock_fd < 0) |
| return d->lock_fd; |
| |
| return 0; |
| } |
| |
| /* Otherwise change the current lock mode on the existing fd */ |
| return RET_NERRNO(flock(d->lock_fd, operation)); |
| } |
| |
| int loop_device_sync(LoopDevice *d) { |
| assert(d); |
| assert(d->fd >= 0); |
| |
| /* We also do this implicitly in loop_device_unref(). Doing this explicitly here has the benefit that |
| * we can check the return value though. */ |
| |
| return RET_NERRNO(fsync(d->fd)); |
| } |