[LTP] [PATCH v18 2/3] newlib_tests: Add tst_attach_loopdev test
Wei Gao
wegao@suse.com
Mon Nov 2 03:22:40 CET 2026
Add a unit test in lib/newlib_tests/ to verify the newly added
tst_attach_loopdev() function.
The test covers:
- Concurrent allocation of multiple loop devices without collisions.
- Parallel worker stress testing to exercise the exponential backoff
retry loop upon transient EBUSY conditions.
Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Wei Gao <wegao@suse.com>
---
v17->v18:
- New patch in v18.
lib/newlib_tests/.gitignore | 1 +
lib/newlib_tests/runtest.sh | 1 +
lib/newlib_tests/tst_attach_loopdev.c | 133 ++++++++++++++++++++++++++
3 files changed, 135 insertions(+)
create mode 100644 lib/newlib_tests/tst_attach_loopdev.c
diff --git a/lib/newlib_tests/.gitignore b/lib/newlib_tests/.gitignore
index 3a6e1643c..2d4b3d43f 100644
--- a/lib/newlib_tests/.gitignore
+++ b/lib/newlib_tests/.gitignore
@@ -11,6 +11,7 @@ test11
test13
test14
test15
+tst_attach_loopdev
tst_capability01
tst_capability02
tst_cgroup01
diff --git a/lib/newlib_tests/runtest.sh b/lib/newlib_tests/runtest.sh
index 71808ef8b..18b64c07a 100755
--- a/lib/newlib_tests/runtest.sh
+++ b/lib/newlib_tests/runtest.sh
@@ -16,6 +16,7 @@ test_zero_hugepage.sh
test0[579]
test1[59]
test2[04]
+tst_attach_loopdev
tst_bool_expr
tst_capability02
tst_checkpoint
diff --git a/lib/newlib_tests/tst_attach_loopdev.c b/lib/newlib_tests/tst_attach_loopdev.c
new file mode 100644
index 000000000..dbc711cb9
--- /dev/null
+++ b/lib/newlib_tests/tst_attach_loopdev.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 SUSE LLC <wegao@suse.com>
+ */
+
+/*\
+ * Unit test for tst_attach_loopdev().
+ *
+ * Verifies that:
+ * - Multiple backing files can be attached simultaneously to distinct
+ * loop devices without collision.
+ * - Concurrent workers attaching and detaching loop devices in parallel
+ * succeed without unhandled EBUSY race conditions.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "tst_test.h"
+
+#define BACKING_FILE1 "test_loop1.img"
+#define BACKING_FILE2 "test_loop2.img"
+
+#define DEV_SIZE_MB 1
+#define NUM_WORKERS 4
+#define WORKER_LOOPS 5
+
+static char dev1[PATH_MAX];
+static char dev2[PATH_MAX];
+
+static void cleanup(void)
+{
+ if (dev1[0])
+ tst_detach_device(dev1);
+
+ if (dev2[0])
+ tst_detach_device(dev2);
+}
+
+static void setup(void)
+{
+ if (tst_prealloc_file(BACKING_FILE1, 1024 * 1024, DEV_SIZE_MB))
+ tst_brk(TBROK, "Failed to create %s", BACKING_FILE1);
+
+ if (tst_prealloc_file(BACKING_FILE2, 1024 * 1024, DEV_SIZE_MB))
+ tst_brk(TBROK, "Failed to create %s", BACKING_FILE2);
+}
+
+static void test_multiple_devices(void)
+{
+ if (tst_attach_loopdev(dev1, sizeof(dev1), BACKING_FILE1)) {
+ tst_res(TFAIL, "Failed to attach %s to dev1", BACKING_FILE1);
+ return;
+ }
+
+ if (tst_attach_loopdev(dev2, sizeof(dev2), BACKING_FILE2)) {
+ tst_res(TFAIL, "Failed to attach %s to dev2", BACKING_FILE2);
+ goto detach1;
+ }
+
+ if (!strcmp(dev1, dev2))
+ tst_res(TFAIL, "dev1 and dev2 assigned identical device: '%s'", dev1);
+ else
+ tst_res(TPASS, "Assigned distinct loop devices: '%s' and '%s'", dev1, dev2);
+
+ if (tst_detach_device(dev2)) {
+ tst_res(TFAIL, "Failed to detach dev2 '%s'", dev2);
+ } else {
+ tst_res(TPASS, "Detached dev2 '%s' successfully", dev2);
+ dev2[0] = '\0';
+ }
+
+detach1:
+ if (tst_detach_device(dev1)) {
+ tst_res(TFAIL, "Failed to detach dev1 '%s'", dev1);
+ } else {
+ tst_res(TPASS, "Detached dev1 '%s' successfully", dev1);
+ dev1[0] = '\0';
+ }
+}
+
+static void test_concurrent_contention(void)
+{
+ pid_t pids[NUM_WORKERS];
+ int i;
+
+ for (i = 0; i < NUM_WORKERS; i++) {
+ pids[i] = SAFE_FORK();
+ if (!pids[i]) {
+ char file[32];
+ char dev[PATH_MAX];
+ int j;
+
+ snprintf(file, sizeof(file), "worker_%d.img", i);
+ if (tst_prealloc_file(file, 1024 * 1024, DEV_SIZE_MB))
+ tst_brk(TBROK, "Worker %d failed to prealloc %s", i, file);
+
+ for (j = 0; j < WORKER_LOOPS; j++) {
+ dev[0] = '\0';
+ if (tst_attach_loopdev(dev, sizeof(dev), file))
+ tst_brk(TBROK, "Worker %d loop %d failed attach", i, j);
+
+ if (tst_detach_device(dev))
+ tst_brk(TBROK, "Worker %d loop %d failed detach", i, j);
+ }
+
+ exit(0);
+ }
+ }
+
+ for (i = 0; i < NUM_WORKERS; i++)
+ SAFE_WAITPID(pids[i], NULL, 0);
+
+ tst_res(TPASS, "All %d workers attached and detached loop devices concurrently",
+ NUM_WORKERS);
+}
+
+static void run(void)
+{
+ test_multiple_devices();
+ test_concurrent_contention();
+}
+
+static struct tst_test test = {
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = run,
+};
--
2.55.0
More information about the ltp
mailing list