[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