]> err.no Git - util-linux/commitdiff
mount: loop device race condition
authorMatthias Koenig <mkoenig@suse.de>
Wed, 20 Jun 2007 13:17:45 +0000 (15:17 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 27 Jun 2007 12:55:00 +0000 (14:55 +0200)
Fix race in mount -o loop

Retry acquiring a loop device if the setup failed with EBUSY.

Signed-Off-By: Matthias Koenig <mkoenig@suse.de>
Signed-off-by: Karel Zak <kzak@redhat.com>
mount/lomount.c
mount/mount.c

index 4774a8539f594b319f17540397e5560336b8fd32..a5def98041facf906ee0ae1c3ccdf1d3b0d6ec8f 100644 (file)
@@ -341,8 +341,16 @@ set_loop(const char *device, const char *file, unsigned long long offset,
        }
 
        if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
-               perror("ioctl: LOOP_SET_FD");
-               return 1;
+               close(fd);
+               close(ffd);
+               if (errno == EBUSY) {
+                       if (verbose)
+                               printf(_("ioctl LOOP_SET_FD failed: %s\n"), strerror(errno));
+                       return 2;
+               } else {
+                       perror("ioctl: LOOP_SET_FD");
+                       return 1;
+               }
        }
        close (ffd);
 
index bc30a76eb065cecd3ffb3b1b96bfe250f8d7c85d..786842f3ec97888f877bd3b50fc1e8308673337f 100644 (file)
@@ -846,20 +846,45 @@ loop_check(const char **spec, const char **type, int *flags,
        printf(_("mount: skipping the setup of a loop device\n"));
     } else {
       int loopro = (*flags & MS_RDONLY);
+      int res;
 
-      if (!*loopdev || !**loopdev)
-       *loopdev = find_unused_loop_device();
-      if (!*loopdev)
-       return EX_SYSERR;       /* no more loop devices */
-      if (verbose)
-       printf(_("mount: going to use the loop device %s\n"), *loopdev);
       offset = opt_offset ? strtoull(opt_offset, NULL, 0) : 0;
-      if (set_loop(*loopdev, *loopfile, offset,
-                  opt_encryption, pfd, &loopro)) {
+
+      do {
+        if (!*loopdev || !**loopdev)
+         *loopdev = find_unused_loop_device();
+       if (!*loopdev)
+         return EX_SYSERR;     /* no more loop devices */
        if (verbose)
-         printf(_("mount: failed setting up loop device\n"));
-       return EX_FAIL;
-      }
+         printf(_("mount: going to use the loop device %s\n"), *loopdev);
+
+       if ((res = set_loop(*loopdev, *loopfile, offset,
+                           opt_encryption, pfd, &loopro))) {
+         if (res == 2) {
+            /* loop dev has been grabbed by some other process,
+               try again, if not given explicitly */
+            if (!opt_loopdev) {
+              if (verbose)
+                printf(_("mount: stolen loop=%s ...trying again\n"), *loopdev);
+              my_free(*loopdev);
+              *loopdev = NULL;
+              continue;
+            }
+            error(_("mount: stolen loop=%s"), *loopdev);
+            return EX_FAIL;
+
+         } else {
+            if (verbose)
+              printf(_("mount: failed setting up loop device\n"));
+            if (!opt_loopdev) {
+              my_free(*loopdev);
+              *loopdev = NULL;
+            }
+            return EX_FAIL;
+         }
+       }
+      } while (!*loopdev);
+
       if (verbose > 1)
        printf(_("mount: setup loop device successfully\n"));
       *spec = *loopdev;