Re: [PATCH 9/9] loop: Add LOOP_CONFIGURE ioctl

2022-11-17 Thread Lauri Kasanen
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()

2022-11-17 Thread Xiaoming Ni
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()

2022-11-17 Thread Xiaoming Ni
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

2022-11-17 Thread Xiaoming Ni
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

2022-11-17 Thread Xiaoming Ni
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()

2022-11-17 Thread Xiaoming Ni
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()

2022-11-17 Thread Xiaoming Ni
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()

2022-11-17 Thread Xiaoming Ni
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()

2022-11-17 Thread Xiaoming Ni
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

2022-11-17 Thread Xiaoming Ni
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

2022-11-17 Thread Xiaoming Ni
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