HMM tests and minor fixes
Subsystems (5)
v4 cover HMM tests and minor fixes
These changes are based on Jason's rdma/hmm branch (5.4.0-rc5). Patch 1 was previously posted here [1] but was dropped from that orginal series. Hopefully, the tests will reduce concerns about edge conditions. I'm sure more tests could be usefully added but I thought this was a good starting point.
Changes since v3:
patch 1:
Unchanged except rebased on Jason's latest hmm (bbe3329e354d3ab5dc18). patch 2:
Is now part of Jason's tree.
patch 3 (now 2):
Major changes to incorporate Jason's review feedback.
* drivers/char/hmm_dmirror.c driver moved to lib/test_hmm.c
* XArray used instead of "page tables".
* platform device driver removed.
* remove redundant copyright.
Changes since v2:
patch 1:
Removed hmm_range_needs_fault() and just use hmm_range_need_fault(). Updated the change log to include that it fixes a bug where hmm_range_fault() incorrectly returned an error when no fault is requested. patch 2:
Removed the confusing change log wording about DMA.
Changed hmm_range_fault() to return the PFN of the zero page like any other page.
patch 3:
Adjusted the test code to match the new zero page behavior.
Changes since v1:
Rebased to Jason's rdma/hmm branch (5.4.0-rc1). Cleaned up locking for the test driver's page tables. Incorporated Christoph Hellwig's comments.
[1] https://lore.kernel.org/linux-mm/[email protected]/
Ralph Campbell (2):
mm/hmm: make full use of walk_page_range()
mm/hmm/test: add self tests for HMM
MAINTAINERS | 3 + include/uapi/linux/test_hmm.h | 59 ++ lib/Kconfig.debug | 11 + lib/Makefile | 1 + lib/test_hmm.c | 1306 ++++++++++++++++++++++++ mm/hmm.c | 121 ++- tools/testing/selftests/vm/.gitignore | 1 + tools/testing/selftests/vm/Makefile | 3 + tools/testing/selftests/vm/config | 2 + tools/testing/selftests/vm/hmm-tests.c | 1295 +++++++++++++++++++++++ tools/testing/selftests/vm/run_vmtests | 16 + tools/testing/selftests/vm/test_hmm.sh | 97 ++ 12 files changed, 2852 insertions(+), 63 deletions(-) create mode 100644 include/uapi/linux/test_hmm.h create mode 100644 lib/test_hmm.c create mode 100644 tools/testing/selftests/vm/hmm-tests.c create mode 100755 tools/testing/selftests/vm/test_hmm.sh
Signature · 1 line
2.20.1
PATCH v4 1/2 mm/hmm: make full use of walk_page_range()
hmm_range_fault() calls find_vma() and walk_page_range() in a loop. This is unnecessary duplication since walk_page_range() calls find_vma() in a loop already.
Simplify hmm_range_fault() by defining a walk_test() callback function to filter unhandled vmas.
This also fixes a bug where hmm_range_fault() was not checking start >= vma->vm_start before checking vma->vm_flags so hmm_range_fault() could return an error based on the wrong vma for the requested range. It also fixes a bug when the vma has no read access and the caller did not request a fault, there shouldn't be any error return code.
--- mm/hmm.c | 121 ++++++++++++++++++++++++++----------------------------- 1 file changed, 58 insertions(+), 63 deletions(-)
mm/hmm.c +58 -63
@@ -65,18 +65,15 @@ static int hmm_vma_do_fault(struct mm_walk *walk, unsigned long addr,return -EFAULT ; } -static int hmm_pfns_bad (unsigned long addr, -unsigned long end, -struct mm_walk *walk) +static int hmm_pfns_fill (unsigned long addr,unsigned long end, +struct hmm_range *range,enum hmm_pfn_value_e value) { -struct hmm_vma_walk *hmm_vma_walk = walk->private; -struct hmm_range *range = hmm_vma_walk->range;uint64_t *pfns = range->pfns;unsigned long i; i = (addr - range->start) >>PAGE_SHIFT ;for (; addr < end; addr +=PAGE_SIZE , i++) - pfns[i] = range->values[HMM_PFN_ERROR ]; + pfns[i] = range->values[value];return 0 ; }
@@ -403,7 +400,7 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp, }return 0 ; }else if (!pmd_present (pmd)) -return hmm_pfns_bad (start, end, walk); +return hmm_pfns_fill (start, end, range,HMM_PFN_ERROR );if (pmd_devmap (pmd) ||pmd_trans_huge (pmd)) {/*
@@ -431,7 +428,7 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,* recover. */ if (pmd_bad (pmd)) -return hmm_pfns_bad (start, end, walk); +return hmm_pfns_fill (start, end, range,HMM_PFN_ERROR ); ptep =pte_offset_map (pmdp, addr); i = (addr - range->start) >>PAGE_SHIFT ;
@@ -589,13 +586,47 @@ static int hmm_vma_walk_hugetlb_entry(pte_t *pte, unsigned long hmask,#define hmm_vma_walk_hugetlb_entry NULL#endif /* CONFIG_HUGETLB_PAGE */ -static void hmm_pfns_clear (struct hmm_range *range, -uint64_t *pfns, -unsigned long addr, -unsigned long end) +static int hmm_vma_walk_test (unsigned long start,unsigned long end, +struct mm_walk *walk) { -for (; addr < end; addr +=PAGE_SIZE , pfns++) - *pfns = range->values[HMM_PFN_NONE ]; +struct hmm_vma_walk *hmm_vma_walk = walk->private; +struct hmm_range *range = hmm_vma_walk->range; +struct vm_area_struct *vma = walk->vma; + +/* +* Skip vma ranges that don't have struct page backing them or +* map I/O devices directly. +*/ +if (vma->vm_flags & (VM_IO |VM_PFNMAP |VM_MIXEDMAP )) +return -EFAULT ; + +/* +* If the vma does not allow read access, then assume that it does not +* allow write access either. HMM does not support architectures +* that allow write without read. +*/ +if (!(vma->vm_flags &VM_READ )) { +bool fault, write_fault; + +/* +* Check to see if a fault is requested for any page in the +* range. +*/ +hmm_range_need_fault (hmm_vma_walk, range->pfns + + ((start - range->start) >>PAGE_SHIFT ), + (end - start) >>PAGE_SHIFT , +0 , &fault, &write_fault); +if (fault || write_fault) +return -EFAULT ; + +hmm_pfns_fill (start, end, range,HMM_PFN_NONE ); + hmm_vma_walk->last = end; + +/* Skip this vma and continue processing the next vma. */ +return 1 ; + } + +return 0 ; }static const struct mm_walk_ops hmm_walk_ops = {
@@ -603,6 +634,7 @@ static const struct mm_walk_ops hmm_walk_ops = { .pmd_entry = hmm_vma_walk_pmd, .pte_hole = hmm_vma_walk_hole, .hugetlb_entry = hmm_vma_walk_hugetlb_entry, + .test_walk = hmm_vma_walk_test, };/**
@@ -635,11 +667,13 @@ static const struct mm_walk_ops hmm_walk_ops = {*/ long hmm_range_fault (struct hmm_range *range,unsigned int flags) { -const unsigned long device_vma =VM_IO |VM_PFNMAP |VM_MIXEDMAP ; -unsigned long start = range->start, end; -struct hmm_vma_walk hmm_vma_walk; +unsigned long start = range->start; +struct hmm_vma_walk hmm_vma_walk = { + .range = range, + .last = start, + .flags = flags, + };struct mm_struct *mm = range->notifier->mm; -struct vm_area_struct *vma;int ret;lockdep_assert_held (&mm->mmap_sem);
@@ -648,52 +682,13 @@ long hmm_range_fault(struct hmm_range *range, unsigned int flags)/* If range is no longer valid force retry. */ if (mmu_range_check_retry (range->notifier, range->notifier_seq))return -EBUSY ; + ret =walk_page_range (mm, start, range->end, &hmm_walk_ops, + &hmm_vma_walk); + start = hmm_vma_walk.last; + }while (ret == -EBUSY ); - vma =find_vma (mm, start); -if (vma ==NULL || (vma->vm_flags & device_vma)) -return -EFAULT ; - -if (!(vma->vm_flags &VM_READ )) { -/* -* If vma do not allow read access, then assume that it -* does not allow write access, either. HMM does not -* support architecture that allow write without read. -*/ -hmm_pfns_clear (range, range->pfns, - range->start, range->end); -return -EPERM ; - } - - hmm_vma_walk.pgmap =NULL ; - hmm_vma_walk.last = start; - hmm_vma_walk.flags = flags; - hmm_vma_walk.range = range; - end =min (range->end, vma->vm_end); - -walk_page_range (vma->vm_mm, start, end, &hmm_walk_ops, - &hmm_vma_walk); - -do { - ret =walk_page_range (vma->vm_mm, start, end, - &hmm_walk_ops, &hmm_vma_walk); - start = hmm_vma_walk.last; - -/* Keep trying while the range is valid. */ - }while (ret == -EBUSY && - !mmu_range_check_retry (range->notifier, - range->notifier_seq)); - -if (ret) { -unsigned long i; - - i = (hmm_vma_walk.last - range->start) >>PAGE_SHIFT ; -hmm_pfns_clear (range, &range->pfns[i], - hmm_vma_walk.last, range->end); -return ret; - } - start = end; - - }while (start < range->end); +if (ret) +return ret;return (hmm_vma_walk.last - range->start) >>PAGE_SHIFT ; }
Signature · 1 line
2.20.1
Re: [PATCH v4 1/2] mm/hmm: make full use of walk_page_range()
Looks good,
Although we could clean this up a tidbit more by removing the start variable:
mm/hmm.c +3 -5
@@ -667,10 +667,9 @@ static const struct mm_walk_ops hmm_walk_ops = {*/ long hmm_range_fault (struct hmm_range *range,unsigned int flags) { -unsigned long start = range->start;struct hmm_vma_walk hmm_vma_walk = { .range = range, - .last = start, + .last = range->start, .flags = flags, };struct mm_struct *mm = range->notifier->mm;
@@ -682,9 +681,8 @@ long hmm_range_fault(struct hmm_range *range, unsigned int flags)/* If range is no longer valid force retry. */ if (mmu_range_check_retry (range->notifier, range->notifier_seq))return -EBUSY ; - ret =walk_page_range (mm, start, range->end, &hmm_walk_ops, - &hmm_vma_walk); - start = hmm_vma_walk.last; + ret =walk_page_range (mm, hmm_vma_walk.last, range->end, + &hmm_walk_ops, &hmm_vma_walk); }while (ret == -EBUSY );if (ret)
Re: [PATCH v4 1/2] mm/hmm: make full use of walk_page_range()
Quoted 26 lines · Christoph Hellwig
Looks good,
Reviewed-by Christoph Hellwig <[email protected]>Although we could clean this up a tidbit more by removing the start variable:
mm/hmm.c +1
-2@@ -667,10 +667,9 @@ static const struct mm_walk_ops hmm_walk_ops = {*/ long hmm_range_fault (struct hmm_range *range,unsigned int flags) { -unsigned long start = range->start;struct hmm_vma_walk hmm_vma_walk = { .range = range, - .last = start, + .last = range->start, .flags = flags, };struct mm_struct *mm = range->notifier->mm;@@ -682,9 +681,8 @@ long hmm_range_fault(struct hmm_range *range, unsigned int flags)/* If range is no longer valid force retry. */
mm/hmm.c long hmm_range_fault(struct hmm_range *range, unsigned int flags) · line 688
Quoted 10 lines
mm/hmm.c +2
-3if (mmu_range_check_retry (range->notifier, range->notifier_seq))return -EBUSY ; - ret =walk_page_range (mm, start, range->end, &hmm_walk_ops, - &hmm_vma_walk); - start = hmm_vma_walk.last; + ret =walk_page_range (mm, hmm_vma_walk.last, range->end, + &hmm_walk_ops, &hmm_vma_walk); }while (ret == -EBUSY );if (ret)
Thanks for the review.
I'll add this to patch 1 since I need to send a v5 for patch 2.
Jason Gunthorpe
AppliedRe: [PATCH v4 1/2] mm/hmm: make full use of walk_page_range()
In reply to Ralph CampbellQuoted 11 lines · Ralph Campbell
hmm_range_fault()callsfind_vma()andwalk_page_range()in a loop. This is unnecessary duplication sincewalk_page_range()callsfind_vma()in a loop already.
Simplifyhmm_range_fault()by defining awalk_test()callback function to filter unhandled vmas.
This also fixes a bug wherehmm_range_fault()was not checking start >=vma->vm_startbefore checkingvma->vm_flagssohmm_range_fault()could return an error based on the wrong vma for the requested range. It also fixes a bug when the vma has no read access and the caller did not request a fault, there shouldn't be any error return code.
Quoted 8 lines
Signed-off-by Ralph Campbell <[email protected]>Cc "Jérôme Glisse" <[email protected]>Cc Jason Gunthorpe <[email protected]>Cc Christoph Hellwig <[email protected]>Reviewed-by Christoph Hellwig <[email protected]>--- mm/hmm.c | 121 ++++++++++++++++++++++++++----------------------------- 1 file changed, 58 insertions(+), 63 deletions(-)
Applied to hmm.git with Christoph's hunk merged in
Thanks,
Jason
PATCH v4 2/2 mm/hmm/test: add self tests for HMM
In reply to Ralph CampbellAdd self tests for HMM.
--- MAINTAINERS | 3 + include/uapi/linux/test_hmm.h | 59 ++ lib/Kconfig.debug | 11 + lib/Makefile | 1 + lib/test_hmm.c | 1306 ++++++++++++++++++++++++ tools/testing/selftests/vm/.gitignore | 1 + tools/testing/selftests/vm/Makefile | 3 + tools/testing/selftests/vm/config | 2 + tools/testing/selftests/vm/hmm-tests.c | 1295 +++++++++++++++++++++++ tools/testing/selftests/vm/run_vmtests | 16 + tools/testing/selftests/vm/test_hmm.sh | 97 ++ 11 files changed, 2794 insertions(+) create mode 100644 include/uapi/linux/test_hmm.h create mode 100644 lib/test_hmm.c create mode 100644 tools/testing/selftests/vm/hmm-tests.c create mode 100755 tools/testing/selftests/vm/test_hmm.sh
MAINTAINERS +3 -0
@@ -7428,7 +7428,10 @@ L: [email protected] S: Maintained F: mm/hmm* F: include/linux/hmm* +F: include/uapi/linux/test_hmm* F: Documentation/vm/hmm.rst +F: lib/test_hmm* +F: tools/testing/selftests/vm/*hmm* HOST AP DRIVER M: Jouni Malinen <[email protected]>
include/uapi/linux/test_hmm.h new file +59 -0
59 lines not on this page · raw message
lib/Kconfig.debug +11 -0
@@ -2057,6 +2057,17 @@ config TEST_MEMINIT If unsure, say N. +config TEST_HMM + tristate "Test HMM (Heterogeneous Memory Management)" + depends on HMM_MIRROR + depends on DEVICE_PRIVATE + help + This is a pseudo device driver solely for testing HMM. + Say M here if you want to build the HMM test module. + Doing so will allow you to run tools/testing/selftest/vm/hmm-tests. + + If unsure, say N. + endif # RUNTIME_TESTING_MENU config MEMTEST
lib/Makefile +1 -0
@@ -89,6 +89,7 @@ obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o obj-$(CONFIG_TEST_STACKINIT) += test_stackinit.o obj-$(CONFIG_TEST_BLACKHOLE_DEV) += test_blackhole_dev.o obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o +obj-$(CONFIG_TEST_HMM) += test_hmm.o obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
lib/test_hmm.c new file +1306 -0
1,306 lines not on this page · raw message
tools/testing/selftests/vm/.gitignore +1 -0
@@ -14,3 +14,4 @@ virtual_address_range gup_benchmark va_128TBswitch map_fixed_noreplace +hmm-tests
tools/testing/selftests/vm/Makefile +3 -0
@@ -5,6 +5,7 @@ CFLAGS = -Wall -I ../../../../usr/include $(EXTRA_CFLAGS) LDLIBS = -lrt TEST_GEN_FILES = compaction_test TEST_GEN_FILES += gup_benchmark +TEST_GEN_FILES += hmm-tests TEST_GEN_FILES += hugepage-mmap TEST_GEN_FILES += hugepage-shm TEST_GEN_FILES += map_hugetlb
@@ -26,6 +27,8 @@ TEST_FILES := test_vmalloc.sh KSFT_KHDR_INSTALL := 1 include ../lib.mk +$(OUTPUT)/hmm-tests: LDLIBS += -lhugetlbfs -lpthread + $(OUTPUT)/userfaultfd: LDLIBS += -lpthread $(OUTPUT)/mlock-random-test: LDLIBS += -lcap
tools/testing/selftests/vm/config +2 -0
@@ -1,2 +1,4 @@ CONFIG_SYSVIPC=y CONFIG_USERFAULTFD=y +CONFIG_HMM_MIRROR=y +CONFIG_DEVICE_PRIVATE=y
tools/testing/selftests/vm/hmm-tests.c new file +1295 -0
1,295 lines not on this page · raw message
tools/testing/selftests/vm/run_vmtests +16 -0
@@ -227,4 +227,20 @@ else exitcode=1 fi +echo "------------------------------------" +echo "running HMM smoke test" +echo "------------------------------------" +./test_hmm.sh smoke +ret_val=$? + +if [ $ret_val -eq 0 ]; then + echo "[PASS]" +elif [ $ret_val -eq $ksft_skip ]; then + echo "[SKIP]" + exitcode=$ksft_skip +else + echo "[FAIL]" + exitcode=1 +fi + exit $exitcode
tools/testing/selftests/vm/test_hmm.sh new file +97 -0
97 lines not on this page · raw message
Signature · 1 line
2.20.1
Re: [PATCH v4 2/2] mm/hmm/test: add self tests for HMM
Shouldn't this go into mm/ instead? It certainly doesn't seem like a library.
Quoted 8 lines
lib/test_hmm.c new file +8
-0+static int dmirror_bounce_copy_from (struct dmirror_bounce *bounce, +unsigned long addr) +{ +unsigned long end = addr + bounce->size; +char __user *uptr = (void __user *)addr; +void *ptr = bounce->ptr; + + for (; addr < end; addr += PAGE_SIZE, ptr += PAGE_SIZE,
lib/test_hmm.c line 145
Quoted 10 lines
lib/test_hmm.c new file +10
-0+ uptr += PAGE_SIZE) { +int ret; + + ret =copy_from_user (ptr, uptr,PAGE_SIZE ); +if (ret) +return ret; + } + +return 0 ; +}
Why does this iterate in page sized chunks? I don't remember a page size limit on copy_{from,to}_user.
Quoted 4 lines
lib/test_hmm.c new file +4
-0+static int dmirror_invalidate_range_start (struct mmu_notifier *mn, +const struct mmu_notifier_range *update) +{ + struct dmirror *dmirror = container_of(mn, struct dmirror, notifier);
lib/test_hmm.c line 198
Quoted 10 lines
lib/test_hmm.c new file +10
-0+ +if (mmu_notifier_range_blockable (update)) +mutex_lock (&dmirror->mutex); +else if (!mutex_trylock (&dmirror->mutex)) +return -EAGAIN ; + +dmirror_do_update (dmirror, update->start, update->end); +mutex_unlock (&dmirror->mutex); +return 0 ; +}
Can we adopts this to Jasons new interval tree invalidate?
lib/test_hmm.c line 254
Quoted 9 lines
lib/test_hmm.c new file +9
-0+static int dmirror_fops_open (struct inode *inode,struct file *filp) +{ +struct cdev *cdev = inode->i_cdev; +struct dmirror_device *mdevice; +struct dmirror *dmirror; + +/* No exclusive opens. */ +if (filp->f_flags &O_EXCL ) +return -EINVAL ;
Device files usually just ignore O_EXCL, I don't see why this one would be any different.
lib/test_hmm.c line 266
Quoted 11 lines
lib/test_hmm.c new file +11
-0+ mdevice = container_of(cdev, struct dmirror_device, cdevice); + dmirror =dmirror_new (mdevice); +if (!dmirror) +return -ENOMEM ; + +/* Only the first open registers the address space. */ +mutex_lock (&mdevice->devmem_lock); +if (filp->private_data) + goto err_busy; + filp->private_data = dmirror; +mutex_unlock (&mdevice->devmem_lock);
->open is only called for the first open of a given file structure..
lib/test_hmm.c line 281
Quoted 6 lines
lib/test_hmm.c new file +6
-0+static int dmirror_fops_release (struct inode *inode,struct file *filp) +{ +struct dmirror *dmirror = filp->private_data; + +if (!dmirror) +return 0 ;
This can't happen if your ->open never returns 0 without setting the private data.
lib/test_hmm.c line 283
Quoted 1 line
lib/test_hmm.c new file +1
-0+ filp->private_data =NULL ;
The file is feed afterwards, no need to clear the private data.
Re: [PATCH v4 2/2] mm/hmm/test: add self tests for HMM
Quoted 2 lines · Christoph Hellwig
Shouldn't this go into
mm/instead? It certainly doesn't seem like a library.
I was following the convention for the other vm test kernel modules. I see a couple of modules in mm/ but I don't have a personal preference for where to place it.
Andrew, do you have a preference?
Quoted 13 lines
Quoted 13 lines
lib/test_hmm.c new file +13
-0+static int dmirror_bounce_copy_from (struct dmirror_bounce *bounce, +unsigned long addr) +{ +unsigned long end = addr + bounce->size; +char __user *uptr = (void __user *)addr; +void *ptr = bounce->ptr; + +for (; addr < end; addr +=PAGE_SIZE , ptr +=PAGE_SIZE , + uptr +=PAGE_SIZE ) { +int ret; + + ret =copy_from_user (ptr, uptr,PAGE_SIZE ); +if (ret)
Quoted 8 lines
lib/test_hmm.c line 145
Quoted 5 lines
lib/test_hmm.c new file +5
-0+return ret; + } + +return 0 ; +}Why does this iterate in page sized chunks? I don't remember a page size limit on copy_{from,to}_user.
Good point. I'll fix that.
Quoted 8 lines
Quoted 8 lines
lib/test_hmm.c new file +8
-0+static int dmirror_invalidate_range_start (struct mmu_notifier *mn, +const struct mmu_notifier_range *update) +{ + struct dmirror *dmirror = container_of(mn, struct dmirror, notifier); + +if (mmu_notifier_range_blockable (update)) +mutex_lock (&dmirror->mutex); +else if (!mutex_trylock (&dmirror->mutex))
Quoted 8 lines
lib/test_hmm.c line 198
Quoted 6 lines
lib/test_hmm.c new file +6
-0+return -EAGAIN ; + +dmirror_do_update (dmirror, update->start, update->end); +mutex_unlock (&dmirror->mutex); +return 0 ; +}Can we adopts this to Jasons new interval tree invalidate?
Well, it would mean registering for the whole process address space. I'll give it a try.
Quoted 4 lines
Quoted 4 lines
lib/test_hmm.c new file +4
-0+static int dmirror_fops_open (struct inode *inode,struct file *filp) +{ +struct cdev *cdev = inode->i_cdev; +struct dmirror_device *mdevice;
Quoted 8 lines
lib/test_hmm.c line 254
Quoted 5 lines
lib/test_hmm.c new file +5
-0+struct dmirror *dmirror; + +/* No exclusive opens. */ +if (filp->f_flags &O_EXCL ) +return -EINVAL ;Device files usually just ignore
O_EXCL, I don't see why this one would be any different.
OK, I'll remove that test.
Quoted 24 lines
lib/test_hmm.c line 266
Quoted 11 lines
lib/test_hmm.c new file +11
-0+ mdevice = container_of(cdev, struct dmirror_device, cdevice); + dmirror =dmirror_new (mdevice); +if (!dmirror) +return -ENOMEM ; + +/* Only the first open registers the address space. */ +mutex_lock (&mdevice->devmem_lock); +if (filp->private_data) + goto err_busy; + filp->private_data = dmirror; +mutex_unlock (&mdevice->devmem_lock);->open is only called for the first open of a given file structure..
lib/test_hmm.c line 281
Quoted 6 lines
lib/test_hmm.c new file +6
-0+static int dmirror_fops_release (struct inode *inode,struct file *filp) +{ +struct dmirror *dmirror = filp->private_data; + +if (!dmirror) +return 0 ;This can't happen if your ->open never returns 0 without setting the private data.
Quoted 3 lines
lib/test_hmm.c line 283
Quoted 1 line
lib/test_hmm.c new file +1
-0+ filp->private_data =NULL ;The file is feed afterwards, no need to clear the private data.
OK, I'll clean that up.
Re: [PATCH v4 2/2] mm/hmm/test: add self tests for HMM
Quoted 17 lines · Ralph Campbell
Quoted 8 lines
Quoted 8 lines
lib/test_hmm.c new file +8
-0+static int dmirror_invalidate_range_start (struct mmu_notifier *mn, +const struct mmu_notifier_range *update) +{ + struct dmirror *dmirror = container_of(mn, struct dmirror, notifier); + +if (mmu_notifier_range_blockable (update)) +mutex_lock (&dmirror->mutex); +else if (!mutex_trylock (&dmirror->mutex))Quoted 8 lines
lib/test_hmm.c line 198
Quoted 6 lines
lib/test_hmm.c new file +6
-0+return -EAGAIN ; + +dmirror_do_update (dmirror, update->start, update->end); +mutex_unlock (&dmirror->mutex); +return 0 ; +}Can we adopts this to Jasons new interval tree invalidate?
Quoted 2 lines
Well, it would mean registering for the whole process address space. I'll give it a try.
I'm not sure it makes much sense that this testing is essentially modeled after nouveau's usage which is very strange compared to the other drivers.
Jason
Re: [PATCH v4 2/2] mm/hmm/test: add self tests for HMM
Quoted 6 lines · Jason Gunthorpe
Quoted 2 lines
Well, it would mean registering for the whole process address space. I'll give it a try.
I'm not sure it makes much sense that this testing is essentially modeled after nouveau's usage which is very strange compared to the other drivers.
Which means we really should make the test cases fit the proper usage. Maybe defer the tests for 5.5 and just merge the first patch for now?
Re: [PATCH v4 2/2] mm/hmm/test: add self tests for HMM
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Jason Gunthorpe
Quoted 2 lines
Well, it would mean registering for the whole process address space. I'll give it a try.
I'm not sure it makes much sense that this testing is essentially modeled after nouveau's usage which is very strange compared to the other drivers.
Which means we really should make the test cases fit the proper usage. Maybe defer the tests for 5.5 and just merge the first patch for now?
I think this a good point to discuss.
Some devices will want to register for all changes to the process address space because there is no requirement to preregister regions that the device can access verses devices like InfiniBand where a range of addresses have to be registered before the device can access those addresses. So for nouveau and the hmm-test driver, the mmu_range_notifier_insert() and mmu_range_notifier_remove() are only used long enough to get a stable copy of a small part of the process address space and copy it to the device's page table. Then the regular process wide invalidations are required to keep the device's page tables consistent with the process page table.
The "hacky" part of the current design is the interaction between the short term narrow address range invalidations verses the long term process wide invalidations. (double callbacks, double locking of the device page table)
Both types of invalidate callbacks seem useful to me so forcing a driver to use only one type doesn't make sense to me.
Re: [PATCH v4 2/2] mm/hmm/test: add self tests for HMM
Quoted 14 lines · Ralph Campbell
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Jason Gunthorpe
Quoted 2 lines
Well, it would mean registering for the whole process address space. I'll give it a try.
I'm not sure it makes much sense that this testing is essentially modeled after nouveau's usage which is very strange compared to the other drivers.
Which means we really should make the test cases fit the proper usage. Maybe defer the tests for 5.5 and just merge the first patch for now?
Quoted 5 lines
I think this a good point to discuss.
Some devices will want to register for all changes to the process address space because there is no requirement to preregister regions that the device can access verses devices like InfiniBand where a range of addresses have to be registered before the device can access those addresses.
But this is a very bad idea to register and do HW actions for ranges that can't possibly have any pages registered. It slows down the entire application
I think the ODP approach might be saner, when it mirrors the entire address space it chops it up into VA chunks, and once a page is registered on the HW the VA chunk goes into the interval tree.
Presumably the GPU also has some kind of page table tree and you could set one of the levels as the VA interval when there are populated children
Jason
Re: [PATCH v4 2/2] mm/hmm/test: add self tests for HMM
Quoted 25 lines · Jason Gunthorpe
Quoted 14 lines · Ralph Campbell
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Jason Gunthorpe
Quoted 2 lines
Well, it would mean registering for the whole process address space. I'll give it a try.
I'm not sure it makes much sense that this testing is essentially modeled after nouveau's usage which is very strange compared to the other drivers.
Which means we really should make the test cases fit the proper usage. Maybe defer the tests for 5.5 and just merge the first patch for now?
Quoted 5 lines
I think this a good point to discuss.
Some devices will want to register for all changes to the process address space because there is no requirement to preregister regions that the device can access verses devices like InfiniBand where a range of addresses have to be registered before the device can access those addresses.But this is a very bad idea to register and do HW actions for ranges that can't possibly have any pages registered. It slows down the entire application
Quoted 8 lines
I think the ODP approach might be saner, when it mirrors the entire address space it chops it up into VA chunks, and once a page is registered on the HW the VA chunk goes into the interval tree.
Presumably the GPU also has some kind of page table tree and you could set one of the levels as the VA interval when there are populated children
Jason
I wasn't suggesting that HW invalidates happen in two places. I'm suggesting the two styles of invalidates can work together. For example, what if a driver calls mmu_notifier_register(mn, mm) to register for address space wide invalidations, then some time later there is a device page table fault and the driver calls mmu_range_notifier_insert() but with a NULL ops.invalidate. The fault handler follows the nouveau/test_hmm pattern to call
mmu_range_read_begin()
hmm_range_fault()
device lock
mmu_range_read_retry()
update device page tables
device unlock
mmu_range_notifier_remove()
The global invalidate() callback would get the device lock and call into mm to update the sequence number of any affected ranges instead of having a range invalidate callback, and then do the HW invalidations.
Re: [PATCH v4 2/2] mm/hmm/test: add self tests for HMM
Quoted 34 lines · Ralph Campbell
Quoted 32 lines · Jason Gunthorpe
Quoted 14 lines · Ralph Campbell
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Jason Gunthorpe
Quoted 2 lines
Well, it would mean registering for the whole process address space. I'll give it a try.
I'm not sure it makes much sense that this testing is essentially modeled after nouveau's usage which is very strange compared to the other drivers.
Which means we really should make the test cases fit the proper usage. Maybe defer the tests for 5.5 and just merge the first patch for now?
Quoted 5 lines
I think this a good point to discuss.
Some devices will want to register for all changes to the process address space because there is no requirement to preregister regions that the device can access verses devices like InfiniBand where a range of addresses have to be registered before the device can access those addresses.But this is a very bad idea to register and do HW actions for ranges that can't possibly have any pages registered. It slows down the entire application
I think the ODP approach might be saner, when it mirrors the entire address space it chops it up into VA chunks, and once a page is registered on the HW the VA chunk goes into the interval tree.
Presumably the GPU also has some kind of page table tree and you could set one of the levels as the VA interval when there are populated children
Quoted 8 lines
Quoted 1 line
Jason
I wasn't suggesting that HW invalidates happen in two places. I'm suggesting the two styles of invalidates can work together. For example, what if a driver calls
mmu_notifier_register(mn, mm)to register for address space wide invalidations, then some time later there is a device page table fault and the driver callsmmu_range_notifier_insert()but with a NULL ops.invalidate.
I'm saying drivers shouldn't do that, it is a basically a hack that it works at all.
Quoted 4 lines
The global
invalidate()callback would get the device lock and call into mm to update the sequence number of any affected ranges instead of having a range invalidate callback, and then do the HW invalidations.
No, I just finished eliminating all the range iteration code in the drivers - and you can't update the sequence number from any place other than the interval invalidation callback anyhow.
Jason
Andrew Morton
maintainerRe: [PATCH v4 2/2] mm/hmm/test: add self tests for HMM
In reply to Ralph CampbellQuoted 9 lines · On Tue, 12 Nov 2019 13:51:11 -0800 Ralph Campbell <[email protected]> wrote:
Quoted 2 lines · Christoph Hellwig
Shouldn't this go into
mm/instead? It certainly doesn't seem like a library.I was following the convention for the other vm test kernel modules. I see a couple of modules in
mm/but I don't have a personal preference for where to place it.Andrew, do you have a preference?
q:/usr/src/25> ls -l lib/test_*.c|wc
33 297 2051
lib/ is a somewhat strange place, but I'd use that for now.
Presumably one day someone will (pointlessly) move these into lib/test-modules/.
Then into lib/test-modules/mm/, etc..