@@ -122,10 +122,12 @@ clone06 clone06
clone07 clone07
clone08 clone08
clone09 clone09
+clone10 clone10
clone301 clone301
clone302 clone302
clone303 clone303
+clone304 clone304
close01 close01
close02 close02
@@ -7,3 +7,4 @@
/clone07
/clone08
/clone09
+/clone10
new file mode 100644
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Red Hat Inc. All Rights Reserved.
+ * Author: Chunfu Wen <chwen@redhat.com>
+ */
+
+/*\
+ * Add tls parameter and flag:CLONE_SETTLS cover for clone
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sched.h>
+#include <sys/wait.h>
+
+#if defined(__i386__)
+#include <asm/ldt.h>
+#endif
+
+#include "tst_test.h"
+#include "clone_platform.h"
+#include "lapi/syscalls.h"
+
+#define TLS_EXP 100
+#define TLS_SIZE 4096
+#define TLS_ALIGN 16
+
+static __thread int tls_var = 0;
+
+static void *tls_ptr;
+static struct user_desc *tls_desc;
+static char *child_stack;
+static volatile int child_done = 0;
+
+static int flags = CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SETTLS;
+
+static void *allocate_tls_area(void)
+{
+ void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
+ if (!tls_area)
+ tst_brk(TBROK | TERRNO, "aligned_alloc failed");
+ memset(tls_area, 0, TLS_SIZE);
+
+ return tls_area;
+}
+
+static void init_tls(void)
+{
+#if defined(__x86_64__) || defined(__aarch64__) || defined(__s390x__)
+ tls_ptr = allocate_tls_area();
+
+#elif defined(__i386__)
+ tls_ptr = allocate_tls_area();
+ tls_desc = SAFE_MALLOC(sizeof(*tls_desc));
+ memset(tls_desc, 0, sizeof(*tls_desc));
+ tls_desc->entry_number = -1;
+ tls_desc->base_addr = (unsigned long)tls_ptr;
+ tls_desc->limit = TLS_SIZE;
+ tls_desc->seg_32bit = 1;
+ tls_desc->contents = 0;
+ tls_desc->read_exec_only = 0;
+ tls_desc->limit_in_pages = 0;
+ tls_desc->seg_not_present = 0;
+ tls_desc->useable = 1;
+
+#else
+ tst_brk(TCONF, "Unsupported architecture for TLS");
+#endif
+}
+
+static void free_tls(void)
+{
+#if defined(__x86_64__) || defined(__aarch64__) || defined(__s390x__)
+ if (tls_ptr) {
+ free(tls_ptr);
+ }
+#elif defined(__i386__)
+ if (tls_desc) {
+ free((void *)(uintptr_t)tls_desc->base_addr);
+ free(tls_desc);
+ }
+#endif
+}
+
+static int touch_tls_in_child(void *arg LTP_ATTRIBUTE_UNUSED)
+{
+ tls_var = TLS_EXP + 1;
+ tst_res(TINFO, "Child (PID: %d, TID: %d): TLS value set to: %d", getpid(), gettid(), tls_var);
+
+ child_done = 1;
+ return 0;
+}
+
+static void verify_tls(void)
+{
+ tls_var = TLS_EXP;
+
+ TEST(ltp_clone7(flags, touch_tls_in_child, NULL, CHILD_STACK_SIZE, child_stack, NULL, tls_ptr, NULL));
+
+ if (TST_RET == -1)
+ tst_brk(TBROK | TTERRNO, "clone() failed");
+
+ while (!child_done)
+ sched_yield();
+
+ if (TLS_EXP == tls_var) {
+ tst_res(TPASS,
+ "Parent (PID: %d, TID: %d): TLS value correct: %d",
+ getpid(), gettid(), tls_var);
+ } else {
+ tst_res(TFAIL,
+ "Parent (PID: %d, TID: %d): TLS value mismatch: got %d, expected %d",
+ getpid(), gettid(), tls_var, TLS_EXP);
+ }
+ exit(0);
+ tst_reap_children();
+}
+
+static void setup(void)
+{
+ child_stack = SAFE_MALLOC(CHILD_STACK_SIZE);
+ init_tls();
+}
+
+static void cleanup(void)
+{
+ free(child_stack);
+ free_tls();
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = verify_tls,
+};
@@ -1,3 +1,4 @@
clone301
clone302
clone303
+clone304
new file mode 100644
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Red Hat Inc. All Rights Reserved.
+ * Author: Chunfu Wen <chwen@redhat.com>
+ */
+
+/*\
+ * Add tls parameter and flag:CLONE_SETTLS cover for clone3
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <sys/wait.h>
+
+#if defined(__i386__)
+#include <asm/ldt.h>
+#endif
+
+#include "tst_test.h"
+#include "lapi/sched.h"
+#include "lapi/pidfd.h"
+
+#define TLS_EXP 100
+#define TLS_SIZE 4096
+#define TLS_ALIGN 16
+#define CHILD_STACK_SIZE (1024*1024)
+
+static int pidfd, child_tid, parent_tid;
+static struct clone_args *args;
+static void *tls_ptr;
+static struct user_desc *tls_desc;
+static void *child_stack;
+
+static volatile int child_done = 0;
+/* TLS variable to validate in child */
+static __thread int tls_var = 0;
+
+static int test_flags = CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SETTLS;
+
+static void *allocate_tls_region(void)
+{
+ void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
+ if (!tls_area) {
+ perror("aligned_alloc");
+ exit(EXIT_FAILURE);
+ }
+ memset(tls_area, 0, TLS_SIZE);
+ return tls_area;
+}
+
+static void initialize_tls(void)
+{
+#if defined(__x86_64__) || defined(__aarch64__) || defined(__s390x__)
+ tls_ptr = allocate_tls_region();
+
+#elif defined(__i386__)
+ /* x86 32-bit: TLS is a struct user_desc */
+ tls_ptr = allocate_tls_region();
+ tls_desc = SAFE_MALLOC(sizeof(*tls_desc));
+ memset(tls_desc, 0, sizeof(*tls_desc));
+ tls_desc->entry_number = -1;
+ tls_desc->base_addr = (unsigned long)tls_ptr;
+ tls_desc->limit = TLS_SIZE;
+ tls_desc->seg_32bit = 1;
+ tls_desc->contents = 0;
+ tls_desc->read_exec_only = 0;
+ tls_desc->limit_in_pages = 0;
+ tls_desc->seg_not_present = 0;
+ tls_desc->useable = 1;
+
+#else
+ tst_brk(TCONF, "This architecture does not support TLS");
+#endif
+}
+
+static void free_tls(void)
+{
+#if defined(__x86_64__) || defined(__aarch64__) || defined(__s390x__)
+ if (tls_ptr) {
+ free(tls_ptr);
+ }
+#elif defined(__i386__)
+ if (tls_desc) {
+ free((void *)(uintptr_t)tls_desc->base_addr);
+ free(tls_desc);
+ }
+#endif
+}
+
+static int check_tls_in_child(void)
+{
+ tls_var = TLS_EXP + 1;
+ tst_res(TINFO, "Child (PID: %d, TID: %d): TLS value set to: %d", getpid(), gettid(), tls_var);
+
+ child_done = 1;
+ tst_syscall(__NR_exit, 0);
+ return 0;
+}
+
+static void run(void)
+{
+ pid_t pid;
+ int status;
+ tls_var = TLS_EXP;
+
+ args->flags = test_flags;
+ args->pidfd = (uint64_t)(&pidfd);
+ args->child_tid = (uint64_t)(&child_tid);
+ args->parent_tid = (uint64_t)(&parent_tid);
+ args->stack = (uint64_t)(child_stack);
+ args->stack_size = CHILD_STACK_SIZE;
+ args->tls = (uint64_t)tls_ptr;
+
+ TEST(pid = clone3(args, sizeof(*args)));
+
+ if (TST_RET == -1)
+ tst_brk(TBROK | TTERRNO, "clone() failed");
+
+ if (!pid)
+ check_tls_in_child();
+
+ while (!child_done)
+ sched_yield();
+
+ if (TLS_EXP == tls_var) {
+ tst_res(TPASS,
+ "Parent (PID: %d, TID: %d): TLS value correct: %d",
+ getpid(), gettid(), tls_var);
+ } else {
+ tst_res(TFAIL,
+ "Parent (PID: %d, TID: %d): TLS value mismatch: got %d, expected %d",
+ getpid(), gettid(), tls_var, TLS_EXP);
+ }
+}
+
+static void setup(void)
+{
+ clone3_supported_by_kernel();
+ child_stack = SAFE_MALLOC(CHILD_STACK_SIZE);
+ initialize_tls();
+}
+
+static void cleanup(void)
+{
+ free(child_stack);
+ free_tls();
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = run,
+ .bufs = (struct tst_buffers []) {
+ {&args, .size = sizeof(*args)},
+ {},
+ }
+};
tls parameter and related flag:CLONE_SETTLS are missed in the testing, so add them into existed test case Signed-off-by: chunfuwen <chwen@redhat.com> --- Changes in v6: - update flag to effective combination - combine x86_64 with other arches - rename child function - remove inproper exit - remove unused code lines - remove sleep statement Changes in v5: - wrap duplicate code into one single methold - remove duplicately malloc Changes in v4: - remove riscv and loongarch definition Changes in v3: - fix missing head file for x86 Changes in v2: - create separate files for clone and clone3 --- runtest/syscalls | 2 + testcases/kernel/syscalls/clone/.gitignore | 1 + testcases/kernel/syscalls/clone/clone10.c | 137 +++++++++++++++++ testcases/kernel/syscalls/clone3/.gitignore | 1 + testcases/kernel/syscalls/clone3/clone304.c | 158 ++++++++++++++++++++ 5 files changed, 299 insertions(+) create mode 100644 testcases/kernel/syscalls/clone/clone10.c create mode 100644 testcases/kernel/syscalls/clone3/clone304.c