diff options
author | Matthias Koenig <mkoenig@suse.de> | 2007-06-20 15:17:45 +0200 |
---|---|---|
committer | Karel Zak <kzak@redhat.com> | 2007-06-27 14:55:00 +0200 |
commit | 95ba33f7a4ed199bc749264359a973a394ea09c4 (patch) | |
tree | 46712a4396e39dcdfdbf5d60ba99a0f5944b13d3 | |
parent | 653872612c2249dd892f5f2f6cc9b1e3abd24b45 (diff) | |
download | util-linux-old-95ba33f7a4ed199bc749264359a973a394ea09c4.tar.gz |
mount: loop device race condition
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>
-rw-r--r-- | mount/lomount.c | 12 | ||||
-rw-r--r-- | mount/mount.c | 47 |
2 files changed, 46 insertions, 13 deletions
diff --git a/mount/lomount.c b/mount/lomount.c index 4774a853..a5def980 100644 --- a/mount/lomount.c +++ b/mount/lomount.c @@ -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); diff --git a/mount/mount.c b/mount/mount.c index bc30a76e..786842f3 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -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; |