diff mbox series

ht_affinity.c: fix ht_affinity test failure

Message ID 20240920083036.87291-1-haifeng.xu@shopee.com
State Superseded
Headers show
Series ht_affinity.c: fix ht_affinity test failure | expand

Commit Message

Haifeng Xu Sept. 20, 2024, 8:30 a.m. UTC
Running ht_affinity test fails:

	smt_smp_affinity    0  TINFO  :  Set affinity through system call
	smt_smp_affinity    0  TINFO  :  Set test process affinity.
	mask: 1
	smt_smp_affinity    0  TINFO  :  ...Error

	...

	smt_smp_affinity    0  TINFO  :  Set test process affinity.
	mask: c0000000
	smt_smp_affinity    0  TINFO  :  ...Error
	smt_smp_affinity    3  TFAIL  :  ht_affinity.c:240: System call setaffinity() is error.

The type of cpumask pointer used in set_affinity() is unsigned long, but
ht_affinity used a unsigned int pointer. When kernel copy cpumask from
user-space pointer, the high 32bit of cpumask is a random value. So the
process can't be bind to the cpu specified by users.

After converting the cpumask from unsigned int to unsigned long, ht_affinity
test succeeds:

	smt_smp_affinity    0  TINFO  :  Set affinity through system call
	smt_smp_affinity    0  TINFO  :  Set test process affinity.
	mask: 1
	smt_smp_affinity    0  TINFO  :  ...OK

	...

	smt_smp_affinity    0  TINFO  :  Set test process affinity.
	mask: c0000000
	smt_smp_affinity    0  TINFO  :  ...OK
	smt_smp_affinity    3  TPASS  :  System call setaffinity() is OK.

Signed-off-by: Haifeng Xu <haifeng.xu@shopee.com>
---
 .../kernel/sched/hyperthreading/ht_affinity/ht_affinity.c   | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

Comments

Cyril Hrubis Sept. 20, 2024, 8:58 a.m. UTC | #1
Hi!
> The type of cpumask pointer used in set_affinity() is unsigned long, but
> ht_affinity used a unsigned int pointer. When kernel copy cpumask from
> user-space pointer, the high 32bit of cpumask is a random value. So the
> process can't be bind to the cpu specified by users.

Good catch, however it would be better if we used sizeof on the mask
instead of sizeof(unsigned long) in the sched_setaffinity() as well:

diff --git a/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c b/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c
index f6e9f2745..3c2fe1bf1 100644
--- a/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c
+++ b/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c
@@ -67,7 +67,7 @@ int HT_SetAffinity(void)
                tst_resm(TINFO, "Set test process affinity.");
                printf("mask: %x\n", mask);

-               sched_setaffinity(pid, sizeof(unsigned long), &mask);
+               sched_setaffinity(pid, sizeof(mask), &mask);

                for (j = 0; j < 10; j++) {
                        for (k = 0; k < 10; k++) {
@@ -95,7 +95,7 @@ int HT_SetAffinity(void)
                tst_resm(TINFO, "Set test process affinity.");
                printf("mask: %x\n", mask);

-               sched_setaffinity(pid, sizeof(unsigned long), &mask);
+               sched_setaffinity(pid, sizeof(mask), &mask);

                for (j = 0; j < 10; j++) {
                        for (k = 0; k < 10; k++) {



Most of the code does that already which makes it impossible to pass
different size than the actual size.
Haifeng Xu Sept. 20, 2024, 10:52 a.m. UTC | #2
On 2024/9/20 16:58, Cyril Hrubis wrote:
> Hi!
>> The type of cpumask pointer used in set_affinity() is unsigned long, but
>> ht_affinity used a unsigned int pointer. When kernel copy cpumask from
>> user-space pointer, the high 32bit of cpumask is a random value. So the
>> process can't be bind to the cpu specified by users.
> 
> Good catch, however it would be better if we used sizeof on the mask
> instead of sizeof(unsigned long) in the sched_setaffinity() as well:
> 
> diff --git a/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c b/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c
> index f6e9f2745..3c2fe1bf1 100644
> --- a/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c
> +++ b/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c
> @@ -67,7 +67,7 @@ int HT_SetAffinity(void)
>                 tst_resm(TINFO, "Set test process affinity.");
>                 printf("mask: %x\n", mask);
> 
> -               sched_setaffinity(pid, sizeof(unsigned long), &mask);
> +               sched_setaffinity(pid, sizeof(mask), &mask);
> 
>                 for (j = 0; j < 10; j++) {
>                         for (k = 0; k < 10; k++) {
> @@ -95,7 +95,7 @@ int HT_SetAffinity(void)
>                 tst_resm(TINFO, "Set test process affinity.");
>                 printf("mask: %x\n", mask);
> 
> -               sched_setaffinity(pid, sizeof(unsigned long), &mask);
> +               sched_setaffinity(pid, sizeof(mask), &mask);
> 
>                 for (j = 0; j < 10; j++) {
>                         for (k = 0; k < 10; k++) {
> 
> 
> 
> Most of the code does that already which makes it impossible to pass
> different size than the actual size.
> 

From the kernel source code, the user_mask_ptr is unsigned long.

SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len,
		unsigned long __user *, user_mask_ptr)

so maybe we can keep the type of user_mask_ptr consistent with it.
Cyril Hrubis Sept. 20, 2024, 12:22 p.m. UTC | #3
Hi!
> From the kernel source code, the user_mask_ptr is unsigned long.
> 
> SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len,
> 		unsigned long __user *, user_mask_ptr)
> 
> so maybe we can keep the type of user_mask_ptr consistent with it.

It's actually accessed as an array. See get_user_cpu_mask() function just
above this syscall definition and userspace is suppose to pass an array
big enough for all the flags of CPUs it cares about.

There are also macros in the libc sched.h header that allows you to
allocate an array big enough for the current machine and manipulate the
bits, see man CPU_ALLOC.
Haifeng Xu Sept. 21, 2024, 4:17 a.m. UTC | #4
On 2024/9/20 20:22, Cyril Hrubis wrote:
> Hi!
>> From the kernel source code, the user_mask_ptr is unsigned long.
>>
>> SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len,
>> 		unsigned long __user *, user_mask_ptr)
>>
>> so maybe we can keep the type of user_mask_ptr consistent with it.
> 
> It's actually accessed as an array. See get_user_cpu_mask() function just
> above this syscall definition and userspace is suppose to pass an array
> big enough for all the flags of CPUs it cares about.
> 
> There are also macros in the libc sched.h header that allows you to
> allocate an array big enough for the current machine and manipulate the
> bits, see man CPU_ALLOC.
> 
OK. I'll post next version with your suggestions. 
Thanks!
diff mbox series

Patch

diff --git a/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c b/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c
index f6e9f2745..e6829c2d2 100644
--- a/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c
+++ b/testcases/kernel/sched/hyperthreading/ht_affinity/ht_affinity.c
@@ -48,7 +48,7 @@  len - length in bytes of the bitmask pointed to by user_mask_ptr.
 
 int HT_SetAffinity(void)
 {
-	unsigned int mask;
+	unsigned long mask;
 	pid_t pid;
 	int result = 1;
 	int cpu_count, i, j, k, cpuid;
@@ -65,7 +65,7 @@  int HT_SetAffinity(void)
 
 	for (i = 0, mask = 0x1; i < cpu_count; i++, mask = mask << 1) {
 		tst_resm(TINFO, "Set test process affinity.");
-		printf("mask: %x\n", mask);
+		printf("mask: %lx\n", mask);
 
 		sched_setaffinity(pid, sizeof(unsigned long), &mask);
 
@@ -93,7 +93,7 @@  int HT_SetAffinity(void)
 
 	for (i = 0, mask = 0x3; i < cpu_count - 1; i++, mask = mask << 1) {
 		tst_resm(TINFO, "Set test process affinity.");
-		printf("mask: %x\n", mask);
+		printf("mask: %lx\n", mask);
 
 		sched_setaffinity(pid, sizeof(unsigned long), &mask);