* [LTP] [PATCH v4] syscalls/set_thread_area01: Refactor into new API
@ 2025-04-04 16:26 Ricardo B. Marlière via ltp
2025-04-07 12:16 ` Andrea Cervesato via ltp
0 siblings, 1 reply; 3+ messages in thread
From: Ricardo B. Marlière via ltp @ 2025-04-04 16:26 UTC (permalink / raw)
To: Linux Test Project; +Cc: Ricardo B. Marlière
From: Ricardo B. Marlière <rbm@suse.com>
Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
Hello,
This patch is available at:
https://github.com/rbmarliere/ltp/tree/conversions/set_thread_area
It's a single patch, on top of this prerequisite:
https://lore.kernel.org/ltp/20250402-conversions-modify_ldt-v6-0-2e4b0e27870e@suse.com/T/#t
Thanks,
- Ricardo.
---
Changes in v4:
- Added set_thread_area02 to runtest/syscalls
- Added missing static modifiers
- Fixed formatting issue in .bufs
- Removed struct tvariant in set_thread_area02
- Renamed entry -> u_info to follow manpage standard
- Added expected errnos to set_thread_area02 description
- Link to v3: https://lore.kernel.org/r/20250403-conversions-set_thread_area-v3-1-df977366be32@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 | 10 ++
runtest/syscalls | 1 +
.../kernel/syscalls/set_thread_area/.gitignore | 3 +-
.../syscalls/set_thread_area/set_thread_area.h | 31 -----
.../syscalls/set_thread_area/set_thread_area01.c | 137 +++++++--------------
.../syscalls/set_thread_area/set_thread_area02.c | 57 +++++++++
6 files changed, 113 insertions(+), 126 deletions(-)
diff --git a/include/lapi/ldt.h b/include/lapi/ldt.h
index 068a577cf113ba47a45d29920c6adb6851f4fc52..7c619c5c9ed8731e124499346c88333b0b1267b3 100644
--- a/include/lapi/ldt.h
+++ b/include/lapi/ldt.h
@@ -33,4 +33,14 @@ 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 *u_info)
+{
+ return tst_syscall(__NR_set_thread_area, u_info);
+}
+
+static inline int get_thread_area(const struct user_desc *u_info)
+{
+ return tst_syscall(__NR_get_thread_area, u_info);
+}
+
#endif /* LAPI_LDT_H__ */
diff --git a/runtest/syscalls b/runtest/syscalls
index 05b3e0d376fae3adf1eb29c22c0b83fa49eee56f..234b14f8bd66db1283b046c103682e937bff0052 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1340,6 +1340,7 @@ set_mempolicy04 set_mempolicy04
set_robust_list01 set_robust_list01
set_thread_area01 set_thread_area01
+set_thread_area02 set_thread_area02
set_tid_address01 set_tid_address01
setdomainname01 setdomainname01
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..3892d42a53a8ad2065c4da337e89d5265a529ee5 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,60 @@
-/*************************************************************************
+// 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 *u_info1;
+static struct user_desc *u_info2;
-static void cleanup(void)
+static void run(void)
{
+ TST_EXP_PASS_SILENT(set_thread_area(u_info1));
+ TST_EXP_PASS_SILENT(get_thread_area(u_info1));
+
+ u_info2->entry_number = u_info1->entry_number;
+ TST_EXP_PASS_SILENT(get_thread_area(u_info2));
+
+ TST_EXP_PASS(memcmp(u_info1, u_info2, sizeof(struct user_desc)));
}
static 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.
+ */
+ u_info1->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[]) {
+ { &u_info1, .size = sizeof(struct user_desc) },
+ { &u_info2, .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..f1997974e62a9db6c4a984f2dbe2725dc1bf17df
--- /dev/null
+++ b/testcases/kernel/syscalls/set_thread_area/set_thread_area02.c
@@ -0,0 +1,57 @@
+// 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:
+ *
+ * - EINVAL u_info->entry_number is out of bounds.
+ * - EFAULT u_info is an invalid pointer.
+ */
+
+#include "tst_test.h"
+
+#include "lapi/ldt.h"
+
+static struct user_desc *u_info;
+
+static struct tcase {
+ struct user_desc *u_info;
+ int exp_errno;
+} tcases[] = {
+ { NULL, EINVAL },
+ { (void *)-9, EFAULT },
+};
+
+static void run(unsigned int i)
+{
+ struct tcase tc = tcases[i];
+
+ if (tst_variant)
+ TST_EXP_FAIL(get_thread_area(tc.u_info), tc.exp_errno);
+ else
+ TST_EXP_FAIL(set_thread_area(tc.u_info), tc.exp_errno);
+}
+
+static void setup(void)
+{
+ /* This makes *entry invalid */
+ u_info->entry_number = -2;
+ tcases[0].u_info = u_info;
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .tcnt = ARRAY_SIZE(tcases),
+ .test = run,
+ .test_variants = 2,
+ .supported_archs = (const char *const[]){ "x86", NULL },
+ .bufs = (struct tst_buffers[]) {
+ { &u_info, .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,
--
Ricardo B. Marlière <rbm@suse.com>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [LTP] [PATCH v4] syscalls/set_thread_area01: Refactor into new API
2025-04-04 16:26 [LTP] [PATCH v4] syscalls/set_thread_area01: Refactor into new API Ricardo B. Marlière via ltp
@ 2025-04-07 12:16 ` Andrea Cervesato via ltp
2025-04-07 12:42 ` Ricardo B. Marli��re via ltp
0 siblings, 1 reply; 3+ messages in thread
From: Andrea Cervesato via ltp @ 2025-04-07 12:16 UTC (permalink / raw)
To: Ricardo B. Marlière, Linux Test Project
Hi!
The patches look good.weI still have the issue with lapi/ldt.h import,
probably due to missing CONFIG_MODIFY_LDT_SYSCALL in some distros:
https://github.com/acerv/ltp/actions/runs/14308513692/job/40097717910
We will need the lapi/ldt.h fallback in
898cc14ad412fb521867b43fed5c4e067b76f809.
Besides this issue that you already know:
Reviewed-by: Andrea Cervesato <andrea.cervesato@suse.com>
On 4/4/25 18:26, Ricardo B. Marlière via ltp wrote:
> From: Ricardo B. Marlière <rbm@suse.com>
>
> Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
> ---
> Hello,
>
> This patch is available at:
>
> https://github.com/rbmarliere/ltp/tree/conversions/set_thread_area
>
> It's a single patch, on top of this prerequisite:
>
> https://lore.kernel.org/ltp/20250402-conversions-modify_ldt-v6-0-2e4b0e27870e@suse.com/T/#t
>
> Thanks,
> - Ricardo.
> ---
> Changes in v4:
> - Added set_thread_area02 to runtest/syscalls
> - Added missing static modifiers
> - Fixed formatting issue in .bufs
> - Removed struct tvariant in set_thread_area02
> - Renamed entry -> u_info to follow manpage standard
> - Added expected errnos to set_thread_area02 description
> - Link to v3: https://lore.kernel.org/r/20250403-conversions-set_thread_area-v3-1-df977366be32@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 | 10 ++
> runtest/syscalls | 1 +
> .../kernel/syscalls/set_thread_area/.gitignore | 3 +-
> .../syscalls/set_thread_area/set_thread_area.h | 31 -----
> .../syscalls/set_thread_area/set_thread_area01.c | 137 +++++++--------------
> .../syscalls/set_thread_area/set_thread_area02.c | 57 +++++++++
> 6 files changed, 113 insertions(+), 126 deletions(-)
>
> diff --git a/include/lapi/ldt.h b/include/lapi/ldt.h
> index 068a577cf113ba47a45d29920c6adb6851f4fc52..7c619c5c9ed8731e124499346c88333b0b1267b3 100644
> --- a/include/lapi/ldt.h
> +++ b/include/lapi/ldt.h
> @@ -33,4 +33,14 @@ 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 *u_info)
> +{
> + return tst_syscall(__NR_set_thread_area, u_info);
> +}
> +
> +static inline int get_thread_area(const struct user_desc *u_info)
> +{
> + return tst_syscall(__NR_get_thread_area, u_info);
> +}
> +
> #endif /* LAPI_LDT_H__ */
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 05b3e0d376fae3adf1eb29c22c0b83fa49eee56f..234b14f8bd66db1283b046c103682e937bff0052 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -1340,6 +1340,7 @@ set_mempolicy04 set_mempolicy04
>
> set_robust_list01 set_robust_list01
> set_thread_area01 set_thread_area01
> +set_thread_area02 set_thread_area02
> set_tid_address01 set_tid_address01
>
> setdomainname01 setdomainname01
> 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..3892d42a53a8ad2065c4da337e89d5265a529ee5 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,60 @@
> -/*************************************************************************
> +// 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 *u_info1;
> +static struct user_desc *u_info2;
>
> -static void cleanup(void)
> +static void run(void)
> {
> + TST_EXP_PASS_SILENT(set_thread_area(u_info1));
> + TST_EXP_PASS_SILENT(get_thread_area(u_info1));
> +
> + u_info2->entry_number = u_info1->entry_number;
> + TST_EXP_PASS_SILENT(get_thread_area(u_info2));
> +
> + TST_EXP_PASS(memcmp(u_info1, u_info2, sizeof(struct user_desc)));
> }
>
> static 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.
> + */
> + u_info1->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[]) {
> + { &u_info1, .size = sizeof(struct user_desc) },
> + { &u_info2, .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..f1997974e62a9db6c4a984f2dbe2725dc1bf17df
> --- /dev/null
> +++ b/testcases/kernel/syscalls/set_thread_area/set_thread_area02.c
> @@ -0,0 +1,57 @@
> +// 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:
> + *
> + * - EINVAL u_info->entry_number is out of bounds.
> + * - EFAULT u_info is an invalid pointer.
> + */
> +
> +#include "tst_test.h"
> +
> +#include "lapi/ldt.h"
> +
> +static struct user_desc *u_info;
> +
> +static struct tcase {
> + struct user_desc *u_info;
> + int exp_errno;
> +} tcases[] = {
> + { NULL, EINVAL },
> + { (void *)-9, EFAULT },
> +};
> +
> +static void run(unsigned int i)
> +{
> + struct tcase tc = tcases[i];
> +
> + if (tst_variant)
> + TST_EXP_FAIL(get_thread_area(tc.u_info), tc.exp_errno);
> + else
> + TST_EXP_FAIL(set_thread_area(tc.u_info), tc.exp_errno);
> +}
> +
> +static void setup(void)
> +{
> + /* This makes *entry invalid */
> + u_info->entry_number = -2;
> + tcases[0].u_info = u_info;
> +}
> +
> +static struct tst_test test = {
> + .setup = setup,
> + .tcnt = ARRAY_SIZE(tcases),
> + .test = run,
> + .test_variants = 2,
> + .supported_archs = (const char *const[]){ "x86", NULL },
> + .bufs = (struct tst_buffers[]) {
> + { &u_info, .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,
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [LTP] [PATCH v4] syscalls/set_thread_area01: Refactor into new API
2025-04-07 12:16 ` Andrea Cervesato via ltp
@ 2025-04-07 12:42 ` Ricardo B. Marli��re via ltp
0 siblings, 0 replies; 3+ messages in thread
From: Ricardo B. Marli��re via ltp @ 2025-04-07 12:42 UTC (permalink / raw)
To: Andrea Cervesato, Linux Test Project
On Mon Apr 7, 2025 at 9:16 AM -03, Andrea Cervesato wrote:
> Hi!
>
> The patches look good.weI still have the issue with lapi/ldt.h import,
> probably due to missing CONFIG_MODIFY_LDT_SYSCALL in some distros:
> https://github.com/acerv/ltp/actions/runs/14308513692/job/40097717910
> We will need the lapi/ldt.h fallback in
> 898cc14ad412fb521867b43fed5c4e067b76f809.
>
Yes! Sent in v7: (I will check against the CI from now on)
https://lore.kernel.org/all/20250407-conversions-modify_ldt-v7-0-cbeb379360a5@suse.com
> Besides this issue that you already know:
>
> Reviewed-by: Andrea Cervesato <andrea.cervesato@suse.com>
Thanks for reviewing,
- Ricardo.
>
> On 4/4/25 18:26, Ricardo B. Marlière via ltp wrote:
>> From: Ricardo B. Marlière <rbm@suse.com>
>>
>> Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
>> ---
>> Hello,
>>
>> This patch is available at:
>>
>> https://github.com/rbmarliere/ltp/tree/conversions/set_thread_area
>>
>> It's a single patch, on top of this prerequisite:
>>
>> https://lore.kernel.org/ltp/20250402-conversions-modify_ldt-v6-0-2e4b0e27870e@suse.com/T/#t
>>
>> Thanks,
>> - Ricardo.
>> ---
>> Changes in v4:
>> - Added set_thread_area02 to runtest/syscalls
>> - Added missing static modifiers
>> - Fixed formatting issue in .bufs
>> - Removed struct tvariant in set_thread_area02
>> - Renamed entry -> u_info to follow manpage standard
>> - Added expected errnos to set_thread_area02 description
>> - Link to v3: https://lore.kernel.org/r/20250403-conversions-set_thread_area-v3-1-df977366be32@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 | 10 ++
>> runtest/syscalls | 1 +
>> .../kernel/syscalls/set_thread_area/.gitignore | 3 +-
>> .../syscalls/set_thread_area/set_thread_area.h | 31 -----
>> .../syscalls/set_thread_area/set_thread_area01.c | 137 +++++++--------------
>> .../syscalls/set_thread_area/set_thread_area02.c | 57 +++++++++
>> 6 files changed, 113 insertions(+), 126 deletions(-)
>>
>> diff --git a/include/lapi/ldt.h b/include/lapi/ldt.h
>> index 068a577cf113ba47a45d29920c6adb6851f4fc52..7c619c5c9ed8731e124499346c88333b0b1267b3 100644
>> --- a/include/lapi/ldt.h
>> +++ b/include/lapi/ldt.h
>> @@ -33,4 +33,14 @@ 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 *u_info)
>> +{
>> + return tst_syscall(__NR_set_thread_area, u_info);
>> +}
>> +
>> +static inline int get_thread_area(const struct user_desc *u_info)
>> +{
>> + return tst_syscall(__NR_get_thread_area, u_info);
>> +}
>> +
>> #endif /* LAPI_LDT_H__ */
>> diff --git a/runtest/syscalls b/runtest/syscalls
>> index 05b3e0d376fae3adf1eb29c22c0b83fa49eee56f..234b14f8bd66db1283b046c103682e937bff0052 100644
>> --- a/runtest/syscalls
>> +++ b/runtest/syscalls
>> @@ -1340,6 +1340,7 @@ set_mempolicy04 set_mempolicy04
>>
>> set_robust_list01 set_robust_list01
>> set_thread_area01 set_thread_area01
>> +set_thread_area02 set_thread_area02
>> set_tid_address01 set_tid_address01
>>
>> setdomainname01 setdomainname01
>> 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..3892d42a53a8ad2065c4da337e89d5265a529ee5 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,60 @@
>> -/*************************************************************************
>> +// 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 *u_info1;
>> +static struct user_desc *u_info2;
>>
>> -static void cleanup(void)
>> +static void run(void)
>> {
>> + TST_EXP_PASS_SILENT(set_thread_area(u_info1));
>> + TST_EXP_PASS_SILENT(get_thread_area(u_info1));
>> +
>> + u_info2->entry_number = u_info1->entry_number;
>> + TST_EXP_PASS_SILENT(get_thread_area(u_info2));
>> +
>> + TST_EXP_PASS(memcmp(u_info1, u_info2, sizeof(struct user_desc)));
>> }
>>
>> static 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.
>> + */
>> + u_info1->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[]) {
>> + { &u_info1, .size = sizeof(struct user_desc) },
>> + { &u_info2, .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..f1997974e62a9db6c4a984f2dbe2725dc1bf17df
>> --- /dev/null
>> +++ b/testcases/kernel/syscalls/set_thread_area/set_thread_area02.c
>> @@ -0,0 +1,57 @@
>> +// 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:
>> + *
>> + * - EINVAL u_info->entry_number is out of bounds.
>> + * - EFAULT u_info is an invalid pointer.
>> + */
>> +
>> +#include "tst_test.h"
>> +
>> +#include "lapi/ldt.h"
>> +
>> +static struct user_desc *u_info;
>> +
>> +static struct tcase {
>> + struct user_desc *u_info;
>> + int exp_errno;
>> +} tcases[] = {
>> + { NULL, EINVAL },
>> + { (void *)-9, EFAULT },
>> +};
>> +
>> +static void run(unsigned int i)
>> +{
>> + struct tcase tc = tcases[i];
>> +
>> + if (tst_variant)
>> + TST_EXP_FAIL(get_thread_area(tc.u_info), tc.exp_errno);
>> + else
>> + TST_EXP_FAIL(set_thread_area(tc.u_info), tc.exp_errno);
>> +}
>> +
>> +static void setup(void)
>> +{
>> + /* This makes *entry invalid */
>> + u_info->entry_number = -2;
>> + tcases[0].u_info = u_info;
>> +}
>> +
>> +static struct tst_test test = {
>> + .setup = setup,
>> + .tcnt = ARRAY_SIZE(tcases),
>> + .test = run,
>> + .test_variants = 2,
>> + .supported_archs = (const char *const[]){ "x86", NULL },
>> + .bufs = (struct tst_buffers[]) {
>> + { &u_info, .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,
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-04-07 12:42 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-04 16:26 [LTP] [PATCH v4] syscalls/set_thread_area01: Refactor into new API Ricardo B. Marlière via ltp
2025-04-07 12:16 ` Andrea Cervesato via ltp
2025-04-07 12:42 ` Ricardo B. Marli��re via ltp
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox