Skip to contentSkip to conversation

max_map_count fail in arm64 system which support lib32

LTP New Cui Bixuan 4 participants 15 messages Mar 7, 2016 – Dec 16, 2016

lore
Share & tools
lore

Cui Bixuan

author
#0 lore raw

Hi,
There is an error when run 32-bit 'max_map_count' in arm64 which support lib32:

./max_map_count_32

max_map_count    0  TINFO  :  set overcommit_memory to 2
max_map_count    0  TINFO  :  set max_map_count to 64
max_map_count    1  TFAIL  :  max_map_count.c:233: 64 map entries in total, but expected 64 entries
max_map_count    0  TINFO  :  set max_map_count to 256
max_map_count    2  TFAIL  :  max_map_count.c:233: 256 map entries in total, but expected 256 entries
max_map_count    0  TINFO  :  set max_map_count to 1024
max_map_count    3  TFAIL  :  max_map_count.c:233: 1024 map entries in total, but expected 1024 entries
max_map_count    0  TINFO  :  set max_map_count to 4096
max_map_count    4  TFAIL  :  max_map_count.c:233: 4096 map entries in total, but expected 4096 entries
max_map_count    0  TINFO  :  set max_map_count to 16384
max_map_count    5  TFAIL  :  max_map_count.c:233: 16384 map entries in total, but expected 16384 entries
max_map_count    0  TINFO  :  set max_map_count to 65536
max_map_count    6  TFAIL  :  max_map_count.c:233: 65536 map entries in total, but expected 65536 entries
max_map_count    0  TINFO  :  set overcommit_memory to 0
max_map_count    0  TINFO  :  set max_map_count to 65530
    When I use 32-bit SDK, it will compile at:

	#elif defined(__arm__)
        	/* Older arm kernels didn't label their vdso maps */
        	if (!strncmp(line, "ffff0000-ffff1000", 17))
                	return true;

    and not:
	#elif defined(__ia64__)
        	/* On ia64, the vdso is not a proper mapping */
        	if (!strcmp(buf, "[vdso]"))
                	return true;


    That will fail in arm64 because of the wrong check; And I have a look at x86 and x86_64, which

have the same check '[vsyscall]';
I think we should fix it but I don't have good idea( I don't know much about it :-( ).

Thanks,
Cui Bixuan

#1 lore raw

Hi!

Quoted 17 lines

./max_map_count_32

max_map_count    0  TINFO  :  set overcommit_memory to 2
max_map_count    0  TINFO  :  set max_map_count to 64
max_map_count    1  TFAIL  :  max_map_count.c:233: 64 map entries in total, but expected 64 entries
max_map_count    0  TINFO  :  set max_map_count to 256
max_map_count    2  TFAIL  :  max_map_count.c:233: 256 map entries in total, but expected 256 entries
max_map_count    0  TINFO  :  set max_map_count to 1024
max_map_count    3  TFAIL  :  max_map_count.c:233: 1024 map entries in total, but expected 1024 entries
max_map_count    0  TINFO  :  set max_map_count to 4096
max_map_count    4  TFAIL  :  max_map_count.c:233: 4096 map entries in total, but expected 4096 entries
max_map_count    0  TINFO  :  set max_map_count to 16384
max_map_count    5  TFAIL  :  max_map_count.c:233: 16384 map entries in total, but expected 16384 entries
max_map_count    0  TINFO  :  set max_map_count to 65536
max_map_count    6  TFAIL  :  max_map_count.c:233: 65536 map entries in total, but expected 65536 entries
max_map_count    0  TINFO  :  set overcommit_memory to 0
max_map_count    0  TINFO  :  set max_map_count to 65530
Quoted 6 lines
    When I use 32-bit SDK, it will compile at:

	#elif defined(__arm__)
        	/* Older arm kernels didn't label their vdso maps */
        	if (!strncmp(line, "ffff0000-ffff1000", 17))
                	return true;

So you compile 32bit binary and run it on 64bit arm kernel and it wrongly skips one mapping?

Quoted 5 lines
    and not:
	#elif defined(__ia64__)
        	/* On ia64, the vdso is not a proper mapping */
        	if (!strcmp(buf, "[vdso]"))
                	return true;

__ia64__ is itanium, I guess that the function always returns false when compiled for 64bit arm.

The solution may be runtime detection for 32bit/64bit kernel on arm. We can look at the machine string in the struct utsname returned from uname(2) to get that information.

Signature · 2 lines
Cyril Hrubis
[email protected]
author
#2 lore raw
Quoted 34 lines · Cyril Hrubis

Hi!

Quoted 17 lines

./max_map_count_32

max_map_count    0  TINFO  :  set overcommit_memory to 2
max_map_count    0  TINFO  :  set max_map_count to 64
max_map_count    1  TFAIL  :  max_map_count.c:233: 64 map entries in total, but expected 64 entries
max_map_count    0  TINFO  :  set max_map_count to 256
max_map_count    2  TFAIL  :  max_map_count.c:233: 256 map entries in total, but expected 256 entries
max_map_count    0  TINFO  :  set max_map_count to 1024
max_map_count    3  TFAIL  :  max_map_count.c:233: 1024 map entries in total, but expected 1024 entries
max_map_count    0  TINFO  :  set max_map_count to 4096
max_map_count    4  TFAIL  :  max_map_count.c:233: 4096 map entries in total, but expected 4096 entries
max_map_count    0  TINFO  :  set max_map_count to 16384
max_map_count    5  TFAIL  :  max_map_count.c:233: 16384 map entries in total, but expected 16384 entries
max_map_count    0  TINFO  :  set max_map_count to 65536
max_map_count    6  TFAIL  :  max_map_count.c:233: 65536 map entries in total, but expected 65536 entries
max_map_count    0  TINFO  :  set overcommit_memory to 0
max_map_count    0  TINFO  :  set max_map_count to 65530
Quoted 6 lines
    When I use 32-bit SDK, it will compile at:

	#elif defined(__arm__)
        	/* Older arm kernels didn't label their vdso maps */
        	if (!strncmp(line, "ffff0000-ffff1000", 17))
                	return true;

So you compile 32bit binary and run it on 64bit arm kernel and it wrongly skips one mapping?

Quoted 5 lines
    and not:
	#elif defined(__ia64__)
        	/* On ia64, the vdso is not a proper mapping */
        	if (!strcmp(buf, "[vdso]"))
                	return true;
Quoted 6 lines

__ia64__ is itanium, I guess that the function always returns false when compiled for 64bit arm.

The solution may be runtime detection for 32bit/64bit kernel on arm. We can look at the machine string in the struct utsname returned from uname(2) to get that information.

Hi,
I add a print:

#elif defined(__arm__)
if (!strncmp(line, "ffff0000-ffff1000", 17))

        {
                printf("%s\n", line);  // I add
                return true;
        }

and then run it(32bit SDK):

./max_map_count

max_map_count    0  TINFO  :  set overcommit_memory to 2
max_map_count    0  TINFO  :  set max_map_count to 64

ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
max_map_count 1 TFAIL : max_map_count.c:242: 64 map entries in total, but expected 64 entries

So we know why it failed:
It skip 'ffff0000-ffff1000' in arm64 kernel when we use 32bit SDK, but it doesn't skip when use 64bit SDK. Maybe the error is caused by the different sdk.

And I do this test for arm32 system:

arma9el:/tmp# ./max_map_count
max_map_count    0  TINFO  :  set overcommit_memory to 2
max_map_count    0  TINFO  :  set max_map_count to 64
ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]
max_map_count    1  TPASS  :  max_maps:64 map_count:65  map entries in total as expected.

It skip 'ffff0000-ffff1000' in arm32 but passed.

Look at max_map_count.c:
* Note: On some architectures there is a special vma VSYSCALL, which
* is allocated without incrementing mm->map_count variable. On these
* architectures each /proc/<pid>/maps has at the end:
...

So I think:
* arm 64bit kernel doesn't have 'special vma VSYSCALL' so no need to skip(32bit binary skip so fail);
* arm 32bit kernel have 'special vma VSYSCALL';

Is it right :-D?

Thanks
Cui Bixuan

Quoted 1 line
#3 lore raw

Hi!

Quoted 10 lines

I add a print:

#elif defined(__arm__)
if (!strncmp(line, "ffff0000-ffff1000", 17))

        {
                printf("%s\n", line);  // I add
                return true;
        }

and then run it(32bit SDK):

...

Quoted 3 lines

So I think:
* arm 64bit kernel doesn't have 'special vma VSYSCALL' so no need to skip(32bit binary skip so fail);
* arm 32bit kernel have 'special vma VSYSCALL';

That is what I think as well.

If you look at the code it does #if defined(__arm__) which is true if you compile for 32bit arm, on 64bit __aarch64__ is defined instead.

Which is why I said we should do runtime check using the machine from uname(2) on arm in order to skip the check in case that 32bit arm binary runs on 64bit kernel. It should contain something as armvX on 32bit arm and aarch64 on 64bit.

Signature · 2 lines
Cyril Hrubis
[email protected]
author
#4 lore raw

PATCH 1/1 max_map_count: fix error by using runtime check

There is a error when compile the case to 32bit binary and run it on 64bit arm kernel, which will wrongly skip one mapping.

Do runtimg check using the machine from uname(2) to fix it.

---
 testcases/kernel/mem/tunable/max_map_count.c | 32 +++++++++++++++++-----------
 1 file changed, 19 insertions(+), 13 deletions(-)
testcases/kernel/mem/tunable/max_map_count.c +19 -13
index 295a47b..a69e560 100644
@@ -59,6 +59,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/utsname.h>
 #include "test.h"
 #include "mem.h"
 
@@ -70,6 +71,7 @@ int TST_TOTAL = 1;
 
 static long old_max_map_count;
 static long old_overcommit;
+struct utsname un;
 
 static long count_maps(pid_t pid);
 static void max_map_count_test(void);
@@ -104,6 +106,9 @@ void setup(void)
 	old_max_map_count = get_sys_tune("max_map_count");
 	old_overcommit = get_sys_tune("overcommit_memory");
 	set_sys_tune("overcommit_memory", 2, 1);
+
+	if (uname(&un) != 0)
+		tst_brkm(TBROK | TERRNO, NULL, "uname error");
 }
 
 void cleanup(void)
@@ -124,19 +129,20 @@ static bool filter_map(const char *line)
 	if (ret != 1)
 		return false;
 
-#if defined(__x86_64__) || defined(__x86__)
-	/* On x86, there's an old compat vsyscall page */
-	if (!strcmp(buf, "[vsyscall]"))
-		return true;
-#elif defined(__ia64__)
-	/* On ia64, the vdso is not a proper mapping */
-	if (!strcmp(buf, "[vdso]"))
-		return true;
-#elif defined(__arm__)
-	/* Older arm kernels didn't label their vdso maps */
-	if (!strncmp(line, "ffff0000-ffff1000", 17))
-		return true;
-#endif
+	if (strstr(un.machine, "x86") != NULL)
+		/* On x86, there's an old compat vsyscall page */
+		if (!strcmp(buf, "[vsyscall]"))
+			return true;
+
+	if (strstr(un.machine, "ia64") != NULL)
+		/* On ia64, the vdso is not a proper mapping */
+		if (!strcmp(buf, "[vdso]"))
+			return true;
+
+	if (strstr(un.machine, "armv") != NULL)
+		/* Older arm kernels didn't label their vdso maps */
+		if (!strncmp(line, "ffff0000-ffff1000", 17))
+			return true;
 
 	return false;
 }
Signature · 1 line
1.8.3.4
#5 lore raw

PATCH 1/1 max_map_count: fix error by using runtime check

----- Original Message -----

Quoted 57 lines

From: "Cui Bixuan" <[email protected]>
To: "Cyril Hrubis" <[email protected]>
Cc: [email protected], [email protected], [email protected]
Sent: Wednesday, 23 March, 2016 9:53:59 AM
Subject: [LTP] [PATCH] max_map_count: fix error by using runtime check

There is a error when compile the case to 32bit binary and run it on 64bit arm kernel, which will wrongly skip one mapping.

Do runtimg check using the machine from uname(2) to fix it.

---
 testcases/kernel/mem/tunable/max_map_count.c | 32
 +++++++++++++++++-----------
 1 file changed, 19 insertions(+), 13 deletions(-)
testcases/kernel/mem/tunable/max_map_count.c +5 -4
index 295a47b..a69e560 100644
@@ -59,6 +59,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/utsname.h>
 #include "test.h"
 #include "mem.h"
 
@@ -70,6 +71,7 @@ int TST_TOTAL = 1;
 
 static long old_max_map_count;
 static long old_overcommit;
+struct utsname un;
 
 static long count_maps(pid_t pid);
 static void max_map_count_test(void);
@@ -104,6 +106,9 @@ void setup(void)
 	old_max_map_count = get_sys_tune("max_map_count");
 	old_overcommit = get_sys_tune("overcommit_memory");
 	set_sys_tune("overcommit_memory", 2, 1);
+
+	if (uname(&un) != 0)
+		tst_brkm(TBROK | TERRNO, NULL, "uname error");
 }
 
 void cleanup(void)
@@ -124,19 +129,20 @@ static bool filter_map(const char *line)
 	if (ret != 1)
 		return false;
 
-#if defined(__x86_64__) || defined(__x86__)
-	/* On x86, there's an old compat vsyscall page */
-	if (!strcmp(buf, "[vsyscall]"))
-		return true;

testcases/kernel/mem/tunable/max_map_count.c static bool filter_map(const char *line) · line 132

Quoted 10 lines
testcases/kernel/mem/tunable/max_map_count.c +1 -9
-#elif defined(__ia64__)
-	/* On ia64, the vdso is not a proper mapping */
-	if (!strcmp(buf, "[vdso]"))
-		return true;
-#elif defined(__arm__)
-	/* Older arm kernels didn't label their vdso maps */
-	if (!strncmp(line, "ffff0000-ffff1000", 17))
-		return true;
-#endif
+	if (strstr(un.machine, "x86") != NULL)

What if uname contains i386?

Can we relax the pass condition to allow map_count to be within some tolerance? Then we wouldn't have to worry so much about all arch specifics.

Quoted 22 lines
testcases/kernel/mem/tunable/max_map_count.c +13 -1
+		/* On x86, there's an old compat vsyscall page */
+		if (!strcmp(buf, "[vsyscall]"))
+			return true;
+
+	if (strstr(un.machine, "ia64") != NULL)
+		/* On ia64, the vdso is not a proper mapping */
+		if (!strcmp(buf, "[vdso]"))
+			return true;
+
+	if (strstr(un.machine, "armv") != NULL)
+		/* Older arm kernels didn't label their vdso maps */
+		if (!strncmp(line, "ffff0000-ffff1000", 17))
+			return true;
 
 	return false;
 }
--

1.8.3.4

--
Mailing list info: https://lists.linux.it/listinfo/ltp

#6 lore raw

PATCH 1/1 max_map_count: fix error by using runtime check

Quoted 6 lines · Jan Stancek
Quoted 6 lines
testcases/kernel/mem/tunable/max_map_count.c +0 -6
-	if (!strcmp(buf, "[vsyscall]"))
-		return true;
-#elif defined(__ia64__)
-	/* On ia64, the vdso is not a proper mapping */
-	if (!strcmp(buf, "[vdso]"))
-		return true;
Quoted 8 lines

testcases/kernel/mem/tunable/max_map_count.c static bool filter_map(const char *line) · line 132

Quoted 6 lines
testcases/kernel/mem/tunable/max_map_count.c +1 -5
-#elif defined(__arm__)
-	/* Older arm kernels didn't label their vdso maps */
-	if (!strncmp(line, "ffff0000-ffff1000", 17))
-		return true;
-#endif
+	if (strstr(un.machine, "x86") != NULL)

What if uname contains i386?

Yes, you are right, I have a mistake.

Quoted 4 lines

Can we relax the pass condition to allow map_count to be within some tolerance? Then we wouldn't have to worry so much about all arch specifics.

Does it influence the case if we relax the pass condition? I think we shuold think about it.

Thanks
Cui Bixuan

Quoted 12 lines
Quoted 11 lines

return false;
}
--
1.8.3.4

--
Mailing list info: https://lists.linux.it/listinfo/ltp

#7 lore raw

PATCH 1/1 max_map_count: fix error by using runtime check

In reply to Jan Stancek

Hi!

Quoted 3 lines

Can we relax the pass condition to allow map_count to be within some tolerance? Then we wouldn't have to worry so much about all arch specifics.

Looking at the code we skip exactly one mapping on some architectures. So it looks like allowing the number of mappings to be greater by one uncoditionally should solve the problem.

But I'm still undecided if we should go this way as we will weaken the test assertion since at the moment we skip exact mappings by their label.

Signature · 2 lines
Cyril Hrubis
[email protected]
author
#8 lore raw

PATCH 1/1 max_map_count: fix error by using runtime check

Quoted 5 lines · Cyril Hrubis

Hi!

Quoted 3 lines

Can we relax the pass condition to allow map_count to be within some tolerance? Then we wouldn't have to worry so much about all arch specifics.

Quoted 7 lines

Looking at the code we skip exactly one mapping on some architectures. So it looks like allowing the number of mappings to be greater by one uncoditionally should solve the problem.

But I'm still undecided if we should go this way as we will weaken the test assertion since at the moment we skip exact mappings by their label.

I have two ideas:
1. Use strcmp() to replace the strstr() and to check x86_64,x86,ia64,armv7b and so on.
2. Now we only find the problem in aarch64, we just fix it:

#elif defined(__arm__)

	/* Skip it when run it in aarch64 */
	if(strcmp(un.machine, "aarch64"))
		return false;

	/* Older arm kernels didn't label their vdso maps */
	if (!strncmp(line, "ffff0000-ffff1000", 17))
		return true;

And I think the second is better :-D

Thanks
Cui Bixuan

Quoted 1 line
#9 lore raw

PATCH 1/1 max_map_count: fix error by using runtime check

Hi!

Quoted 11 lines

2. Now we only find the problem in aarch64, we just fix it:

#elif defined(__arm__)

	/* Skip it when run it in aarch64 */
	if(strcmp(un.machine, "aarch64"))
		return false;

	/* Older arm kernels didn't label their vdso maps */
	if (!strncmp(line, "ffff0000-ffff1000", 17))
		return true;
Quoted 1 line

And I think the second is better :-D

Let's go with this one for now and if we find more special cases later we can relax the conditions as Jan suggested.

Signature · 2 lines
Cyril Hrubis
[email protected]
author
#10 lore raw

PATCH v2 1/1 max_map_count: fix error by using runtime check

There is a error when compile the case to 32bit binary and run it on 64bit arm kernel, which will wrongly skip one mapping.

Add runtimg check by using the machine from uname(2) to fix it.

---
 testcases/kernel/mem/tunable/max_map_count.c | 9 +++++++++
 1 file changed, 9 insertions(+)
testcases/kernel/mem/tunable/max_map_count.c +9 -0
index 295a47b..cc7a4e1 100644
@@ -59,6 +59,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/utsname.h>
 #include "test.h"
 #include "mem.h"
 
@@ -70,6 +71,7 @@ int TST_TOTAL = 1;
 
 static long old_max_map_count;
 static long old_overcommit;
+static struct utsname un;
 
 static long count_maps(pid_t pid);
 static void max_map_count_test(void);
@@ -104,6 +106,9 @@ void setup(void)
 	old_max_map_count = get_sys_tune("max_map_count");
 	old_overcommit = get_sys_tune("overcommit_memory");
 	set_sys_tune("overcommit_memory", 2, 1);
+
+	if (uname(&un) != 0)
+		tst_brkm(TBROK | TERRNO, NULL, "uname error");
 }
 
 void cleanup(void)
@@ -133,6 +138,10 @@ static bool filter_map(const char *line)
 	if (!strcmp(buf, "[vdso]"))
 		return true;
 #elif defined(__arm__)
+	/* Skip it when run it in aarch64 */
+	if (strcmp(un.machine, "aarch64"))
+		return false;
+
 	/* Older arm kernels didn't label their vdso maps */
 	if (!strncmp(line, "ffff0000-ffff1000", 17))
 		return true;
Signature · 1 line
1.8.3.4
#11 lore raw

PATCH v2 1/1 max_map_count: fix error by using runtime check

Hi!

Quoted 2 lines

There is a error when compile the case to 32bit binary and run it on 64bit arm kernel, which will wrongly skip one mapping.

Pushed with fixed typo in the patch description, thanks.

Signature · 2 lines
Cyril Hrubis
[email protected]
author
#12 lore raw
In reply to Cyril Hrubis
Quoted 20 lines · Cyril Hrubis

Hi!

Quoted 10 lines

I add a print:

#elif defined(__arm__)
if (!strncmp(line, "ffff0000-ffff1000", 17))

        {
                printf("%s\n", line);  // I add
                return true;
        }

and then run it(32bit SDK):

...

Quoted 3 lines

So I think:
* arm 64bit kernel doesn't have 'special vma VSYSCALL' so no need to skip(32bit binary skip so fail);
* arm 32bit kernel have 'special vma VSYSCALL';

That is what I think as well.

Quoted 7 lines

If you look at the code it does #if defined(__arm__) which is true if you compile for 32bit arm, on 64bit __aarch64__ is defined instead.

Which is why I said we should do runtime check using the machine from uname(2) on arm in order to skip the check in case that 32bit arm binary runs on 64bit kernel. It should contain something as armvX on 32bit arm and aarch64 on 64bit.

Hi,
I send a patch which uses string check(strstr function) instead of '#if defined' check.
And it contains arm, x86 and ia64.

Thanks,
Cui Bixuan

Quoted 1 line
author
#13 lore raw

PATCH 1/1 max_map_count: fix a mistake and support it for aarch64_be

In reply to Cui Bixuan

There is a mistake for if (strcmp()) for skipping in aarch64. And there is the same error in aarch64be, so add it.

---
 testcases/kernel/mem/tunable/max_map_count.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
testcases/kernel/mem/tunable/max_map_count.c +1 -1
index eb7486f..ca322da 100644
@@ -139,7 +139,7 @@ static bool filter_map(const char *line)
 		return true;
 #elif defined(__arm__)
 	/* Skip it when run it in aarch64 */
-	if (strcmp(un.machine, "aarch64"))
+	if ((!strcmp(un.machine, "aarch64")) || (!strcmp(un.machine, "aarch64_be")))
 		return false;
 
 	/* Older arm kernels didn't label their vdso maps */
Signature · 1 line
2.6.2
author
#14 lore raw

[LTP] we can ignore it and discuss the problem at 'Fix wrong checking of aarch64' from [email protected]

:-D

Quoted 22 lines · Cui Bixuan

There is a mistake for if (strcmp()) for skipping in aarch64. And there is the same error in aarch64be, so add it.

---
 testcases/kernel/mem/tunable/max_map_count.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
testcases/kernel/mem/tunable/max_map_count.c +1 -1
index eb7486f..ca322da 100644
@@ -139,7 +139,7 @@ static bool filter_map(const char *line)
 		return true;
 #elif defined(__arm__)
 	/* Skip it when run it in aarch64 */
-	if (strcmp(un.machine, "aarch64"))
+	if ((!strcmp(un.machine, "aarch64")) || (!strcmp(un.machine, "aarch64_be")))
 		return false;
 
 	/* Older arm kernels didn't label their vdso maps */