[PATCH] mount: support the sizelimit and offset option for loop devices

Steffen Trumtrar s.trumtrar at pengutronix.de
Wed Jul 29 08:43:53 UTC 2020


Starting with linux kernel v5.4 squashfs has a more strict parameter
checking implemented. Unlike util-linux mount, busybox never supported
the sizelimit option but simply forwards it to the kernel.
Since v5.4 mounting will fail with

    squashfs: Unknown parameter 'sizelimit'

Support the sizelimit parameter by setting it in the LOOP_SET_STATUS64
structure before handing it to the kernel.

While at it also add support for the offset option, which currently will
always be set to 0.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 include/libbb.h      |  3 ++-
 libbb/loop.c         |  4 +++-
 util-linux/losetup.c |  2 +-
 util-linux/mount.c   | 38 +++++++++++++++++++++++++++++++++++++-
 4 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index 6be934994499..fe7fcff40ee0 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1515,7 +1515,8 @@ int del_loop(const char *device) FAST_FUNC;
  * malloc and return it in *devname.
  * return value is the opened fd to the loop device, or < on error
  */
-int set_loop(char **devname, const char *file, unsigned long long offset, unsigned flags) FAST_FUNC;
+int set_loop(char **devname, const char *file, unsigned long long offset,
+	     unsigned long long sizelimit, unsigned flags) FAST_FUNC;
 /* These constants match linux/loop.h (without BB_ prefix): */
 #define BB_LO_FLAGS_READ_ONLY 1
 #define BB_LO_FLAGS_AUTOCLEAR 4
diff --git a/libbb/loop.c b/libbb/loop.c
index ada0c7638f3b..c65982c32b71 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -102,7 +102,8 @@ int FAST_FUNC get_free_loop(void)
  * search will re-use an existing loop device already bound to that
  * file/offset if it finds one.
  */
-int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, unsigned flags)
+int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset,
+		       unsigned long long sizelimit, unsigned flags)
 {
 	char dev[LOOP_NAMESIZE];
 	char *try;
@@ -185,6 +186,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
 				memset(&loopinfo, 0, sizeof(loopinfo));
 				safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
 				loopinfo.lo_offset = offset;
+				loopinfo.lo_sizelimit = sizelimit;
 				/*
 				 * Used by mount to set LO_FLAGS_AUTOCLEAR.
 				 * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file.
diff --git a/util-linux/losetup.c b/util-linux/losetup.c
index cc6c2b1d54e6..ec0cf04e4502 100644
--- a/util-linux/losetup.c
+++ b/util-linux/losetup.c
@@ -151,7 +151,7 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
 			if (opt & OPT_P) {
 				flags |= BB_LO_FLAGS_PARTSCAN;
 			}
-			if (set_loop(&d, argv[0], offset, flags) < 0)
+			if (set_loop(&d, argv[0], offset, 0, flags) < 0)
 				bb_simple_perror_msg_and_die(argv[0]);
 			return EXIT_SUCCESS;
 		}
diff --git a/util-linux/mount.c b/util-linux/mount.c
index 84c85c0578ea..bd6dfa3ba0bd 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -2030,9 +2030,44 @@ static int singlemount(struct mntent *mp, int ignore_busy)
 	) {
 		// Do we need to allocate a loopback device for it?
 		if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
+			char *opt;
+			unsigned long long offset = 0;
+			unsigned long long sizelimit = 0;
+
 			loopFile = bb_simplify_path(mp->mnt_fsname);
 			mp->mnt_fsname = NULL; // will receive malloced loop dev name
 
+			/* parse options */
+			if (filteropts)
+				for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
+					char *opteq = strchr(opt, '=');
+					int len = strlen(opt);
+					char *match;
+
+					if (opteq) {
+						int idx;
+						static const char options[] ALIGN1 =
+							/* 0 */ "offset\0"
+							/* 1 */ "sizelimit\0";
+
+						*opteq++ = '\0';
+						idx = index_in_strings(options, opt);
+						switch (idx) {
+						case 0: // "offset"
+							offset = strtoull(opteq, 0, 0);
+							match = strstr(filteropts, opt);
+							*match = '\0';
+							strcat(filteropts, match+len);
+							continue;
+						case 1: // "sizelimit"
+							sizelimit = strtoull(opteq, 0, 0);
+							match = strstr(filteropts, opt);
+							*match = '\0';
+							strcat(filteropts, match+len);
+							continue;
+						}
+					}
+				}
 			// mount always creates AUTOCLEARed loopdevs, so that umounting
 			// drops them without any code in the userspace.
 			// This happens since circa linux-2.6.25:
@@ -2041,7 +2076,8 @@ static int singlemount(struct mntent *mp, int ignore_busy)
 			// Subject: Allow auto-destruction of loop devices
 			loopfd = set_loop(&mp->mnt_fsname,
 					loopFile,
-					0,
+					offset,
+					sizelimit,
 					((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0)
 						| BB_LO_FLAGS_AUTOCLEAR
 			);
-- 
2.27.0



More information about the busybox mailing list