From 95ba33f7a4ed199bc749264359a973a394ea09c4 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Wed, 20 Jun 2007 15:17:45 +0200 Subject: [PATCH] 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 Signed-off-by: Karel Zak --- mount/lomount.c | 12 ++++++++++-- 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; -- 2.39.5