There's a race between LOOP_CTL_GET_FREE and LOOP_SET_FD. Work around it
by just retrying if we get EBUSY on the LOOP_SET_FD call. This is what
similar code in ChromeOS already does.

Bug: http://b/135716654
---
 toys/other/losetup.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
From 148875a244f7c2f00f827097b9ee92d05f23341b Mon Sep 17 00:00:00 2001
From: Elliott Hughes <[email protected]>
Date: Mon, 5 Aug 2019 16:33:16 -0700
Subject: [PATCH] losetup: fix the race.

There's a race between LOOP_CTL_GET_FREE and LOOP_SET_FD. Work around it
by just retrying if we get EBUSY on the LOOP_SET_FD call. This is what
similar code in ChromeOS already does.

Bug: http://b/135716654
---
 toys/other/losetup.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/toys/other/losetup.c b/toys/other/losetup.c
index 8edc65ae..e73761a0 100644
--- a/toys/other/losetup.c
+++ b/toys/other/losetup.c
@@ -49,10 +49,11 @@ GLOBALS(
 // -f: *device is NULL
 
 // Perform requested operation on one device. Returns 1 if handled, 0 if error
-static void loopback_setup(char *device, char *file)
+static int loopback_setup(char *device, char *file)
 {
   struct loop_info64 *loop = (void *)(toybuf+32);
   int lfd = -1, ffd = ffd;
+  int racy = !device;
 
   // Open file (ffd) and loop device (lfd)
 
@@ -65,7 +66,7 @@ static void loopback_setup(char *device, char *file)
 
     // mount -o loop depends on found device being at the start of toybuf.
     if (cfd != -1) {
-      if (0 <= (i = ioctl(cfd, 0x4C82))) { // LOOP_CTL_GET_FREE
+      if (0 <= (i = ioctl(cfd, LOOP_CTL_GET_FREE))) {
         sprintf(device = toybuf, "%s/loop%d", TT.dir, i);
       }
       close(cfd);
@@ -105,7 +106,10 @@ static void loopback_setup(char *device, char *file)
     char *s = xabspath(file, 1);
 
     if (!s) perror_exit("file"); // already opened, but if deleted since...
-    if (ioctl(lfd, LOOP_SET_FD, ffd)) perror_exit("%s=%s", device, file);
+    if (ioctl(lfd, LOOP_SET_FD, ffd)) {
+      if (racy && errno == EBUSY) return 1;
+      perror_exit("%s=%s", device, file);
+    }
     loop->lo_offset = TT.o;
     loop->lo_sizelimit = TT.S;
     xstrncpy((char *)loop->lo_file_name, s, LO_NAME_SIZE);
@@ -127,6 +131,7 @@ static void loopback_setup(char *device, char *file)
 done:
   if (file) close(ffd);
   if (lfd != -1) close(lfd);
+  return 0;
 }
 
 // Perform an action on all currently existing loop devices
@@ -173,7 +178,7 @@ void losetup_main(void)
 
   if (FLAG(f)) {
     if (toys.optc > 1) perror_exit("max 1 arg");
-    loopback_setup(NULL, *toys.optargs);
+    while (loopback_setup(NULL, *toys.optargs));
   } else if (FLAG(a) || FLAG(j)) {
     if (toys.optc) error_exit("bad args");
     dirtree_read(TT.dir, dash_a);
-- 
2.22.0.770.g0f2c4a37fd-goog

_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to