Skip to contentSkip to conversation

libmount: preserve reused loop devices and request direct I/O

PATCH New Tianyi Chen 1 participant 3 messages Oct 4 Util-Linux package

lore
Share & tools
lore
#0 lore raw

v2 cover libmount: preserve reused loop devices and request direct I/O

Hi Karel,

This revision addresses your review of PR #4646. The reused-device fix is now separate from the direct-I/O option.

Changes in v2:
- Add a specific diagnostic for direct-I/O mode conflicts.
- Use ul_strtobool() and the test-suite cleanup helpers.
- Document buffered-I/O fallback and how to check the effective mode.
- Add the option comment header and reused-device debug message.
- Remove the AI attribution trailer as requested.

Built mount, umount, losetup and findmnt with Meson. As root in a private mount namespace, loop-reuse, loop-direct-io, regfile and fstab-loop all passed. The direct-I/O test also checks boolean aliases and the conflict diagnostic.

Thanks,
Tianyi

Tianyi Chen (2):
libmount: keep reused loop devices attached on mount failure
libmount: support explicit loop direct I/O requests

 libmount/src/hook_loopdev.c         | 41 +++++++++++++-
 sys-utils/mount.8.adoc              | 13 ++++-
 tests/expected/mount/loop-direct-io |  6 +++
 tests/expected/mount/loop-reuse     |  1 +
 tests/ts/mount/loop-direct-io       | 84 +++++++++++++++++++++++++++++
 tests/ts/mount/loop-reuse           | 23 ++++++++
 6 files changed, 165 insertions(+), 3 deletions(-)
 create mode 100644 tests/expected/mount/loop-direct-io
 create mode 100644 tests/expected/mount/loop-reuse
 create mode 100755 tests/ts/mount/loop-direct-io
 create mode 100755 tests/ts/mount/loop-reuse

base-commit: 55e3c4dba6101a47ecaae71c91edbe10c59b8d56

Signature · 1 line
2.55.0
#1 lore raw

PATCH v2 1/2 libmount: keep reused loop devices attached on mount failure

A loop device found by overlap detection may have been set up by the caller. Do not detach it when a later mount step fails; only close the reference acquired by this mount.

Add a regression test using a preconfigured device and an invalid filesystem option.

---
 libmount/src/hook_loopdev.c     |  7 +++++++
 tests/expected/mount/loop-reuse |  1 +
 tests/ts/mount/loop-reuse       | 23 +++++++++++++++++++++++
 3 files changed, 31 insertions(+)
 create mode 100644 tests/expected/mount/loop-reuse
 create mode 100755 tests/ts/mount/loop-reuse
libmount/src/hook_loopdev.c +7 -0
index b2291340..809d64d8 100644
@@ -21,6 +21,7 @@
 
 struct hook_data {
 	int loopdev_fd;
+	bool reused;
 };
 
 static int delete_loopdev(struct libmnt_context *cxt, struct hook_data *hd);
@@ -350,6 +351,7 @@ static int setup_loopdev(struct libmnt_context *cxt,
 	} while (1);
 
 success:
+	hd->reused = reuse;
 	if (!rc)
 		rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc));
 
@@ -408,6 +410,11 @@ static int delete_loopdev(struct libmnt_context *cxt, struct hook_data *hd)
 		hd->loopdev_fd = -1;
 	}
 
+	if (hd && hd->reused) {
+		DBG_OBJ(LOOP, cxt, ul_debug("keeping reused device"));
+		return 0;
+	}
+
 	rc = loopdev_detach(src);	/* see lib/loopdev.c */
 
 	DBG_OBJ(LOOP, cxt, ul_debug("deleted [rc=%d]", rc));
tests/expected/mount/loop-reuse new file +1 -0
new file mode 100644
index 00000000..9b132bb6
@@ -0,0 +1 @@
+reused device preserved: OK
tests/ts/mount/loop-reuse new file +23 -0
new file mode 100755
index 00000000..704b3378
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="keep reused loop device on failure"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+ts_check_test_command "$TS_CMD_MOUNT"
+ts_check_test_command "$TS_CMD_UMOUNT"
+ts_skip_nonroot
+ts_check_losetup
+ts_check_prog "mkfs.ext2"
+
+ts_device_init
+mkfs.ext2 -F "$TS_LODEV" &> /dev/null || ts_die "Cannot make filesystem"
+mkdir -p "$TS_MOUNTPOINT"
+$TS_CMD_MOUNT -t ext2 -o loop,invalid-fs-option "$TS_OUTDIR/$TS_TESTNAME.img" \
+	"$TS_MOUNTPOINT" &> /dev/null && ts_die "Accepted invalid filesystem option"
+[ "$($TS_CMD_LOSETUP -j "$TS_OUTDIR/$TS_TESTNAME.img" | cut -d: -f1)" = "$TS_LODEV" ] ||
+	ts_die "Failed mount detached reused device"
+ts_log "reused device preserved: OK"
+ts_finalize
Signature · 1 line
2.55.0
#2 lore raw

PATCH v2 2/2 libmount: support explicit loop direct I/O requests

In reply to Tianyi Chen

Allow X-loopdev.direct-io=on|off to select the direct I/O mode when mounting a file through a loop device. Pass the flag to the existing loop setup path and require a matching mode when reusing a device. Omitting the option preserves the current behavior.

Add an explicit diagnostic for direct I/O mode conflicts and document that the option is a request whose result should be checked with losetup. Parse the boolean with ul_strtobool and cover the option with the standard loop-device test cleanup helpers.

---
 libmount/src/hook_loopdev.c         | 34 +++++++++++-
 sys-utils/mount.8.adoc              | 13 ++++-
 tests/expected/mount/loop-direct-io |  6 +++
 tests/ts/mount/loop-direct-io       | 84 +++++++++++++++++++++++++++++
 4 files changed, 134 insertions(+), 3 deletions(-)
 create mode 100644 tests/expected/mount/loop-direct-io
 create mode 100755 tests/ts/mount/loop-direct-io
libmount/src/hook_loopdev.c +32 -2
index 809d64d8..981ad6c1 100644
@@ -139,7 +139,7 @@ static int setup_loopdev(struct libmnt_context *cxt,
 {
 	const char *backing_file, *loopdev = NULL;
 	struct loopdev_cxt lc;
-	int rc = 0, lo_flags = 0;
+	int rc = 0, lo_flags = 0, direct_io = -1;
 	uint64_t offset = 0, sizelimit = 0;
 	bool reuse = FALSE;
 	struct libmnt_opt *opt, *loopopt = NULL;
@@ -155,6 +155,23 @@ static int setup_loopdev(struct libmnt_context *cxt,
 		lo_flags |= LO_FLAGS_READ_ONLY;
 	}
 
+	/*
+	 * X-loopdev.direct-io=
+	 */
+	opt = mnt_optlist_get_named(ol, "X-loopdev.direct-io", cxt->map_userspace);
+	if (opt) {
+		const char *value = mnt_opt_get_value(opt);
+		bool enabled;
+
+		if (ul_strtobool(value, &enabled) != 0) {
+			rc = -MNT_ERR_MOUNTOPT;
+			goto done_no_deinit;
+		}
+		direct_io = enabled;
+		if (enabled)
+			lo_flags |= LO_FLAGS_DIRECT_IO;
+	}
+
 	/*
 	 * loop=
 	 */
@@ -258,6 +275,18 @@ static int setup_loopdev(struct libmnt_context *cxt,
 				goto done;
 			}
 
+			if (direct_io != -1 && !!loopcxt_is_dio(&lc) != direct_io) {
+				const char *dev = loopcxt_get_device(&lc);
+
+				DBG_OBJ(LOOP, cxt, ul_debug("%s has incompatible direct I/O mode",
+						dev));
+				/* TRANSLATORS: Do not translate "e ". It is a message classifier. */
+				mnt_context_sprintf_mesg(cxt,
+						_("e loop device %s has incompatible direct I/O mode"), dev);
+				rc = -MNT_ERR_LOOPOVERLAP;
+				goto done;
+			}
+
 			/* This is no more supported, but check to be safe. */
 			if (loopcxt_get_encrypt_type(&lc, &lc_encrypt_type) == 0
 			    && lc_encrypt_type != LO_CRYPT_NONE) {
@@ -454,7 +483,8 @@ static int is_loopdev_required(struct libmnt_context *cxt, struct libmnt_optlist
 		return 0;
 
 	/* loop= (sizelimit= or offset=) explicitly specified */
-	if (flags & (MNT_MS_LOOP | MNT_MS_OFFSET | MNT_MS_SIZELIMIT)) {
+	if (flags & (MNT_MS_LOOP | MNT_MS_OFFSET | MNT_MS_SIZELIMIT)
+	    || mnt_optlist_get_named(ol, "X-loopdev.direct-io", cxt->map_userspace)) {
 		DBG_OBJ(LOOP, cxt, ul_debug("loopdev specific options detected"));
 		return 1;
 	}
sys-utils/mount.8.adoc +12 -1
index 922ecda7..6261bac3 100644
@@ -796,6 +796,17 @@ ____
 mount -t auto -o'X-mount.auto-fstypes="noext2,ext3"'  /dev/sdc1 /mnt/test
 ____
 
+*X-loopdev.direct-io*=*on*|*off*::
+Request enabling or disabling direct I/O when setting up a loop device. The
+kernel may fall back to buffered I/O, for example when the backing file
+offset is unaligned or the block size is too small. Direct I/O is a request,
+not a guarantee; check the effective mode with *losetup --list -O NAME,DIO*. If a loop device already exists for
+the same file, offset and size limit, its direct I/O mode must match; otherwise
+the mount fails without changing the existing device. Without this option, new
+loop devices use buffered I/O and existing devices can be reused in either
+mode. This option does not change an existing mount or apply when no loop
+device is needed. See also *losetup*(8) *--direct-io*.
+
 *X-mount.mkdir*[**=**_mode_]::
 Allow to make a target directory (mountpoint) if it does not exist yet. The optional argument _mode_ specifies the filesystem access mode used for *mkdir*(2) in octal notation. The default mode is 0755. This functionality is supported only for root users or when *mount* is executed without suid permissions. The option is also supported as *x-mount.mkdir*, but this notation is deprecated since v2.30. See also *--mkdir* command line option.
 
@@ -1708,7 +1719,7 @@ ____
 *mount -t ext4 /tmp/disk.img /mnt*
 ____
 
-This type of mount knows about three options, namely *loop*, *offset* and *sizelimit*, that are really options to *losetup*(8). (These options can be used in addition to those specific to the filesystem type.)
+Loop device setup accepts *loop*, *offset*, *sizelimit* and *X-loopdev.direct-io*, corresponding to options of *losetup*(8). (These options can be used in addition to those specific to the filesystem type.)
 
 Since Linux 2.6.25 auto-destruction of loop devices is supported, meaning that any loop device allocated by *mount* will be freed by *umount* independently of _/etc/mtab_.
 
tests/expected/mount/loop-direct-io new file +6 -0
new file mode 100644
index 00000000..990eda84
@@ -0,0 +1,6 @@
+invalid options: OK
+new device (on): OK
+new device (off): OK
+new device (default): OK
+reuse and failed mount (on): OK
+reuse and failed mount (off): OK
tests/ts/mount/loop-direct-io new file +84 -0

84 lines not on this page · raw message

Signature · 1 line
2.55.0