linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Jiaqi Yan <jiaqiyan@google.com>
To: mike.kravetz@oracle.com, peterx@redhat.com, naoya.horiguchi@nec.com
Cc: songmuchun@bytedance.com, duenwen@google.com,
	axelrasmussen@google.com,  jthoughton@google.com,
	rientjes@google.com, linmiaohe@huawei.com,  shy828301@gmail.com,
	baolin.wang@linux.alibaba.com,  wangkefeng.wang@huawei.com,
	akpm@linux-foundation.org, linux-mm@kvack.org,
	 linux-kernel@vger.kernel.org, Jiaqi Yan <jiaqiyan@google.com>
Subject: [RFC PATCH v1 7/7] selftest/mm: test PAGESIZE unmapping UFFD WP marker HWPOISON pages
Date: Fri, 28 Apr 2023 00:41:39 +0000	[thread overview]
Message-ID: <20230428004139.2899856-8-jiaqiyan@google.com> (raw)
In-Reply-To: <20230428004139.2899856-1-jiaqiyan@google.com>

For not-yet-faulted hugepage containing HWPOISON raw page, test
1. only HWPOISON raw page will not be faulted, and a BUS_MCEERR_AR
   SIGBUS will be sent to userspace.
2. healthy raw pages are faulted in as normal. Since the hugepage
   has been writeprotect by UFFD, non BUS_MCEERR_AR SIGBUS will be
   sent to userspace.

Signed-off-by: Jiaqi Yan <jiaqiyan@google.com>
---
 tools/testing/selftests/mm/hugetlb-hgm.c | 170 +++++++++++++++++++++++
 1 file changed, 170 insertions(+)

diff --git a/tools/testing/selftests/mm/hugetlb-hgm.c b/tools/testing/selftests/mm/hugetlb-hgm.c
index bc9529986b66..81ee2d99fea8 100644
--- a/tools/testing/selftests/mm/hugetlb-hgm.c
+++ b/tools/testing/selftests/mm/hugetlb-hgm.c
@@ -515,6 +515,169 @@ static int uffd_register(int uffd, char *primary_map, unsigned long len,
 	return ioctl(uffd, UFFDIO_REGISTER, &reg);
 }
 
+static int setup_present_map(char *present_map, size_t len)
+{
+	size_t offset = 0;
+	unsigned char iter = 0;
+	unsigned long pagesize = getpagesize();
+	uint64_t size;
+
+	for (size = len/2; size >= pagesize;
+			offset += size, size /= 2) {
+		iter++;
+		memset(present_map + offset, iter, size);
+	}
+	return 0;
+}
+
+static enum test_status test_hwpoison_absent_uffd_wp(int fd, size_t hugepagesize, size_t len)
+{
+	int uffd;
+	char *absent_map, *present_map;
+	struct uffdio_api api;
+	int register_args;
+	struct sigaction new, old;
+	enum test_status status = TEST_SKIPPED;
+	const unsigned long pagesize = getpagesize();
+	const unsigned long hwpoison_index = 128;
+	char *hwpoison_addr;
+
+	if (hwpoison_index >= (len / pagesize)) {
+		printf(ERROR_PREFIX "hwpoison_index out of range");
+		return TEST_FAILED;
+	}
+
+	if (ftruncate(fd, len) < 0) {
+		perror(ERROR_PREFIX "ftruncate failed");
+		return TEST_FAILED;
+	}
+
+	uffd = userfaultfd(O_CLOEXEC);
+	if (uffd < 0) {
+		perror(ERROR_PREFIX "uffd not created");
+		return TEST_FAILED;
+	}
+
+	absent_map = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	if (absent_map == MAP_FAILED) {
+		perror(ERROR_PREFIX "mmap for ABSENT mapping failed");
+		goto close_uffd;
+	}
+	printf(PREFIX "ABSENT mapping: %p\n", absent_map);
+
+	api.api = UFFD_API;
+	api.features = UFFD_FEATURE_SIGBUS | UFFD_FEATURE_EXACT_ADDRESS |
+		UFFD_FEATURE_EVENT_FORK;
+	if (ioctl(uffd, UFFDIO_API, &api) == -1) {
+		perror(ERROR_PREFIX "UFFDIO_API failed");
+		goto unmap_absent;
+	}
+
+	/*
+	 * Register with UFFDIO_REGISTER_MODE_WP to have UFFD WP bit on
+	 * the HugeTLB page table entry.
+	 */
+	register_args = UFFDIO_REGISTER_MODE_MISSING | UFFDIO_REGISTER_MODE_WP;
+	if (uffd_register(uffd, absent_map, len, register_args)) {
+		perror(ERROR_PREFIX "UFFDIO_REGISTER failed");
+		goto unmap_absent;
+	}
+
+	new.sa_sigaction = &sigbus_handler;
+	new.sa_flags = SA_SIGINFO;
+	if (sigaction(SIGBUS, &new, &old) < 0) {
+		perror(ERROR_PREFIX "could not setup SIGBUS handler");
+		goto unmap_absent;
+	}
+
+	/*
+	 * Set WP markers to the absent huge mapping. With HGM enabled in
+	 * kernel CONFIG, memory_failure will enabled HGM in kernel,
+	 * so no need to enable HGM from userspace.
+	 */
+	if (userfaultfd_writeprotect(uffd, absent_map, len, true) < 0) {
+		status = TEST_FAILED;
+		goto unmap_absent;
+	}
+
+	status = TEST_PASSED;
+
+	/*
+	 * With MAP_SHARED hugetlb memory, we cna inject memory error to
+	 * not-yet-faulted mapping (absent_map) by injecting memory error
+	 * to a already faulted mapping (present_map).
+	 */
+	present_map = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	if (present_map == MAP_FAILED) {
+		perror(ERROR_PREFIX "mmap for non present mapping failed");
+		goto close_uffd;
+	}
+	printf(PREFIX "PRESENT mapping: %p\n", present_map);
+	setup_present_map(present_map, len);
+
+	hwpoison_addr = present_map + hwpoison_index * pagesize;
+	if (madvise(hwpoison_addr, pagesize, MADV_HWPOISON)) {
+		perror(PREFIX "MADV_HWPOISON a page in PRESENT mapping failed");
+		status = TEST_FAILED;
+		goto unmap_present;
+	}
+
+	printf(PREFIX "checking poisoned range [%p, %p) (len=%#lx) in PRESENT mapping\n",
+	       hwpoison_addr, hwpoison_addr + pagesize, pagesize);
+	if (test_sigbus(hwpoison_addr, true) < 0) {
+		status = TEST_FAILED;
+		goto done;
+	}
+	printf(PREFIX "checking healthy pages in PRESENT mapping\n");
+	unsigned long hwpoison_addrs[] = {
+		(unsigned long)hwpoison_addr,
+		(unsigned long)hwpoison_addr,
+		(unsigned long)hwpoison_addr
+	};
+	status = verify_raw_pages(present_map, len, hwpoison_addrs);
+	if (status != TEST_PASSED) {
+		printf(ERROR_PREFIX "checking healthy pages failed\n");
+		goto done;
+	}
+
+	for (int i = 0; i < len; i += pagesize) {
+		if (i == hwpoison_index * pagesize) {
+			printf(PREFIX "checking poisoned range [%p, %p) (len=%#lx) in ABSENT mapping\n",
+				absent_map + i, absent_map + i + pagesize, pagesize);
+			if (test_sigbus(absent_map + i, true) < 0) {
+				status = TEST_FAILED;
+				break;
+			}
+		} else {
+			/*
+			 * With UFFD_FEATURE_SIGBUS, we should get a SIGBUS for
+			 * every not faulted (non present) page/byte.
+			 */
+			if (test_sigbus(absent_map + i, false) < 0) {
+				printf(PREFIX "checking healthy range [%p, %p) (len=%#lx) in ABSENT mapping failed\n",
+					absent_map + i, absent_map + i + pagesize, pagesize);
+				status = TEST_FAILED;
+				break;
+			}
+		}
+	}
+done:
+	if (ftruncate(fd, 0) < 0) {
+		perror(ERROR_PREFIX "ftruncate back to 0 failed");
+		status = TEST_FAILED;
+	}
+unmap_present:
+	printf(PREFIX "Unmap PRESENT mapping=%p\n", absent_map);
+	munmap(present_map, len);
+unmap_absent:
+	printf(PREFIX "Unmap ABSENT mapping=%p\n", absent_map);
+	munmap(absent_map, len);
+close_uffd:
+	printf(PREFIX "Close UFFD\n");
+	close(uffd);
+	return status;
+}
+
 enum test_type {
 	TEST_DEFAULT,
 	TEST_UFFDWP,
@@ -744,6 +907,13 @@ int main(void)
 	printf("HGM hwpoison test: %s\n", status_to_str(status));
 	if (status == TEST_FAILED)
 		ret = -1;
+
+	printf("HGM hwpoison UFFD-WP marker test...\n");
+	status = test_hwpoison_absent_uffd_wp(fd, hugepagesize, len);
+	printf("HGM hwpoison UFFD-WP marker test: %s\n",
+		status_to_str(status));
+	if (status == TEST_FAILED)
+		ret = -1;
 close:
 	close(fd);
 
-- 
2.40.1.495.gc816e09b53d-goog



      parent reply	other threads:[~2023-04-28  0:42 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-28  0:41 [RFC PATCH v1 0/7] PAGE_SIZE Unmapping in Memory Failure Recovery for HugeTLB Pages Jiaqi Yan
2023-04-28  0:41 ` [RFC PATCH v1 1/7] hugetlb: add HugeTLB splitting functionality Jiaqi Yan
2023-04-28  0:41 ` [RFC PATCH v1 2/7] hugetlb: create PTE level mapping when possible Jiaqi Yan
2023-04-28  0:41 ` [RFC PATCH v1 3/7] mm: publish raw_hwp_page in mm.h Jiaqi Yan
2023-04-28  0:41 ` [RFC PATCH v1 4/7] mm/memory_failure: unmap raw HWPoison PTEs when possible Jiaqi Yan
     [not found]   ` <20230530022456.GA1434147@hori.linux.bs1.fc.nec.co.jp>
2023-05-30 21:31     ` Jiaqi Yan
2023-05-30 22:11       ` Jiaqi Yan
2023-04-28  0:41 ` [RFC PATCH v1 5/7] hugetlb: only VM_FAULT_HWPOISON_LARGE raw page Jiaqi Yan
2023-04-28  0:41 ` [RFC PATCH v1 6/7] selftest/mm: test PAGESIZE unmapping HWPOISON pages Jiaqi Yan
2023-04-28  0:41 ` Jiaqi Yan [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230428004139.2899856-8-jiaqiyan@google.com \
    --to=jiaqiyan@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=axelrasmussen@google.com \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=duenwen@google.com \
    --cc=jthoughton@google.com \
    --cc=linmiaohe@huawei.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mike.kravetz@oracle.com \
    --cc=naoya.horiguchi@nec.com \
    --cc=peterx@redhat.com \
    --cc=rientjes@google.com \
    --cc=shy828301@gmail.com \
    --cc=songmuchun@bytedance.com \
    --cc=wangkefeng.wang@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox