mount,losetup: use /dev/loop-control is it exists
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 9 Jun 2019 21:20:49 +0000 (23:20 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 9 Jun 2019 21:20:49 +0000 (23:20 +0200)
function                                             old     new   delta
get_free_loop                                          -      58     +58
set_loop                                             597     649     +52
losetup_main                                         482     476      -6
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/1 up/down: 110/-6)            Total: 104 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
include/libbb.h
libbb/loop.c
util-linux/losetup.c

index 100d6b606314bdf199b4a6b7a4d49d4e6b7d0415..021100db1a2061cd2de2f400e2f17b57fef80109 100644 (file)
@@ -1461,14 +1461,15 @@ extern void bb_warn_ignoring_args(char *arg) FAST_FUNC;
 
 extern int get_linux_version_code(void) FAST_FUNC;
 
-extern char *query_loop(const char *device) FAST_FUNC;
-extern int del_loop(const char *device) FAST_FUNC;
+char *query_loop(const char *device) FAST_FUNC;
+int get_free_loop(void) FAST_FUNC;
+int del_loop(const char *device) FAST_FUNC;
 /*
  * If *devname is not NULL, use that name, otherwise try to find free one,
  * malloc and return it in *devname.
  * return value is the opened fd to the loop device, or < on error
  */
-extern 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 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
index c78535a206d026c5beedb5add0e0dd4e14399cbd..ada0c7638f3b673b0d15cd1c6a4b2c23534b05b3 100644 (file)
@@ -78,6 +78,24 @@ int FAST_FUNC del_loop(const char *device)
        return rc;
 }
 
+/* Obtain an unused loop device number */
+int FAST_FUNC get_free_loop(void)
+{
+       int fd;
+       int loopdevno;
+
+       fd = open("/dev/loop-control", O_RDWR | O_CLOEXEC);
+       if (fd == -1)
+               return fd - 1; /* -2: "no /dev/loop-control" */
+
+#ifndef LOOP_CTL_GET_FREE
+# define LOOP_CTL_GET_FREE 0x4C82
+#endif
+       loopdevno = ioctl(fd, LOOP_CTL_GET_FREE);
+       close(fd);
+       return loopdevno; /* can be -1 if error */
+}
+
 /* 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.  This
@@ -106,12 +124,24 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
                return -errno;
        }
 
-//TODO: use LOOP_CTL_GET_FREE instead of trying every loopN in sequence? a-la:
-// fd = open("/dev/loop-control", O_RDWR);
-// loopN = ioctl(fd, LOOP_CTL_GET_FREE);
-//
+       try = *device;
+       if (!try) {
+               i = get_free_loop();
+               if (i == -2) { /* no /dev/loop-control */
+                       i = 0;
+                       try = dev;
+                       goto old_style;
+               }
+               if (i == -1) {
+                       close(ffd);
+                       return -1; /* no free loop devices */
+               }
+               try = *device = xasprintf(LOOP_FORMAT, i);
+               goto try_to_open;
+       }
+
+ old_style:
        /* Find a loop device.  */
-       try = *device ? *device : dev;
        /* 1048575 (0xfffff) is a max possible minor number in Linux circa 2010 */
        for (i = 0; rc && i < 1048576; i++) {
                sprintf(dev, LOOP_FORMAT, i);
@@ -170,7 +200,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
                                        rc = ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo);
                                }
                                if (rc != 0) {
-                                       ioctl(dfd, LOOP_CLR_FD, 0);
+                                       ioctl(dfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary
                                }
                        }
                } else {
index b52d693ec4c838e2ebbbbf899fc66015f340e694..5dc7570748077421c94dc494da92219269e8fafa 100644 (file)
@@ -114,8 +114,14 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
        /* contains -f */
        if (opt & OPT_f) {
                char *s;
-               int n = 0;
+               int n;
 
+               n = get_free_loop();
+               if (n == -1)
+                       bb_error_msg_and_die("no free loop devices");
+               if (n < 0) /* n == -2: no /dev/loop-control, use legacy method */
+                       n = 0;
+               /* or: n >= 0: the number of next free loopdev, just verify it */
                do {
                        if (n > MAX_LOOP_NUM)
                                bb_error_msg_and_die("no free loop devices");