]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
selftests/hmm-tests: add test for dirty bits
authorAlistair Popple <apopple@nvidia.com>
Tue, 16 Aug 2022 07:39:25 +0000 (17:39 +1000)
committerAndrew Morton <akpm@linux-foundation.org>
Fri, 26 Aug 2022 05:02:56 +0000 (22:02 -0700)
We were not correctly copying PTE dirty bits to pages during
migrate_vma_setup() calls.  This could potentially lead to data loss, so
add a test for this.

Link: https://lkml.kernel.org/r/23069a5c6e07d16d4c4f0951ff003591ffc4f656.1660635033.git-series.apopple@nvidia.com
Signed-off-by: Alistair Popple <apopple@nvidia.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Huang Ying <ying.huang@intel.com>
Cc: Alex Sierra <alex.sierra@amd.com>
Cc: Ben Skeggs <bskeggs@redhat.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Felix Kuehling <felix.kuehling@amd.com>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Karol Herbst <kherbst@redhat.com>
Cc: Logan Gunthorpe <logang@deltatee.com>
Cc: Lyude Paul <lyude@redhat.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Paul Mackerras <paulus@ozlabs.org>
Cc: Ralph Campbell <rcampbell@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
tools/testing/selftests/vm/hmm-tests.c

index f2c2c970eeb275224c5b78e20786b424104bdcd1..2b1e139e8650edcbb2478caea919661040ef6f42 100644 (file)
@@ -1240,6 +1240,130 @@ TEST_F(hmm, migrate_multiple)
        }
 }
 
+static char cgroup[] = "/sys/fs/cgroup/hmm-test-XXXXXX";
+static int write_cgroup_param(char *cgroup_path, char *param, long value)
+{
+       int ret;
+       FILE *f;
+       char *filename;
+
+       if (asprintf(&filename, "%s/%s", cgroup_path, param) < 0)
+               return -1;
+
+       f = fopen(filename, "w");
+       if (!f) {
+               ret = -1;
+               goto out;
+       }
+
+       ret = fprintf(f, "%ld\n", value);
+       if (ret < 0)
+               goto out1;
+
+       ret = 0;
+
+out1:
+       fclose(f);
+out:
+       free(filename);
+
+       return ret;
+}
+
+static int setup_cgroup(void)
+{
+       pid_t pid = getpid();
+       int ret;
+
+       if (!mkdtemp(cgroup))
+               return -1;
+
+       ret = write_cgroup_param(cgroup, "cgroup.procs", pid);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int destroy_cgroup(void)
+{
+       pid_t pid = getpid();
+       int ret;
+
+       ret = write_cgroup_param("/sys/fs/cgroup/cgroup.procs",
+                               "cgroup.proc", pid);
+       if (ret)
+               return ret;
+
+       if (rmdir(cgroup))
+               return -1;
+
+       return 0;
+}
+
+/*
+ * Try and migrate a dirty page that has previously been swapped to disk. This
+ * checks that we don't loose dirty bits.
+ */
+TEST_F(hmm, migrate_dirty_page)
+{
+       struct hmm_buffer *buffer;
+       unsigned long npages;
+       unsigned long size;
+       unsigned long i;
+       int *ptr;
+       int tmp = 0;
+
+       npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
+       ASSERT_NE(npages, 0);
+       size = npages << self->page_shift;
+
+       buffer = malloc(sizeof(*buffer));
+       ASSERT_NE(buffer, NULL);
+
+       buffer->fd = -1;
+       buffer->size = size;
+       buffer->mirror = malloc(size);
+       ASSERT_NE(buffer->mirror, NULL);
+
+       ASSERT_EQ(setup_cgroup(), 0);
+
+       buffer->ptr = mmap(NULL, size,
+                          PROT_READ | PROT_WRITE,
+                          MAP_PRIVATE | MAP_ANONYMOUS,
+                          buffer->fd, 0);
+       ASSERT_NE(buffer->ptr, MAP_FAILED);
+
+       /* Initialize buffer in system memory. */
+       for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
+               ptr[i] = 0;
+
+       ASSERT_FALSE(write_cgroup_param(cgroup, "memory.reclaim", 1UL<<30));
+
+       /* Fault pages back in from swap as clean pages */
+       for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
+               tmp += ptr[i];
+
+       /* Dirty the pte */
+       for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
+               ptr[i] = i;
+
+       /*
+        * Attempt to migrate memory to device, which should fail because
+        * hopefully some pages are backed by swap storage.
+        */
+       ASSERT_TRUE(hmm_migrate_sys_to_dev(self->fd, buffer, npages));
+
+       ASSERT_FALSE(write_cgroup_param(cgroup, "memory.reclaim", 1UL<<30));
+
+       /* Check we still see the updated data after restoring from swap. */
+       for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
+               ASSERT_EQ(ptr[i], i);
+
+       hmm_buffer_free(buffer);
+       destroy_cgroup();
+}
+
 /*
  * Read anonymous memory multiple times.
  */