[LTP] [PATCH v5] lib: Use backoff polling to wait for loop device nodes
Wake Liu
wakel@google.com
Fri Aug 7 12:04:38 CEST 2026
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.
Signed-off-by: Wake Liu <wakel@google.com>
---
v4 -> v5:
- Declare tst_multiply_timeout() in tst_common.h to fix old API build failures in CI.
v3 -> v4:
- Rebase onto the latest LTP HEAD.
- Remove self-referencing Link in commit message.
v2 -> v3:
- Reuse LTP native TST_RETRY_FN_EXP_BACKOFF() macro in tst_common.h to simplify code.
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.
include/tst_common.h | 2 ++
lib/tst_device.c | 13 +++++++++----
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/include/tst_common.h b/include/tst_common.h
index e1f7c7907..d09edbbbe 100644
--- a/include/tst_common.h
+++ b/include/tst_common.h
@@ -26,6 +26,8 @@
#define LTP_ALIGN(x, a) __LTP_ALIGN_MASK(x, (typeof(x))(a) - 1)
#define __LTP_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+unsigned int tst_multiply_timeout(unsigned int timeout);
+
/**
* TST_RETRY_FUNC() - Repeatedly retry a function with an increasing delay.
* @FUNC - The function which will be retried
diff --git a/lib/tst_device.c b/lib/tst_device.c
index 744173ffe..00304711b 100644
--- a/lib/tst_device.c
+++ b/lib/tst_device.c
@@ -82,7 +82,7 @@ static int set_dev_path(char *dev, 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];
@@ -93,8 +93,13 @@ int tst_find_free_loopdev(char *path, size_t path_len)
rc = ioctl(ctl_fd, LOOP_CTL_GET_FREE);
close(ctl_fd);
if (rc >= 0) {
- if (path && set_dev_loop_path(rc, path, path_len))
- tst_brkm(TBROK, NULL, "Could not stat loop device %i", rc);
+ if (path) {
+ path_set = TST_RETRY_FN_EXP_BACKOFF(
+ set_dev_loop_path(rc, path, path_len),
+ TST_RETVAL_EQ0, 1);
+ if (path_set)
+ tst_brkm(TBROK, NULL, "Could not stat loop device %i", rc);
+ }
tst_resm(TINFO, "Found free device %d '%s'",
rc, path ?: "");
return rc;
@@ -161,7 +166,7 @@ int tst_attach_device(const char *dev, const char *file)
LO_NAME_SIZE);
}
- dev_fd = open(dev, O_RDWR);
+ dev_fd = TST_RETRY_FN_EXP_BACKOFF(open(dev, O_RDWR), TST_RETVAL_GE0, 1);
if (dev_fd < 0) {
tst_resm(TWARN | TERRNO, "open('%s', O_RDWR) failed", dev);
return 1;
--
2.55.0.654.g21b8a5bc05-goog
More information about the ltp
mailing list