* [LTP] [PATCH v2] Migrating the libhugetlbfs/testcases/truncate_above_4GB.c test
@ 2023-09-29 8:39 Geetika
2023-11-30 9:03 ` Richard Palethorpe
0 siblings, 1 reply; 3+ messages in thread
From: Geetika @ 2023-09-29 8:39 UTC (permalink / raw)
To: ltp
Test Description:
A misconversion of hugetlb_vmtruncate_list to a prio_tree meant that
on 32-bit machines, truncates at or above 4GB could truncate lower pages,
resulting in BUG_ON()s. This kernel bug was fixed with
'commit 856fc2950555'.
The purpose of this test is to check whether huge pages are handled correctly
when a file is truncated above the 4GB boundary. It ensures that the memory is
not corrupted or lost during the truncation process, and that the expected data
is still present in the memory after truncation.
Signed-off-by: Geetika <geetika@linux.ibm.com>
---
v2:
-Corrected typo
---
runtest/hugetlb | 1 +
testcases/kernel/mem/.gitignore | 1 +
.../kernel/mem/hugetlb/hugemmap/hugemmap39.c | 171 ++++++++++++++++++
3 files changed, 173 insertions(+)
create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap39.c
diff --git a/runtest/hugetlb b/runtest/hugetlb
index 299c07ac9..26587ecc0 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -35,6 +35,7 @@ hugemmap29 hugemmap29
hugemmap30 hugemmap30
hugemmap31 hugemmap31
hugemmap32 hugemmap32
+hugemmap39 hugemmap39
hugemmap05_1 hugemmap05 -m
hugemmap05_2 hugemmap05 -s
hugemmap05_3 hugemmap05 -s -m
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index 7258489ed..4c55d5c8c 100644
--- a/testcases/kernel/mem/.gitignore
+++ b/testcases/kernel/mem/.gitignore
@@ -34,6 +34,7 @@
/hugetlb/hugemmap/hugemmap30
/hugetlb/hugemmap/hugemmap31
/hugetlb/hugemmap/hugemmap32
+/hugetlb/hugemmap/hugemmap39
/hugetlb/hugeshmat/hugeshmat01
/hugetlb/hugeshmat/hugeshmat02
/hugetlb/hugeshmat/hugeshmat03
diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap39.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap39.c
new file mode 100644
index 000000000..be5cba69f
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap39.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation.
+ * Copyright (C) 2006 Hugh Dickins <hugh@veritas.com>
+ */
+
+/*\
+ *[Descripiton]
+ *
+ * At one stage, a misconversion of hugetlb_vmtruncate_list to a
+ * prio_tree meant that on 32-bit machines, truncates at or above 4GB
+ * could truncate lower pages, resulting in BUG_ON()s.
+ *
+ * WARNING: The offsets and addresses used within are specifically
+ * calculated to trigger the bug as it existed. Don't mess with them
+ * unless you *really* know what you're doing.
+ *
+ */
+
+#define _GNU_SOURCE
+#define _LARGEFILE64_SOURCE
+#define FOURGIG ((off64_t)0x100000000ULL)
+#define MNTPOINT "hugetlbfs/"
+
+#include <signal.h>
+#include <setjmp.h>
+#include "hugetlb.h"
+
+static int page_size;
+static long hpage_size;
+static int fd = -1;
+static volatile int test_pass;
+static int err;
+static int sigbus_count;
+static sigjmp_buf sig_escape;
+
+static void sigbus_handler_fail(int signum, siginfo_t *si, void *uc)
+{
+ siglongjmp(sig_escape, 17);
+}
+
+static void sigbus_handler_pass(int signum, siginfo_t *si, void *uc)
+{
+ test_pass = 1;
+ siglongjmp(sig_escape, 17);
+}
+
+static void run_test(void)
+{
+ long long buggy_offset, truncate_point;
+ void *p, *q;
+ volatile unsigned int *pi, *qi;
+
+ struct sigaction sa_pass = {
+ .sa_sigaction = sigbus_handler_pass,
+ .sa_flags = SA_SIGINFO,
+ };
+
+ struct sigaction sa_fail = {
+ .sa_sigaction = sigbus_handler_pass,
+ .sa_flags = SA_SIGINFO,
+ };
+
+ sigbus_count = 0;
+ test_pass = 0;
+
+ buggy_offset = truncate_point / (hpage_size / page_size);
+ buggy_offset = PALIGN(buggy_offset, hpage_size);
+
+ /* First get arena of three hpages size, at file offset 4GB */
+ q = mmap64(NULL, 3*hpage_size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE, fd, truncate_point);
+ if (q == MAP_FAILED)
+ tst_brk(TBROK, "mmap() offset 4GB: %s", strerror(errno));
+ qi = q;
+ /* Touch the high page */
+ *qi = 0;
+
+ /* This part of the test makes the problem more obvious, but
+ * is not essential. It can't be done on segmented powerpc, where
+ * segment restrictions prohibit us from performing such a
+ * mapping, so skip it there. Similarly, ia64's address space
+ * restrictions prevent this.
+ */
+#if (defined(__powerpc__) && defined(PPC_NO_SEGMENTS)) \
+ || !defined(__powerpc__) && !defined(__powerpc64__) \
+ && !defined(__ia64__)
+ /* Replace middle hpage by tinypage mapping to trigger
+ * nr_ptes BUG
+ */
+ p = mmap64(q + hpage_size, hpage_size, PROT_READ|PROT_WRITE,
+ MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (p != q + hpage_size)
+ tst_brk(TBROK, "mmap() offset 4GB: %s", strerror(errno));
+ pi = p;
+ /* Touch one page to allocate its page table */
+ *pi = 0;
+#endif
+
+ /* Replace top hpage by hpage mapping at confusing file offset */
+ p = mmap64(q + 2*hpage_size, hpage_size, PROT_READ|PROT_WRITE,
+ MAP_FIXED|MAP_PRIVATE, fd, buggy_offset);
+ if (p != q + 2*hpage_size)
+ tst_brk(TBROK, "mmap() buggy offset 0x%llx", buggy_offset);
+ pi = p;
+ /* Touch the low page with something non-zero */
+ *pi = 1;
+
+ err = ftruncate64(fd, truncate_point);
+ if (err) {
+ tst_res(TFAIL, "ftruncate failed");
+ goto cleanup;
+ }
+
+ SAFE_SIGACTION(SIGBUS, &sa_fail, NULL);
+ if (sigsetjmp(sig_escape, 1) == 0)
+ if (*pi != 1) {
+ tst_res(TFAIL, "Data 1 has changed!");
+ goto cleanup;
+ }
+
+ SAFE_SIGACTION(SIGBUS, &sa_pass, NULL);
+ if (sigsetjmp(sig_escape, 1) == 0)
+ *qi;
+ else
+ sigbus_count++;
+ if (sigbus_count != 1)
+ /* Should have SIGBUSed above */
+ tst_res(TFAIL, "Didn't SIGBUS on truncated page.");
+ if (test_pass == 1)
+ tst_res(TPASS, "Expected SIGBUS");
+
+cleanup:
+ SAFE_MUNMAP(q, 3*hpage_size);
+ SAFE_MUNMAP(p, hpage_size);
+}
+
+static void setup(void)
+{
+ long long truncate_point;
+
+ page_size = getpagesize();
+ hpage_size = tst_get_hugepage_size();
+ fd = tst_creat_unlinked(MNTPOINT, 0);
+ truncate_point = FOURGIG;
+ if (hpage_size > truncate_point)
+ tst_brk(TCONF, "Huge page size is too large!");
+ if (truncate_point % hpage_size > 0)
+ tst_brk(TCONF, "Truncation point is not aligned to huge page size!");
+}
+
+static void cleanup(void)
+{
+ if (fd >= 0)
+ SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+ .tags = (struct tst_tag[]) {
+ {"linux-git", "856fc2950555"},
+ {}
+ },
+ .needs_root = 1,
+ .mntpoint = MNTPOINT,
+ .needs_hugetlbfs = 1,
+ .hugepages = {4, TST_NEEDS},
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = run_test,
+};
+
--
2.39.2 (Apple Git-143)
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [LTP] [PATCH v2] Migrating the libhugetlbfs/testcases/truncate_above_4GB.c test
2023-09-29 8:39 [LTP] [PATCH v2] Migrating the libhugetlbfs/testcases/truncate_above_4GB.c test Geetika
@ 2023-11-30 9:03 ` Richard Palethorpe
2024-03-27 13:31 ` Geetika M
0 siblings, 1 reply; 3+ messages in thread
From: Richard Palethorpe @ 2023-11-30 9:03 UTC (permalink / raw)
To: Geetika; +Cc: ltp
Hello,
Geetika <geetika@linux.ibm.com> writes:
> Test Description:
>
> A misconversion of hugetlb_vmtruncate_list to a prio_tree meant that
> on 32-bit machines, truncates at or above 4GB could truncate lower pages,
> resulting in BUG_ON()s. This kernel bug was fixed with
> 'commit 856fc2950555'.
>
> The purpose of this test is to check whether huge pages are handled correctly
> when a file is truncated above the 4GB boundary. It ensures that the memory is
> not corrupted or lost during the truncation process, and that the expected data
> is still present in the memory after truncation.
>
> Signed-off-by: Geetika <geetika@linux.ibm.com>
> ---
> v2:
> -Corrected typo
> ---
> runtest/hugetlb | 1 +
> testcases/kernel/mem/.gitignore | 1 +
> .../kernel/mem/hugetlb/hugemmap/hugemmap39.c | 171 ++++++++++++++++++
> 3 files changed, 173 insertions(+)
> create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap39.c
>
> diff --git a/runtest/hugetlb b/runtest/hugetlb
> index 299c07ac9..26587ecc0 100644
> --- a/runtest/hugetlb
> +++ b/runtest/hugetlb
> @@ -35,6 +35,7 @@ hugemmap29 hugemmap29
> hugemmap30 hugemmap30
> hugemmap31 hugemmap31
> hugemmap32 hugemmap32
> +hugemmap39 hugemmap39
> hugemmap05_1 hugemmap05 -m
> hugemmap05_2 hugemmap05 -s
> hugemmap05_3 hugemmap05 -s -m
> diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
> index 7258489ed..4c55d5c8c 100644
> --- a/testcases/kernel/mem/.gitignore
> +++ b/testcases/kernel/mem/.gitignore
> @@ -34,6 +34,7 @@
> /hugetlb/hugemmap/hugemmap30
> /hugetlb/hugemmap/hugemmap31
> /hugetlb/hugemmap/hugemmap32
> +/hugetlb/hugemmap/hugemmap39
> /hugetlb/hugeshmat/hugeshmat01
> /hugetlb/hugeshmat/hugeshmat02
> /hugetlb/hugeshmat/hugeshmat03
> diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap39.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap39.c
> new file mode 100644
> index 000000000..be5cba69f
> --- /dev/null
> +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap39.c
> @@ -0,0 +1,171 @@
> +// SPDX-License-Identifier: LGPL-2.1-or-later
> +/*
> + * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation.
> + * Copyright (C) 2006 Hugh Dickins <hugh@veritas.com>
> + */
> +
> +/*\
> + *[Descripiton]
> + *
> + * At one stage, a misconversion of hugetlb_vmtruncate_list to a
> + * prio_tree meant that on 32-bit machines, truncates at or above 4GB
> + * could truncate lower pages, resulting in BUG_ON()s.
> + *
> + * WARNING: The offsets and addresses used within are specifically
> + * calculated to trigger the bug as it existed. Don't mess with them
> + * unless you *really* know what you're doing.
> + *
> + */
> +
> +#define _GNU_SOURCE
> +#define _LARGEFILE64_SOURCE
> +#define FOURGIG ((off64_t)0x100000000ULL)
> +#define MNTPOINT "hugetlbfs/"
> +
> +#include <signal.h>
> +#include <setjmp.h>
> +#include "hugetlb.h"
> +
> +static int page_size;
> +static long hpage_size;
> +static int fd = -1;
> +static volatile int test_pass;
> +static int err;
> +static int sigbus_count;
> +static sigjmp_buf sig_escape;
> +
> +static void sigbus_handler_fail(int signum, siginfo_t *si, void *uc)
> +{
> + siglongjmp(sig_escape, 17);
> +}
> +
> +static void sigbus_handler_pass(int signum, siginfo_t *si, void *uc)
> +{
> + test_pass = 1;
> + siglongjmp(sig_escape, 17);
> +}
> +
> +static void run_test(void)
> +{
> + long long buggy_offset, truncate_point;
> + void *p, *q;
> + volatile unsigned int *pi, *qi;
> +
> + struct sigaction sa_pass = {
> + .sa_sigaction = sigbus_handler_pass,
> + .sa_flags = SA_SIGINFO,
> + };
> +
> + struct sigaction sa_fail = {
> + .sa_sigaction = sigbus_handler_pass,
> + .sa_flags = SA_SIGINFO,
> + };
> +
> + sigbus_count = 0;
> + test_pass = 0;
> +
> + buggy_offset = truncate_point / (hpage_size / page_size);
> + buggy_offset = PALIGN(buggy_offset, hpage_size);
> +
> + /* First get arena of three hpages size, at file offset 4GB */
> + q = mmap64(NULL, 3*hpage_size, PROT_READ|PROT_WRITE,
> + MAP_PRIVATE, fd, truncate_point);
> + if (q == MAP_FAILED)
> + tst_brk(TBROK, "mmap() offset 4GB: %s", strerror(errno));
In musl mmap64 is just defined as mmap or not at all if _GNU_SOURCE is
absent. So do we really need it? It seems likely to cause compilation
failures.
Instead we could just use SAFE_MMAP.
Same goes for truncate64 etc.
There are a lot of warnings when compiling this, we don't want to
introduce more warnings.
--
Thank you,
Richard.
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [LTP] [PATCH v2] Migrating the libhugetlbfs/testcases/truncate_above_4GB.c test
2023-11-30 9:03 ` Richard Palethorpe
@ 2024-03-27 13:31 ` Geetika M
0 siblings, 0 replies; 3+ messages in thread
From: Geetika M @ 2024-03-27 13:31 UTC (permalink / raw)
To: rpalethorpe; +Cc: ltp
Hello Richard,
On 30/11/23 2:33 pm, Richard Palethorpe wrote:
> Hello,
>
> Geetika<geetika@linux.ibm.com> writes:
>
....
>> +/*\
>> + *[Descripiton]
>> + *
>> + * At one stage, a misconversion of hugetlb_vmtruncate_list to a
>> + * prio_tree meant that on 32-bit machines, truncates at or above 4GB
>> + * could truncate lower pages, resulting in BUG_ON()s.
>> + *
>> + * WARNING: The offsets and addresses used within are specifically
>> + * calculated to trigger the bug as it existed. Don't mess with them
>> + * unless you *really* know what you're doing.
>> + *
>> + */
>> +
>> +#define _GNU_SOURCE
>> +#define _LARGEFILE64_SOURCE
>> +#define FOURGIG ((off64_t)0x100000000ULL)
>> +#define MNTPOINT "hugetlbfs/"
>> +
>> +#include <signal.h>
>> +#include <setjmp.h>
>> +#include "hugetlb.h"
>> +
>> +static int page_size;
>> +static long hpage_size;
>> +static int fd = -1;
>> +static volatile int test_pass;
>> +static int err;
>> +static int sigbus_count;
>> +static sigjmp_buf sig_escape;
>> +
>> +static void sigbus_handler_fail(int signum, siginfo_t *si, void *uc)
>> +{
>> + siglongjmp(sig_escape, 17);
>> +}
>> +
>> +static void sigbus_handler_pass(int signum, siginfo_t *si, void *uc)
>> +{
>> + test_pass = 1;
>> + siglongjmp(sig_escape, 17);
>> +}
>> +
>> +static void run_test(void)
>> +{
>> + long long buggy_offset, truncate_point;
>> + void *p, *q;
>> + volatile unsigned int *pi, *qi;
>> +
>> + struct sigaction sa_pass = {
>> + .sa_sigaction = sigbus_handler_pass,
>> + .sa_flags = SA_SIGINFO,
>> + };
>> +
>> + struct sigaction sa_fail = {
>> + .sa_sigaction = sigbus_handler_pass,
>> + .sa_flags = SA_SIGINFO,
>> + };
>> +
>> + sigbus_count = 0;
>> + test_pass = 0;
>> +
>> + buggy_offset = truncate_point / (hpage_size / page_size);
>> + buggy_offset = PALIGN(buggy_offset, hpage_size);
>> +
>> + /* First get arena of three hpages size, at file offset 4GB */
>> + q = mmap64(NULL, 3*hpage_size, PROT_READ|PROT_WRITE,
>> + MAP_PRIVATE, fd, truncate_point);
>> + if (q == MAP_FAILED)
>> + tst_brk(TBROK, "mmap() offset 4GB: %s", strerror(errno));
> In musl mmap64 is just defined as mmap or not at all if _GNU_SOURCE is
> absent. So do we really need it? It seems likely to cause compilation
> failures.
>
> Instead we could just use SAFE_MMAP.
>
> Same goes for truncate64 etc.
>
> There are a lot of warnings when compiling this, we don't want to
> introduce more warnings.
>
The "mmap64" function is used instead of "mmap" in this test because it
allows for mapping memory from files that are larger than 2 gigabytes
into the process memory.
In a 64-bit system, "mmap" and "mmap64" might behave the same way.
However, the key difference lies in the offset parameter. The "mmap"
function uses "off_t" type for the offset parameter, which is a 32-bit
type on some systems, limiting the file size to 2GB. On the other hand,
"mmap64" uses "off64_t" for the offset parameter, which is a 64-bit
type, allowing for larger file sizes.
This test case is for 32bit systems. On a 32-bit system, mmap and mmap64
serve similar purposes, but mmap64 is specifically designed to handle
files larger than 2GB. In test program we are mapping at file offset
4GB so we should use mmap64 with _LARGEFILE64_SOURCE macro.
_LARGEFILE64_SOURCE is already defined in the test program so on 32bit
systems it will take mmap64 path not mmap path.
Hence we cannot use SAFE_MMAP here.
I can work on fixing warnings related to unused parameters.
Are there any other warnings that you see with this code?
Thanks & Regards,
Geetika
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2024-03-27 13:32 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-09-29 8:39 [LTP] [PATCH v2] Migrating the libhugetlbfs/testcases/truncate_above_4GB.c test Geetika
2023-11-30 9:03 ` Richard Palethorpe
2024-03-27 13:31 ` Geetika M
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox