[LTP] [PATCH v3] syscalls/set_thread_area01: Refactor into new API

Ricardo B. Marlière rbm@suse.com
Thu Apr 3 18:40:46 CEST 2025


On Thu Apr 3, 2025 at 12:59 PM -03, Ricardo B. Marlière wrote:
> From: Ricardo B. Marlière <rbm@suse.com>
>
> Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
> ---
> Changes in v3:
> - Moved syscall wrappers to include/lapi/ldt.h
> - Split the test into a new set_thread_area02.c file
> - Used guarded buffers
> - Used .supported_archs instead of #ifdef __i386__
> - Used .test_variants and .tcnt+.test in set_thread_area02.c
> - Tweaked test decriptions
> - Link to v2: https://lore.kernel.org/r/20250403-conversions-set_thread_area-v2-1-a177e5c2b28d@suse.com
>
> Changes in v2:
> - Used tst_test.test_all instead of .test
> - Removed VALUE_AND_STRING macro
> - Added local wrappers to the syscalls
> - Fixed the test description
> - Added a comment quote from the set_thread_area manual to add context
> - Link to v1: https://lore.kernel.org/all/20250327-conversions-modify_ldt-v2-6-2907d4d3f6c0@suse.com
> ---
>  include/lapi/ldt.h                                 |  11 ++
>  .../kernel/syscalls/set_thread_area/.gitignore     |   3 +-
>  .../syscalls/set_thread_area/set_thread_area.h     |  31 -----
>  .../syscalls/set_thread_area/set_thread_area01.c   | 140 +++++++--------------
>  .../syscalls/set_thread_area/set_thread_area02.c   |  62 +++++++++
>  5 files changed, 120 insertions(+), 127 deletions(-)
>
> diff --git a/include/lapi/ldt.h b/include/lapi/ldt.h
> index 068a577cf113ba47a45d29920c6adb6851f4fc52..f9e70dd3de53ab5ad4fb9cff6552f39b49c7a3ac 100644
> --- a/include/lapi/ldt.h
> +++ b/include/lapi/ldt.h
> @@ -33,4 +33,15 @@ static inline int safe_modify_ldt(const char *file, const int lineno, int func,
>  #define SAFE_MODIFY_LDT(func, ptr, bytecount) \
>  	safe_modify_ldt(__FILE__, __LINE__, (func), (ptr), (bytecount))
>  
> +static inline int set_thread_area(const struct user_desc *entry)
> +{
> +	return tst_syscall(__NR_set_thread_area, entry);
> +}
> +
> +static inline int get_thread_area(const struct user_desc *entry)
> +{
> +	return tst_syscall(__NR_get_thread_area, entry);
> +}
> +
> +
>  #endif /* LAPI_LDT_H__ */
> diff --git a/testcases/kernel/syscalls/set_thread_area/.gitignore b/testcases/kernel/syscalls/set_thread_area/.gitignore
> index 547eb86e3c4ee86e2343067867c3bb027e0ee85a..b80ce741812c33fd9af47ecba8561ef385212e97 100644
> --- a/testcases/kernel/syscalls/set_thread_area/.gitignore
> +++ b/testcases/kernel/syscalls/set_thread_area/.gitignore
> @@ -1 +1,2 @@
> -/set_thread_area01
> +set_thread_area01
> +set_thread_area02
> diff --git a/testcases/kernel/syscalls/set_thread_area/set_thread_area.h b/testcases/kernel/syscalls/set_thread_area/set_thread_area.h
> deleted file mode 100644
> index 2bd2469d549ecf8c5c589a0a9485f886d043f7ed..0000000000000000000000000000000000000000
> --- a/testcases/kernel/syscalls/set_thread_area/set_thread_area.h
> +++ /dev/null
> @@ -1,31 +0,0 @@
> -#include <stdio.h>
> -#include <errno.h>
> -
> -/* Harness Specific Include Files. */
> -#include "test.h"
> -#include "lapi/syscalls.h"
> -#include "config.h"
> -
> -#if defined HAVE_ASM_LDT_H
> -#include <linux/unistd.h>
> -#include <asm/ldt.h>
> -
> -#if defined HAVE_STRUCT_USER_DESC
> -typedef struct user_desc thread_area_s;
> -#elif defined HAVE_STRUCT_MODIFY_LDT_LDT_S
> -typedef struct modify_ldt_ldt_s thread_area_s;
> -#else
> -typedef struct user_desc {
> -	unsigned int entry_number;
> -	unsigned long int base_addr;
> -	unsigned int limit;
> -	unsigned int seg_32bit:1;
> -	unsigned int contents:2;
> -	unsigned int read_exec_only:1;
> -	unsigned int limit_in_pages:1;
> -	unsigned int seg_not_present:1;
> -	unsigned int useable:1;
> -	unsigned int empty:25;
> -} thread_area_s;
> -#endif /* HAVE_STRUCT_USER_DESC */
> -#endif /* HAVE_ASM_LDT_H */
> diff --git a/testcases/kernel/syscalls/set_thread_area/set_thread_area01.c b/testcases/kernel/syscalls/set_thread_area/set_thread_area01.c
> index 30626d5e90ebf8e20624c370cc4474cb51a6b102..4e190db9afb93a56a32593d2908ef3a389ccf830 100644
> --- a/testcases/kernel/syscalls/set_thread_area/set_thread_area01.c
> +++ b/testcases/kernel/syscalls/set_thread_area/set_thread_area01.c
> @@ -1,111 +1,61 @@
> -/*************************************************************************
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
>   * Copyright (c) Crackerjack Project., 2007
>   * Copyright (c) Manas Kumar Nayak <maknayak@in.ibm.com>
>   * Copyright (c) Cyril Hrubis <chrubis@suse.cz> 2011
> + * Copyright (c) 2025 SUSE LLC Ricardo B. Marlière <rbm@suse.com>
> + */
> +
> +/*\
> + * Basic test of i386 thread-local storage for set_thread_area and
> + * get_thread_area syscalls. It verifies a simple write and read of an entry
> + * works.
>   *
> - * This program is free software;  you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY;  without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> - * the GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program;  if not, write to the Free Software
> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + * [Algorithm]
>   *
> - ************************************************************************/
> + * - Call set_thread_area to a struct user_desc pointer with entry_number = -1,
> + *   which will be set to a free entry_number upon exiting.
> + * - Call get_thread_area to read the new entry.
> + * - Use the new entry_number in another pointer and call get_thread_area.
> + * - Make sure they have the same data.
> + */
>  
> -#include "set_thread_area.h"
> +#include "tst_test.h"
>  
> -char *TCID = "set_thread_area_01";
> -int TST_TOTAL = 6;
> +#include "lapi/ldt.h"
>  
> -#if defined(HAVE_ASM_LDT_H) && defined(HAVE_STRUCT_USER_DESC)
> +static struct user_desc *entry1;
> +static struct user_desc *entry2;
>  
> -static void cleanup(void)
> +void run(void)
>  {
> +	TST_EXP_PASS_SILENT(set_thread_area(entry1));
> +	TST_EXP_PASS_SILENT(get_thread_area(entry1));

Perhaps I should also add the SAFE_ macros and make use of them here?

> +
> +	entry2->entry_number = entry1->entry_number;
> +	TST_EXP_PASS_SILENT(get_thread_area(entry2));
> +
> +	TST_EXP_PASS(memcmp(entry1, entry2, sizeof(struct user_desc)));
>  }
>  
> -static void setup(void)
> +void setup(void)
>  {
> -	TEST_PAUSE;
> +	/* When set_thread_area() is passed an entry_number of -1, it  searches
> +	 * for a free TLS entry. If set_thread_area() finds a free TLS entry,
> +	 * the value of u_info->entry_number is set upon return to show which
> +	 * entry was changed.
> +	 */
> +	entry1->entry_number = -1;
>  }
>  
> -struct test {
> -	int syscall;
> -	const char *const syscall_name;
> -	thread_area_s *u_info;
> -	int exp_ret;
> -	int exp_errno;
> -};
> -
> -/*
> - * The set_thread_area uses a free entry_number if entry number is set to -1
> - * and upon the syscall exit the entry number is set to entry which was used.
> - * So when we call get_thread_area on u_info1, the entry number is initalized
> - * corectly by the previous set_thread_area.
> - */
> -static struct user_desc u_info1 = {.entry_number = -1 };
> -static struct user_desc u_info2 = {.entry_number = -2 };
> -
> -#define VALUE_AND_STRING(val) val, #val
> -
> -static struct test tests[] = {
> -	{VALUE_AND_STRING(__NR_set_thread_area), &u_info1, 0, 0},
> -	{VALUE_AND_STRING(__NR_get_thread_area), &u_info1, 0, 0},
> -	{VALUE_AND_STRING(__NR_set_thread_area), &u_info2, -1, EINVAL},
> -	{VALUE_AND_STRING(__NR_get_thread_area), &u_info2, -1, EINVAL},
> -	{VALUE_AND_STRING(__NR_set_thread_area), (void *)-9, -1, EFAULT},
> -	{VALUE_AND_STRING(__NR_get_thread_area), (void *)-9, -1, EFAULT},
> +static struct tst_test test = {
> +	.setup = setup,
> +	.test_all = run,
> +	.supported_archs = (const char *const[]){ "x86", NULL },
> +	.bufs =
> +		(struct tst_buffers[]){
> +			{ &entry1, .size = sizeof(struct user_desc) },
> +			{ &entry2, .size = sizeof(struct user_desc) },
> +			{},
> +		},
>  };
> -
> -int main(int argc, char *argv[])
> -{
> -	int lc;
> -	unsigned i;
> -
> -	tst_parse_opts(argc, argv, NULL, NULL);
> -
> -	setup();
> -
> -	for (lc = 0; TEST_LOOPING(lc); lc++) {
> -		for (i = 0; i < sizeof(tests) / sizeof(struct test); i++) {
> -			TEST(tst_syscall(tests[i].syscall, tests[i].u_info));
> -
> -			if (TEST_RETURN != tests[i].exp_ret) {
> -				tst_resm(TFAIL, "%s returned %li expected %i",
> -					 tests[i].syscall_name,
> -					 TEST_RETURN, tests[i].exp_ret);
> -				continue;
> -			}
> -
> -			if (TEST_ERRNO != tests[i].exp_errno) {
> -				tst_resm(TFAIL,
> -					 "%s failed with %i (%s) expected %i (%s)",
> -					 tests[i].syscall_name, TEST_ERRNO,
> -					 strerror(TEST_ERRNO),
> -					 tests[i].exp_errno,
> -					 strerror(tests[i].exp_errno));
> -				continue;
> -			}
> -
> -			tst_resm(TPASS, "%s returned %li errno %i (%s)",
> -				 tests[i].syscall_name, TEST_RETURN,
> -				 TEST_ERRNO, strerror(TEST_ERRNO));
> -		}
> -	}
> -
> -	cleanup();
> -	tst_exit();
> -}
> -#else
> -int main(void)
> -{
> -	tst_brkm(TCONF, NULL,
> -		 "set_thread_area isn't available for this architecture");
> -}
> -#endif
> diff --git a/testcases/kernel/syscalls/set_thread_area/set_thread_area02.c b/testcases/kernel/syscalls/set_thread_area/set_thread_area02.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..e5ace82353bacc40bd462a5be2a598d456d31e3d
> --- /dev/null
> +++ b/testcases/kernel/syscalls/set_thread_area/set_thread_area02.c
> @@ -0,0 +1,62 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) Crackerjack Project., 2007
> + * Copyright (c) Manas Kumar Nayak <maknayak@in.ibm.com>
> + * Copyright (c) Cyril Hrubis <chrubis@suse.cz> 2011
> + * Copyright (c) 2025 SUSE LLC Ricardo B. Marlière <rbm@suse.com>
> + */
> +
> +/*\
> + * Tests set_thread_area and get_thread_area syscalls for their expected errors.
> + */
> +
> +#include "tst_test.h"
> +
> +#include "lapi/ldt.h"
> +
> +static struct user_desc *entry;
> +
> +static struct tvariant {
> +	const char *desc;
> +} tvariants[] = {
> +	{ TST_TO_STR(SET_THREAD_AREA) },
> +	{ TST_TO_STR(GET_THREAD_AREA) },
> +};
> +
> +static struct tcase {
> +	struct user_desc *entry;
> +	int exp_errno;
> +} tcases[] = {
> +	{ NULL, EINVAL },
> +	{ (void *)-9, EFAULT },
> +};
> +void run(unsigned int i)
> +{
> +	struct tcase tc = tcases[i];
> +
> +	if (tst_variant)
> +		TST_EXP_FAIL(get_thread_area(tc.entry), tc.exp_errno);
> +	else
> +		TST_EXP_FAIL(set_thread_area(tc.entry), tc.exp_errno);
> +}
> +
> +void setup(void)
> +{
> +	/* This makes *entry invalid */
> +	entry->entry_number = -2;
> +	tcases[0].entry = entry;
> +	tst_res(TINFO, "Testing %s", tvariants[tst_variant].desc);
> +}
> +
> +static struct tst_test test = {
> +	.setup = setup,
> +	.tcnt = ARRAY_SIZE(tcases),
> +	.test = run,
> +	.test_variants = ARRAY_SIZE(tvariants),
> +	.supported_archs = (const char *const[]){ "x86", NULL },
> +	.bufs =
> +		(struct tst_buffers[]){
> +			{ &entry, .size = sizeof(struct user_desc) },
> +			{},
> +		},
> +};
>
> ---
> base-commit: 898cc14ad412fb521867b43fed5c4e067b76f809
> change-id: 20250403-conversions-set_thread_area-07a90e0cd449
> prerequisite-message-id: <20250402-conversions-modify_ldt-v6-0-2e4b0e27870e@suse.com>
> prerequisite-patch-id: 490a3e6bc4004db5234224b6fd6d4bf5030b219d
> prerequisite-patch-id: 962bb815444eb2de9756dd2659e097567b6d6fe8
> prerequisite-patch-id: a8357fb870a8d7278e206b4fc65f1d9450fee802
>
> Best regards,



More information about the ltp mailing list