mm/hmm: add tests for hmm_pfn_to_map_order()
authorRalph Campbell <rcampbell@nvidia.com>
Wed, 1 Jul 2020 22:53:52 +0000 (15:53 -0700)
committerJason Gunthorpe <jgg@nvidia.com>
Fri, 10 Jul 2020 19:24:28 +0000 (16:24 -0300)
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: Ralph Campbell <rcampbell@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
lib/test_hmm.c
lib/test_hmm_uapi.h
tools/testing/selftests/vm/hmm-tests.c

index a2a8226..9aa577a 100644 (file)
@@ -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,
index 67b3b2e..670b4ef 100644 (file)
@@ -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,
index 79db226..b533dd0 100644 (file)
@@ -1292,6 +1292,82 @@ TEST_F(hmm2, snapshot)
 }
 
 /*
+ * 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).
  */
 TEST_F(hmm2, double_map)