diff options
author | Elliott Hughes <enh@google.com> | 2019-08-05 16:33:16 -0700 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2019-08-09 20:33:14 -0500 |
commit | a626662bf5abf198ef5c4dfe9c783416169242fd (patch) | |
tree | ab47a7220279a62f95d75efbe0ef8eef89597969 /toys | |
parent | 77df4f81bb44f4f92f0dd08d87186d35d10bfaee (diff) | |
download | toybox-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.c | 13 |
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); |