mm/hmm.c: allow VM_MIXEDMAP to work with hmm_range_fault
commit87c01d57fa
upstream. hmm_range_fault() can be used instead of get_user_pages() for devices which allow faulting however unlike get_user_pages() it will return an error when used on a VM_MIXEDMAP range. To make hmm_range_fault() more closely match get_user_pages() remove this restriction. This requires dealing with the !ARCH_HAS_PTE_SPECIAL case in hmm_vma_handle_pte(). Rather than replicating the logic of vm_normal_page() call it directly and do a check for the zero pfn similar to what get_user_pages() currently does. Also add a test to hmm selftest to verify functionality. Link: https://lkml.kernel.org/r/20211104012001.2555676-1-apopple@nvidia.com Fixes:da4c3c735e
("mm/hmm/mirror: helper to snapshot CPU page table") Signed-off-by: Alistair Popple <apopple@nvidia.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Cc: Jerome Glisse <jglisse@redhat.com> Cc: John Hubbard <jhubbard@nvidia.com> Cc: Zi Yan <ziy@nvidia.com> Cc: Ralph Campbell <rcampbell@nvidia.com> Cc: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
42de0446a1
Коммит
52b66f8189
|
@ -1087,9 +1087,33 @@ static long dmirror_fops_unlocked_ioctl(struct file *filp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dmirror_fops_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) {
|
||||
struct page *page;
|
||||
int ret;
|
||||
|
||||
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = vm_insert_page(vma, addr, page);
|
||||
if (ret) {
|
||||
__free_page(page);
|
||||
return ret;
|
||||
}
|
||||
put_page(page);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations dmirror_fops = {
|
||||
.open = dmirror_fops_open,
|
||||
.release = dmirror_fops_release,
|
||||
.mmap = dmirror_fops_mmap,
|
||||
.unlocked_ioctl = dmirror_fops_unlocked_ioctl,
|
||||
.llseek = default_llseek,
|
||||
.owner = THIS_MODULE,
|
||||
|
|
5
mm/hmm.c
5
mm/hmm.c
|
@ -300,7 +300,8 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
|
|||
* Since each architecture defines a struct page for the zero page, just
|
||||
* fall through and treat it like a normal page.
|
||||
*/
|
||||
if (pte_special(pte) && !pte_devmap(pte) &&
|
||||
if (!vm_normal_page(walk->vma, addr, pte) &&
|
||||
!pte_devmap(pte) &&
|
||||
!is_zero_pfn(pte_pfn(pte))) {
|
||||
if (hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0)) {
|
||||
pte_unmap(ptep);
|
||||
|
@ -518,7 +519,7 @@ static int hmm_vma_walk_test(unsigned long start, unsigned long end,
|
|||
struct hmm_range *range = hmm_vma_walk->range;
|
||||
struct vm_area_struct *vma = walk->vma;
|
||||
|
||||
if (!(vma->vm_flags & (VM_IO | VM_PFNMAP | VM_MIXEDMAP)) &&
|
||||
if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)) &&
|
||||
vma->vm_flags & VM_READ)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -1248,6 +1248,48 @@ TEST_F(hmm, anon_teardown)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test memory snapshot without faulting in pages accessed by the device.
|
||||
*/
|
||||
TEST_F(hmm, mixedmap)
|
||||
{
|
||||
struct hmm_buffer *buffer;
|
||||
unsigned long npages;
|
||||
unsigned long size;
|
||||
unsigned char *m;
|
||||
int ret;
|
||||
|
||||
npages = 1;
|
||||
size = npages << self->page_shift;
|
||||
|
||||
buffer = malloc(sizeof(*buffer));
|
||||
ASSERT_NE(buffer, NULL);
|
||||
|
||||
buffer->fd = -1;
|
||||
buffer->size = size;
|
||||
buffer->mirror = malloc(npages);
|
||||
ASSERT_NE(buffer->mirror, NULL);
|
||||
|
||||
|
||||
/* Reserve a range of addresses. */
|
||||
buffer->ptr = mmap(NULL, size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE,
|
||||
self->fd, 0);
|
||||
ASSERT_NE(buffer->ptr, MAP_FAILED);
|
||||
|
||||
/* 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;
|
||||
ASSERT_EQ(m[0], HMM_DMIRROR_PROT_READ);
|
||||
|
||||
hmm_buffer_free(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test memory snapshot without faulting in pages accessed by the device.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче