mount: support the sizelimit and offset option for loop devices
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. function old new delta cut_out_ull_opt - 167 +167 singlemount 1230 1266 +36 set_loop 834 862 +28 losetup_main 479 483 +4 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/0 up/down: 235/0) Total: 235 bytes Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
abefc3c276
commit
6561e07460
@ -1515,7 +1515,8 @@ int del_loop(const char *device) FAST_FUNC;
|
|||||||
* malloc and return it in *devname.
|
* malloc and return it in *devname.
|
||||||
* return value is the opened fd to the loop device, or < on error
|
* 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): */
|
/* These constants match linux/loop.h (without BB_ prefix): */
|
||||||
#define BB_LO_FLAGS_READ_ONLY 1
|
#define BB_LO_FLAGS_READ_ONLY 1
|
||||||
#define BB_LO_FLAGS_AUTOCLEAR 4
|
#define BB_LO_FLAGS_AUTOCLEAR 4
|
||||||
|
@ -102,7 +102,8 @@ int FAST_FUNC get_free_loop(void)
|
|||||||
* search will re-use an existing loop device already bound to that
|
* search will re-use an existing loop device already bound to that
|
||||||
* file/offset if it finds one.
|
* 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 dev[LOOP_NAMESIZE];
|
||||||
char *try;
|
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));
|
memset(&loopinfo, 0, sizeof(loopinfo));
|
||||||
safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
|
safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
|
||||||
loopinfo.lo_offset = offset;
|
loopinfo.lo_offset = offset;
|
||||||
|
loopinfo.lo_sizelimit = sizelimit;
|
||||||
/*
|
/*
|
||||||
* Used by mount to set LO_FLAGS_AUTOCLEAR.
|
* 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.
|
* LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file.
|
||||||
|
@ -150,7 +150,7 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
if (opt & OPT_P) {
|
if (opt & OPT_P) {
|
||||||
flags |= BB_LO_FLAGS_PARTSCAN;
|
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]);
|
bb_simple_perror_msg_and_die(argv[0]);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -1886,6 +1886,58 @@ static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
|
|||||||
|
|
||||||
#endif // !ENABLE_FEATURE_MOUNT_NFS
|
#endif // !ENABLE_FEATURE_MOUNT_NFS
|
||||||
|
|
||||||
|
// Find "...,NAME=NUM,..." in the option string, remove "NAME=NUM" option
|
||||||
|
// and return NUM.
|
||||||
|
// Return 0 if not found.
|
||||||
|
// All instances must be parsed and removed (for example, since kernel 5.4
|
||||||
|
// squashfs: Unknown parameter 'sizelimit'
|
||||||
|
// will result if loopback mount option "sizelimit=NNN" is not removed
|
||||||
|
// and squashfs sees it in option string).
|
||||||
|
static unsigned long long cut_out_ull_opt(char *opts, const char *name_eq)
|
||||||
|
{
|
||||||
|
unsigned long long ret = 0;
|
||||||
|
|
||||||
|
if (!opts) // allow NULL opts (simplifies callers' work)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
char *end;
|
||||||
|
char *opt;
|
||||||
|
|
||||||
|
// Find comma-delimited "NAME="
|
||||||
|
for (;;) {
|
||||||
|
opt = strstr(opts, name_eq);
|
||||||
|
if (!opt)
|
||||||
|
return ret;
|
||||||
|
if (opt == opts)
|
||||||
|
break; // found it (it's first opt)
|
||||||
|
if (opt[-1] == ',') {
|
||||||
|
opts = opt - 1;
|
||||||
|
break; // found it (it's not a first opt)
|
||||||
|
}
|
||||||
|
// False positive like "VNAME=", we are at "N".
|
||||||
|
// - skip it, loop back to searching
|
||||||
|
opts = opt + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bb_strtoull(opt + strlen(name_eq), &end, 0);
|
||||||
|
if (errno && errno != EINVAL) {
|
||||||
|
err:
|
||||||
|
bb_error_msg_and_die("bad option '%s'", opt);
|
||||||
|
}
|
||||||
|
if (*end == '\0') {
|
||||||
|
// It is "[,]NAME=NUM\0" - truncate it and return
|
||||||
|
*opts = '\0';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (*end != ',')
|
||||||
|
goto err;
|
||||||
|
// We are at trailing comma
|
||||||
|
// Remove "NAME=NUM," and loop back to check for duplicate opts
|
||||||
|
overlapping_strcpy(opt, end + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
|
// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
|
||||||
// type detection. Returns 0 for success, nonzero for failure.
|
// type detection. Returns 0 for success, nonzero for failure.
|
||||||
// NB: mp->xxx fields may be trashed on exit
|
// NB: mp->xxx fields may be trashed on exit
|
||||||
@ -2029,9 +2081,16 @@ static int singlemount(struct mntent *mp, int ignore_busy)
|
|||||||
) {
|
) {
|
||||||
// Do we need to allocate a loopback device for it?
|
// Do we need to allocate a loopback device for it?
|
||||||
if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
|
if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
|
||||||
|
unsigned long long offset;
|
||||||
|
unsigned long long sizelimit;
|
||||||
|
|
||||||
loopFile = bb_simplify_path(mp->mnt_fsname);
|
loopFile = bb_simplify_path(mp->mnt_fsname);
|
||||||
mp->mnt_fsname = NULL; // will receive malloced loop dev name
|
mp->mnt_fsname = NULL; // will receive malloced loop dev name
|
||||||
|
|
||||||
|
// Parse and remove loopback options
|
||||||
|
offset = cut_out_ull_opt(filteropts, "offset=");
|
||||||
|
sizelimit = cut_out_ull_opt(filteropts, "sizelimit=");
|
||||||
|
|
||||||
// mount always creates AUTOCLEARed loopdevs, so that umounting
|
// mount always creates AUTOCLEARed loopdevs, so that umounting
|
||||||
// drops them without any code in the userspace.
|
// drops them without any code in the userspace.
|
||||||
// This happens since circa linux-2.6.25:
|
// This happens since circa linux-2.6.25:
|
||||||
@ -2040,7 +2099,8 @@ static int singlemount(struct mntent *mp, int ignore_busy)
|
|||||||
// Subject: Allow auto-destruction of loop devices
|
// Subject: Allow auto-destruction of loop devices
|
||||||
loopfd = set_loop(&mp->mnt_fsname,
|
loopfd = set_loop(&mp->mnt_fsname,
|
||||||
loopFile,
|
loopFile,
|
||||||
0,
|
offset,
|
||||||
|
sizelimit,
|
||||||
((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0)
|
((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0)
|
||||||
| BB_LO_FLAGS_AUTOCLEAR
|
| BB_LO_FLAGS_AUTOCLEAR
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user