aboutsummaryrefslogtreecommitdiff
path: root/toys
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2019-08-05 16:33:16 -0700
committerRob Landley <rob@landley.net>2019-08-09 20:33:14 -0500
commita626662bf5abf198ef5c4dfe9c783416169242fd (patch)
treeab47a7220279a62f95d75efbe0ef8eef89597969 /toys
parent77df4f81bb44f4f92f0dd08d87186d35d10bfaee (diff)
downloadtoybox-a626662bf5abf198ef5c4dfe9c783416169242fd.tar.gz
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
Diffstat (limited to 'toys')
-rw-r--r--toys/other/losetup.c13
1 files 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);