#include "alloc-util.h"
#include "blockdev-util.h"
+#include "data-fd-util.h"
#include "device-util.h"
#include "devnum-util.h"
#include "env-util.h"
}
static int open_lock_fd(int primary_fd, int operation) {
- _cleanup_close_ int lock_fd = -1;
+ _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_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ lock_fd = fd_reopen(primary_fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (lock_fd < 0)
return lock_fd;
assert(fd >= 0);
assert(c);
+ if (c->block_size != 0) {
+ int z;
+
+ if (ioctl(fd, BLKSSZGET, &z) < 0)
+ return -errno;
+
+ assert(z >= 0);
+ if ((uint32_t) z != c->block_size)
+ log_debug("LOOP_CONFIGURE didn't honour requested block size %u, got %i instead. Ignoring.", c->block_size, z);
+ }
+
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
return -errno;
if (z != c->info.lo_sizelimit) {
- log_debug("LOOP_CONFIGURE is broken, doesn't honour .lo_sizelimit. Falling back to LOOP_SET_STATUS64.");
+ log_debug("LOOP_CONFIGURE is broken, doesn't honour .info.lo_sizelimit. Falling back to LOOP_SET_STATUS64.");
broken = true;
}
}
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 lo_offset field, if someone else is accessing the
+ * 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
static bool loop_configure_broken = false;
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
- _cleanup_(cleanup_clear_loop_close) int loop_with_fd = -1; /* This must be declared before lock_fd. */
- _cleanup_close_ int fd = -1, lock_fd = -1;
+ _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;
int open_flags,
uint64_t offset,
uint64_t size,
+ uint32_t block_size,
uint32_t loop_flags,
int lock_op,
LoopDevice **ret) {
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
- _cleanup_close_ int direct_io_fd = -1, control = -1;
+ _cleanup_close_ int direct_io_fd = -EBADF, control = -EBADF;
_cleanup_free_ char *backing_file = NULL;
struct loop_config config;
int r, f_flags;
config = (struct loop_config) {
.fd = fd,
+ .block_size = block_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,
int open_flags,
uint64_t offset,
uint64_t size,
+ uint32_t block_size,
uint32_t loop_flags,
int lock_op,
LoopDevice **ret) {
open_flags,
offset,
size,
+ block_size,
loop_flags_mangle(loop_flags),
lock_op,
ret);
LoopDevice **ret) {
int r, basic_flags, direct_flags, rdwr_flags;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
bool direct = false;
assert(path);
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, loop_flags, lock_op, ret);
+ return loop_device_make_internal(path, fd, open_flags, 0, 0, 0, loop_flags, lock_op, ret);
+}
+
+int loop_device_make_by_path_memory(
+ const char *path,
+ int open_flags,
+ 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, 0, loop_flags, lock_op, ret);
}
static LoopDevice* loop_device_free(LoopDevice *d) {
int lock_op,
LoopDevice **ret) {
- _cleanup_close_ int fd = -1, lock_fd = -1;
+ _cleanup_close_ int fd = -EBADF, lock_fd = -EBADF;
_cleanup_free_ char *node = NULL, *backing_file = NULL;
struct loop_info64 info;
uint64_t diskseq = 0;
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 = -1;
+ _cleanup_close_ int whole_fd = -EBADF;
struct stat st;
dev_t devno;
int r;