All of lore.kernel.org
 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: 12+ 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
2023-05-30  2:25   ` HORIGUCHI NAOYA(堀口 直也)
2023-05-30 21:31     ` Jiaqi Yan
2023-05-30 22:11       ` Jiaqi Yan
2023-06-01  2:58   ` HORIGUCHI NAOYA(堀口 直也)
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.