[PATCH v2] lib: Use backoff polling to wait for loop device nodes
Wake Liu via ltp <[email protected]> Tue, 4 Aug 2026 01:59:05 +0000
| Newsgroups | gmane.linux.ltp |
|---|---|
| Message-ID | <[email protected]> |
From: Wake Liu via ltp <[email protected]> On systems where loop device node creation is asynchronous (such as Android containers or systems with slow udev startup), calling stat() or open() immediately after LOOP_CTL_GET_FREE can transiently fail because the device file (e.g. /dev/loopX) has not been fully populated in time. Introduce an exponential-backoff retry loop in both tst_find_free_loopdev() and tst_attach_device() (starting at 1ms delay, doubling each try, capped at 100ms) to wait for the device node to be successfully populated. This improves the robustness of loop device allocations on asynchronous virtualized environments while minimizing unnecessary delays on responsive systems. Link: https://lore.kernel.org/ltp/20260803152754.3991113-1-wakel-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org/ Signed-off-by: Wake Liu <[email protected]> --- v1 -> v2: - Strictly clamp backoff delay to 100ms (prevent overflow exceeding cap). - Skip usleep on final loop iteration to avoid unnecessary idle delay. - Reduce max attempts to 30 (stat) and 15 (open) to bound worst-case timeout. lib/tst_device.c | 32 +++++++++++++++++++++++++++----- diff --git a/lib/tst_device.c b/lib/tst_device.c index 744173ffef..19e1a8a25c 100644 --- a/lib/tst_device.c +++ b/lib/tst_device.c @@ -82,7 +82,7 @@ static int set_dev_loop_path(int rc, char *path, size_t path_len) int tst_find_free_loopdev(char *path, size_t path_len) { - int ctl_fd, dev_fd, rc, i; + int ctl_fd, dev_fd, rc, i, path_set; struct loop_info loopinfo; char buf[PATH_MAX]; @@ -94,8 +94,18 @@ int tst_find_free_loopdev(char *path, size_t path_len) if (rc >= 0) { if (path) { - if (set_dev_loop_path(rc, path, path_len)) - tst_brkm(TBROK, NULL, "Could not stat loop device %i", rc); + unsigned int usec = 1000; /* start with 1ms */ + + for (i = 0; i < 30; i++) { + path_set = set_dev_loop_path(rc, path, path_len); + if (!path_set) + break; + if (i < 29) { + usleep(usec); + usec = usec * 2 < 100000 ? usec * 2 : 100000; + } + } + if (path_set) + tst_brkm(TBROK, NULL, "Could not stat loop device %i", rc); } tst_resm(TINFO, "Found free device %d '%s'", rc, path ?: ""); @@ -166,9 +176,8 @@ int tst_find_free_loopdev(char *path, size_t path_len) int tst_attach_device(const char *dev, const char *file) { - int dev_fd, file_fd; - struct loop_info loopinfo; - int attach_tries = 20; + int dev_fd, file_fd, i; + struct loop_info loopinfo; unsigned int usec = 1000; /* start with 1ms */ if (strlen(file) >= LO_NAME_SIZE) { @@ -175,13 +184,14 @@ int tst_attach_device(const char *dev, const char *file) LO_NAME_SIZE); } - while (attach_tries--) { + for (i = 0; i < 15; i++) { dev_fd = open(dev, O_RDWR); if (dev_fd >= 0) break; - usleep(usec); - if (usec < 100000) /* cap backoff at 100ms */ - usec *= 2; + if (i < 14) { + usleep(usec); + usec = usec * 2 < 100000 ? usec * 2 : 100000; + } } if (dev_fd < 0) { tst_resm(TWARN | TERRNO, "open('%s', O_RDWR) failed", dev); -- Mailing list info: https://lists.linux.it/listinfo/ltp