Commit e478425b authored by Ralph Campbell's avatar Ralph Campbell Committed by Jason Gunthorpe
Browse files

mm/hmm: add tests for hmm_pfn_to_map_order()

Add a sanity test for hmm_range_fault() returning the page mapping size
order.

Link: https://lore.kernel.org/r/20200701225352.9649-6-rcampbell@nvidia.com


Signed-off-by: default avatarRalph Campbell <rcampbell@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 3b50a6e5
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -766,6 +766,10 @@ static void dmirror_mkentry(struct dmirror *dmirror, struct hmm_range *range,
		*perm |= HMM_DMIRROR_PROT_WRITE;
	else
		*perm |= HMM_DMIRROR_PROT_READ;
	if (hmm_pfn_to_map_order(entry) + PAGE_SHIFT == PMD_SHIFT)
		*perm |= HMM_DMIRROR_PROT_PMD;
	else if (hmm_pfn_to_map_order(entry) + PAGE_SHIFT == PUD_SHIFT)
		*perm |= HMM_DMIRROR_PROT_PUD;
}

static bool dmirror_snapshot_invalidate(struct mmu_interval_notifier *mni,
+4 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ struct hmm_dmirror_cmd {
 * HMM_DMIRROR_PROT_NONE: unpopulated PTE or PTE with no access
 * HMM_DMIRROR_PROT_READ: read-only PTE
 * HMM_DMIRROR_PROT_WRITE: read/write PTE
 * HMM_DMIRROR_PROT_PMD: PMD sized page is fully mapped by same permissions
 * HMM_DMIRROR_PROT_PUD: PUD sized page is fully mapped by same permissions
 * HMM_DMIRROR_PROT_ZERO: special read-only zero page
 * HMM_DMIRROR_PROT_DEV_PRIVATE_LOCAL: Migrated device private page on the
 *					device the ioctl() is made
@@ -51,6 +53,8 @@ enum {
	HMM_DMIRROR_PROT_NONE			= 0x00,
	HMM_DMIRROR_PROT_READ			= 0x01,
	HMM_DMIRROR_PROT_WRITE			= 0x02,
	HMM_DMIRROR_PROT_PMD			= 0x04,
	HMM_DMIRROR_PROT_PUD			= 0x08,
	HMM_DMIRROR_PROT_ZERO			= 0x10,
	HMM_DMIRROR_PROT_DEV_PRIVATE_LOCAL	= 0x20,
	HMM_DMIRROR_PROT_DEV_PRIVATE_REMOTE	= 0x30,
+76 −0
Original line number Diff line number Diff line
@@ -1291,6 +1291,82 @@ TEST_F(hmm2, snapshot)
	hmm_buffer_free(buffer);
}

/*
 * Test the hmm_range_fault() HMM_PFN_PMD flag for large pages that
 * should be mapped by a large page table entry.
 */
TEST_F(hmm, compound)
{
	struct hmm_buffer *buffer;
	unsigned long npages;
	unsigned long size;
	int *ptr;
	unsigned char *m;
	int ret;
	long pagesizes[4];
	int n, idx;
	unsigned long i;

	/* Skip test if we can't allocate a hugetlbfs page. */

	n = gethugepagesizes(pagesizes, 4);
	if (n <= 0)
		return;
	for (idx = 0; --n > 0; ) {
		if (pagesizes[n] < pagesizes[idx])
			idx = n;
	}
	size = ALIGN(TWOMEG, pagesizes[idx]);
	npages = size >> self->page_shift;

	buffer = malloc(sizeof(*buffer));
	ASSERT_NE(buffer, NULL);

	buffer->ptr = get_hugepage_region(size, GHR_STRICT);
	if (buffer->ptr == NULL) {
		free(buffer);
		return;
	}

	buffer->size = size;
	buffer->mirror = malloc(npages);
	ASSERT_NE(buffer->mirror, NULL);

	/* Initialize the pages the device will snapshot in buffer->ptr. */
	for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
		ptr[i] = i;

	/* Simulate a device snapshotting CPU pagetables. */
	ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages);
	ASSERT_EQ(ret, 0);
	ASSERT_EQ(buffer->cpages, npages);

	/* Check what the device saw. */
	m = buffer->mirror;
	for (i = 0; i < npages; ++i)
		ASSERT_EQ(m[i], HMM_DMIRROR_PROT_WRITE |
				HMM_DMIRROR_PROT_PMD);

	/* Make the region read-only. */
	ret = mprotect(buffer->ptr, size, PROT_READ);
	ASSERT_EQ(ret, 0);

	/* Simulate a device snapshotting CPU pagetables. */
	ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages);
	ASSERT_EQ(ret, 0);
	ASSERT_EQ(buffer->cpages, npages);

	/* Check what the device saw. */
	m = buffer->mirror;
	for (i = 0; i < npages; ++i)
		ASSERT_EQ(m[i], HMM_DMIRROR_PROT_READ |
				HMM_DMIRROR_PROT_PMD);

	free_hugepage_region(buffer->ptr);
	buffer->ptr = NULL;
	hmm_buffer_free(buffer);
}

/*
 * Test two devices reading the same memory (double mapped).
 */