aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <ben@decadent.org.uk>2019-11-05 19:52:19 +0000
committerBen Hutchings <ben@decadent.org.uk>2019-11-05 20:03:26 +0000
commit333ef3af1dcef61a6bc5dba531453e5e0cb27da1 (patch)
tree188611dec8de3023582f4af0d70dbe8f18c0b4e2
parent209676c9a3d057c0eba48f633eb541b17c7d1eba (diff)
downloadklibc-333ef3af1dcef61a6bc5dba531453e5e0cb27da1.tar.gz
[klibc] losetup: Use LOOP_CTL_GET_FREE to find free device
Since Linux 3.1, the loop driver creates a /dev/loop-control device node which supports ioctls to allocate and free devices. When the loop driver is modular, udev creates this in advance, and opening it causes the driver to be loaded. (The same is not true for /dev/loop*.) Using the LOOP_CTL_GET_FREE ioctl also allows creating more than the default number of loop devices, and is more efficient than checking a range of possible device names. Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--usr/utils/losetup.c59
1 files changed, 17 insertions, 42 deletions
diff --git a/usr/utils/losetup.c b/usr/utils/losetup.c
index 5d328138f994be..4a85e126ceeba9 100644
--- a/usr/utils/losetup.c
+++ b/usr/utils/losetup.c
@@ -95,51 +95,26 @@ is_loop_device (const char *device) {
char * find_unused_loop_device (void)
{
- /* Just creating a device, say in /tmp, is probably a bad idea -
- people might have problems with backup or so.
- So, we just try /dev/loop[0-7]. */
char dev[20];
- char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
- int i, j, fd, somedev = 0, someloop = 0, permission = 0;
- struct stat statbuf;
- struct loop_info loopinfo;
-
- for (j = 0; j < SIZE(loop_formats); j++) {
- for(i = 0; i < 256; i++) {
- sprintf(dev, loop_formats[j], i);
- if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
- somedev++;
- fd = open (dev, O_RDONLY);
- if (fd >= 0) {
- if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
- someloop++; /* in use */
- else if (errno == ENXIO) {
- close (fd);
- return xstrdup(dev);/* probably free */
- }
- close (fd);
- } else if (errno == EACCES)
- permission++;
-
- continue;/* continue trying as long as devices exist */
- }
- break;
- }
+ int fd, rc;
+
+ fd = open("/dev/loop-control", O_RDWR);
+ if (fd < 0) {
+ error("%s: could not open /dev/loop-control. Maybe this kernel "
+ "does not know\n"
+ " about the loop device? (If so, recompile or "
+ "`modprobe loop'.)", progname);
+ return NULL;
}
-
- if (!somedev)
- error("%s: could not find any device /dev/loop#", progname);
- else if (!someloop && permission)
- error("%s: no permission to look at /dev/loop#", progname);
- else if (!someloop)
- error(
- "%s: Could not find any loop device. Maybe this kernel "
- "does not know\n"
- " about the loop device? (If so, recompile or "
- "`modprobe loop'.)", progname);
- else
+ rc = ioctl(fd, LOOP_CTL_GET_FREE, 0);
+ close(fd);
+ if (rc < 0) {
error("%s: could not find any free loop device", progname);
- return 0;
+ return NULL;
+ }
+
+ sprintf(dev, "/dev/loop%d", rc);
+ return xstrdup(dev);
}
/*