Re: [PATCH 9/9] loop: Add LOOP_CONFIGURE ioctl
On Fri, 18 Nov 2022 09:01:58 +0800 Xiaoming Ni wrote: > LOOP_CONFIGURE is added to Linux 5.8 ... > diff --git a/libbb/loop.c b/libbb/loop.c > index 9a7ca666d..d4f4906b0 100644 > --- a/libbb/loop.c > +++ b/libbb/loop.c > @@ -126,6 +126,30 @@ static int open_file(const char *file, unsigned flags, > int *mode) > return ffd; > } > > +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0) > +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) > +#else This assumes compile-time matches runtime. Ie, if you build on a 5.8 system, but run on an earlier kernel, the resulting busybox would be unable to mount loops at all. Please put it backward runtime compatibility, probably by having the new-kernel code in the same func. - Lauri ___ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox
[PATCH 8/9] loop:refactor: extract subfunction set_loop_dev()
Step 8 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop_dev() function old new delta set_loop 700 703 +3 -- (add/remove: 0/0 grow/shrink: 1/0 up/down: 3/0) Total: 3 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 41 - 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 67e16ddb0..9a7ca666d 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -201,6 +201,26 @@ static int do_stat_and_mknod(const char *dev, const char *device, int i) return 0; } +static int set_loop_dev(const char *dev, int *mode, int ffd, bb_loop_info *loopinfo) +{ + int rc; + /* Open the sucker and check its loopiness */ + int lfd = open(dev, *mode); + if (lfd < 0 && errno == EROFS) { + *mode = O_RDONLY; + lfd = open(dev, *mode); + } + if (lfd < 0) { + return lfd; + } + rc = set_loop_info(ffd, lfd, loopinfo); + if (rc == lfd) { + return lfd; + } + close(lfd); + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to @@ -211,7 +231,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - int i, lfd, ffd, mode, rc; + int i, ffd, mode, rc; bb_loop_info loopinfo; ffd = open_file(file, flags, ); @@ -242,32 +262,19 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse break; } open_lfd: - /* Open the sucker and check its loopiness */ - lfd = rc = open(try, mode); - if (lfd < 0 && errno == EROFS) { - mode = O_RDONLY; - lfd = rc = open(try, mode); - } - if (lfd < 0) { + rc = set_loop_dev(try, , ffd, ); + if (rc == -1) { if (errno == ENXIO) { /* Happens if loop module is not loaded */ /* rc is -1; */ break; } - goto try_next_loopN; - } - rc = set_loop_info(ffd, lfd, ); - if (rc == lfd) { + } else { /* SUCCESS! */ if (!*device) *device = xstrdup(try); break; } - close(lfd); - try_next_loopN: - rc = -1; - if (*device) /* was looking for a particular "/dev/loopN"? */ - break; /* yes, do not try other names */ } /* for() */ close(ffd); -- 2.27.0 ___ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox
[PATCH 1/9] loop:refactor: extract subfunction open_file()
Step 1 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop() function old new delta set_loop 760 758 -2 -- (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-2) Total: -2 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 25 + 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 750642ade..c517ceb13 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -96,6 +96,22 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int open_file(const char *file, unsigned flags, int *mode) +{ + int ffd; + /* open the file. barf if this doesn't work. */ + *mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; + retry_open_ffd: + ffd = open(file, *mode); + if (ffd < 0) { + if (*mode != O_RDONLY) { + *mode = O_RDONLY; + goto retry_open_ffd; + } + } + return ffd; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -109,15 +125,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse struct stat statbuf; int i, lfd, ffd, mode, rc; - /* Open the file. Barf if this doesn't work. */ - mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; - open_ffd: - ffd = open(file, mode); + ffd = open_file(file, flags, ); if (ffd < 0) { - if (mode != O_RDONLY) { - mode = O_RDONLY; - goto open_ffd; - } return -errno; } -- 2.27.0 ___ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox
[PATCH 9/9] loop: Add LOOP_CONFIGURE ioctl
LOOP_CONFIGURE is added to Linux 5.8 This allows userspace to completely setup a loop device with a single ioctl, removing the in-between state where the device can be partially configured - eg the loop device has a backing file associated with it, but is reading from the wrong offset. https://lwn.net/Articles/820408/ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0): function old new delta set_loop 703 626 -77 -- (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-77) Total: -77 bytes else: add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0 (0) Signed-off-by: Xiaoming Ni --- libbb/loop.c | 25 + 1 file changed, 25 insertions(+) diff --git a/libbb/loop.c b/libbb/loop.c index 9a7ca666d..d4f4906b0 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,30 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0) + +/* + * loop: Add LOOP_CONFIGURE ioctl + * https://lwn.net/Articles/820408/ + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 + */ +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) +{ + int rc; + struct loop_config config; + + memset(, 0, sizeof(config)); + config.fd = ffd; + memcpy(, loopinfo, sizeof(config.info)); + + rc = ioctl(lfd, LOOP_CONFIGURE, ); + if (rc == 0) { + return lfd; + } + return -1; +} + +#else static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; @@ -149,6 +173,7 @@ static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary return -1; } +#endif static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) { -- 2.27.0 ___ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox
[PATCH 3/9] loop:refactor: del close_and_try_next_loopN
Step 3 of micro-refactoring the set_loop() function: Delete close_and_try_next_loopN. (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 71fd8c1bc..91c3a45c4 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -197,13 +197,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc && errno == ENXIO) { /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { + close(lfd); /* Ouch. Are we racing with other mount? */ if (!*device) { - close(lfd); //TODO: add "if (--failcount != 0) ..."? continue; + } else { + break; } - goto close_and_try_next_loopN; } memset(, 0, sizeof(loopinfo)); safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); @@ -233,7 +234,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary } - close_and_try_next_loopN: close(lfd); try_next_loopN: rc = -1; -- 2.27.0 ___ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox
[PATCH 7/9] loop:refactor: Extract subfunction do_stat_and_mknod()
Step 7 of micro-refactoring the set_loop(): Extract subfunction do_stat_and_mknod() function old new delta set_loop 720 700 -20 -- (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 39 +-- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 2200ccb9a..67e16ddb0 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -180,6 +180,28 @@ static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); } +static int do_stat_and_mknod(const char *dev, const char *device, int i) +{ + struct stat statbuf; + + IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) + if (stat(dev, ) != 0 || !S_ISBLK(statbuf.st_mode)) { + if (ENABLE_FEATURE_MOUNT_LOOP_CREATE + && errno == ENOENT + && (!device) + ) { + /* Node doesn't exist, try to create it */ + if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) { + return 0; + } + } + /* Ran out of block devices, return failure */ + return -1; + } + return 0; +} + + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -189,7 +211,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - struct stat statbuf; int i, lfd, ffd, mode, rc; bb_loop_info loopinfo; @@ -216,18 +237,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } } - IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) - if (stat(try, ) != 0 || !S_ISBLK(statbuf.st_mode)) { - if (ENABLE_FEATURE_MOUNT_LOOP_CREATE -&& errno == ENOENT -&& (!*device) - ) { - /* Node doesn't exist, try to create it */ - if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) - goto open_lfd; - } - /* Ran out of block devices, return failure */ - rc = -1; + rc = do_stat_and_mknod(try, *device, i); + if (rc == -1) { break; } open_lfd: @@ -249,7 +260,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc == lfd) { /* SUCCESS! */ if (!*device) - *device = xstrdup(dev); + *device = xstrdup(try); break; } close(lfd); -- 2.27.0 ___ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox
[PATCH 5/9] loop:refactor: extract subfunction set_loop_configure()
Step 5 of micro-refactoring the set_loop(): Extract subfunction set_loop_configure() function old new delta set_loop 700 708 +8 -- (add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0) Total: 8 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 63 ++-- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 89adc4f94..914af57b2 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,41 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_configure(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(, 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. +* Note that closing LO_FLAGS_AUTOCLEARed lfd before mount +* is wrong (would free the loop device!) +*/ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, ); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, ); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return -1; +} + static int set_loop_info(int ffd, int lfd, const char *file, unsigned long long offset, unsigned long long sizelimit, unsigned flags) { @@ -136,33 +171,7 @@ static int set_loop_info(int ffd, int lfd, const char *file, /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - return -1; - } - memset(, 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. -* Note that closing LO_FLAGS_AUTOCLEARed lfd before mount -* is wrong (would free the loop device!) -*/ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, ); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, ); - } - if (rc == 0) { - return lfd; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); } return -1; } -- 2.27.0 ___ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox
[PATCH 2/9] loop:refactor: extract subfunction get_next_free_loop()
Step 2 of micro-refactoring the set_loop function () Extract subfunction get_next_free_loop() from set_loop() Also fix miss free(try) when stat(try) and mknod fail function old new delta set_loop 758 734 -24 -- (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-24) Total: -24 bytes Fixes: 3448914e8cc5 ("mount,losetup: use /dev/loop-control is it exists") Signed-off-by: Xiaoming Ni --- libbb/loop.c | 55 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index c517ceb13..71fd8c1bc 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -96,6 +96,20 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int get_next_free_loop(char *dev, int id) +{ + int i = get_free_loop(); + if (i >= 0) { + sprintf(dev, LOOP_FORMAT, i); + return 1; /* use /dev/loop-control */ + } else if (i == -2) { + sprintf(dev, LOOP_FORMAT, id); + return 2; + } else { + return -1; /* no free loop devices */ + } +} + static int open_file(const char *file, unsigned flags, int *mode) { int ffd; @@ -132,30 +146,26 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse try = *device; if (!try) { - get_free_loopN: - i = get_free_loop(); - if (i == -1) { - close(ffd); - return -1; /* no free loop devices */ - } - if (i >= 0) { - try = xasprintf(LOOP_FORMAT, i); - goto open_lfd; - } - /* i == -2: no /dev/loop-control. Do an old-style search for a free device */ try = dev; } /* Find a loop device */ /* 0xf is a max possible minor number in Linux circa 2010 */ for (i = 0; i <= 0xf; i++) { - sprintf(dev, LOOP_FORMAT, i); + if (!*device) { + rc = get_next_free_loop(dev, i); + if (rc == -1) { + break; /* no free loop devices */ + } else if (rc == 1) { + goto open_lfd; + } + } IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) if (stat(try, ) != 0 || !S_ISBLK(statbuf.st_mode)) { if (ENABLE_FEATURE_MOUNT_LOOP_CREATE && errno == ENOENT -&& try == dev +&& (!*device) ) { /* Node doesn't exist, try to create it */ if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) @@ -188,13 +198,10 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { /* Ouch. Are we racing with other mount? */ - if (!*device /* yes */ -&& try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); + if (!*device) { close(lfd); //TODO: add "if (--failcount != 0) ..."? - goto get_free_loopN; + continue; } goto close_and_try_next_loopN; } @@ -218,8 +225,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } if (rc == 0) { /* SUCCESS! */ - if (try != dev) /* tried a kernel-offered free loopN? */ - *device = try; /* malloced */ if (!*device) /* was looping in search of free "/dev/loopN"? */ *device = xstrdup(dev); rc = lfd; /* return this */ @@ -227,16 +232,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary - } else { - /* device is not free (rc == 0), or error other than ENXIO */ - if (rc == 0
[PATCH 4/9] loop:refactor: extract subfunction set_loop_info()
Step 4 of micro-refactoring the set_loop(): Extract subfunction set_loop_info() from set_loop() function old new delta set_loop 734 700 -34 -- (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-34) Total: -34 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 91 +++- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 91c3a45c4..89adc4f94 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,47 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_info(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + + rc = ioctl(lfd, BB_LOOP_GET_STATUS, ); + + /* If device is free, try to claim it */ + if (rc && errno == ENXIO) { + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(, 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. +* Note that closing LO_FLAGS_AUTOCLEARed lfd before mount +* is wrong (would free the loop device!) +*/ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, ); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, ); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + } + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -135,7 +176,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - bb_loop_info loopinfo; struct stat statbuf; int i, lfd, ffd, mode, rc; @@ -190,49 +230,12 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - - rc = ioctl(lfd, BB_LOOP_GET_STATUS, ); - - /* If device is free, try to claim it */ - if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - close(lfd); - /* Ouch. Are we racing with other mount? */ - if (!*device) { -//TODO: add "if (--failcount != 0) ..."? - continue; - } else { - break; - } - } - memset(, 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. -* Note that closing LO_FLAGS_AUTOCLEARed lfd before mount -* is wrong (would free the loop device!) -*/ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, ); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ -
[PATCH 6/9] loop:refactor: Use a structure to reduce parameters
Step 6 of micro-refactoring the set_loop(): Use structs to avoid transferring a large number of parameters in set_loop_configure() and set_loop_info() function old new delta set_loop 708 720 +12 -- (add/remove: 0/0 grow/shrink: 1/0 up/down: 12/0) Total: 12 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 54 +--- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 914af57b2..2200ccb9a 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,32 +126,21 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } -static int set_loop_configure(int ffd, int lfd, const char *file, - unsigned long long offset, unsigned long long sizelimit, unsigned flags) +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; - bb_loop_info loopinfo; + bb_loop_info loopinfo2; /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { return -1; } - memset(, 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. -* Note that closing LO_FLAGS_AUTOCLEARed lfd before mount -* is wrong (would free the loop device!) -*/ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, ); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + rc = ioctl(lfd, BB_LOOP_SET_STATUS, loopinfo); + if (rc != 0 && (loopinfo->lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + memcpy(, loopinfo, sizeof(*loopinfo)); /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, ); + loopinfo2.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, ); } if (rc == 0) { return lfd; @@ -161,21 +150,36 @@ static int set_loop_configure(int ffd, int lfd, const char *file, return -1; } -static int set_loop_info(int ffd, int lfd, const char *file, - unsigned long long offset, unsigned long long sizelimit, unsigned flags) +static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; - bb_loop_info loopinfo; + bb_loop_info tmp; - rc = ioctl(lfd, BB_LOOP_GET_STATUS, ); + rc = ioctl(lfd, BB_LOOP_GET_STATUS, ); /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); + return set_loop_configure(ffd, lfd, loopinfo); } return -1; } +static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + 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. +* Note that closing LO_FLAGS_AUTOCLEARed lfd before mount +* is wrong (would free the loop device!) +*/ + loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -187,12 +191,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse char *try; struct stat statbuf; int i, lfd, ffd, mode, rc; + bb_loop_info loopinfo; ffd = open_file(file, flags, ); if (ffd < 0) { return -errno; } + init_bb_loop_info(, file, offset, sizelimit, flags); try = *device; if (!try) { try = dev; @@ -239,7 +245,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); +
[PATCH 0/9] loop: Micro-refactoring set_loop() and add LOOP_CONFIGURE
LOOP_CONFIGURE is added to Linux 5.8 This allows userspace to completely setup a loop device with a single ioctl, removing the in-between state where the device can be partially configured - eg the loop device has a backing file associated with it, but is reading from the wrong offset. https://lwn.net/Articles/820408/ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 To facilitate the addition of new functions, the code of set_loop() is micro-refactored. LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0): function old new delta set_loop 760 626-134 -- (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-134) Total: -134 bytes else function old new delta set_loop 760 703 -57 -- (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-57) Total: -57 bytes Xiaoming Ni (9): loop:refactor: extract subfunction open_file() loop:refactor: extract subfunction get_next_free_loop() loop:refactor: del close_and_try_next_loopN loop:refactor: extract subfunction set_loop_info() loop:refactor: extract subfunction set_loop_configure() loop:refactor: Use a structure to reduce parameters loop:refactor: Extract subfunction do_stat_and_mknod() loop:refactor: extract subfunction set_loop_dev() loop: Add LOOP_CONFIGURE ioctl libbb/loop.c | 275 +++ 1 file changed, 170 insertions(+), 105 deletions(-) -- 2.27.0 ___ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox