close(gup_fd);
        hmm_buffer_free(buffer);
 }
+
+/*
+ * Test copy-on-write in device pages.
+ * In case of writing to COW private page(s), a page fault will migrate pages
+ * back to system memory first. Then, these pages will be duplicated. In case
+ * of COW device coherent type, pages are duplicated directly from device
+ * memory.
+ */
+TEST_F(hmm, hmm_cow_in_device)
+{
+       struct hmm_buffer *buffer;
+       unsigned long npages;
+       unsigned long size;
+       unsigned long i;
+       int *ptr;
+       int ret;
+       unsigned char *m;
+       pid_t pid;
+       int status;
+
+       npages = 4;
+       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);
+
+       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] = i;
+
+       /* Migrate memory to device. */
+
+       ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
+       ASSERT_EQ(ret, 0);
+       ASSERT_EQ(buffer->cpages, npages);
+
+       pid = fork();
+       if (pid == -1)
+               ASSERT_EQ(pid, 0);
+       if (!pid) {
+               /* Child process waitd for SIGTERM from the parent. */
+               while (1) {
+               }
+               perror("Should not reach this\n");
+               exit(0);
+       }
+       /* Parent process writes to COW pages(s) and gets a
+        * new copy in system. In case of device private pages,
+        * this write causes a migration to system mem first.
+        */
+       for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
+               ptr[i] = i;
+
+       /* Terminate child and wait */
+       EXPECT_EQ(0, kill(pid, SIGTERM));
+       EXPECT_EQ(pid, waitpid(pid, &status, 0));
+       EXPECT_NE(0, WIFSIGNALED(status));
+       EXPECT_EQ(SIGTERM, WTERMSIG(status));
+
+       /* Take snapshot to CPU pagetables */
+       ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages);
+       ASSERT_EQ(ret, 0);
+       ASSERT_EQ(buffer->cpages, npages);
+       m = buffer->mirror;
+       for (i = 0; i < npages; i++)
+               ASSERT_EQ(HMM_DMIRROR_PROT_WRITE, m[i]);
+
+       hmm_buffer_free(buffer);
+}
 TEST_HARNESS_MAIN