diff mbox series

[v2,7/9] userfaultfd: add UFFDIO_CONTINUE ioctl

Message ID 20210122212926.3457593-8-axelrasmussen@google.com (mailing list archive)
State New, archived
Headers show
Series userfaultfd: add minor fault handling | expand

Commit Message

Axel Rasmussen Jan. 22, 2021, 9:29 p.m. UTC
This ioctl is how userspace ought to resolve "minor" userfaults. The
idea is, userspace is notified that a minor fault has occurred. It might
change the contents of the page using its second non-UFFD mapping, or
not. Then, it calls UFFDIO_CONTINUE to tell the kernel "I have ensured
the page contents are correct, carry on setting up the mapping".

Note that it doesn't make much sense to use UFFDIO_{COPY,ZEROPAGE} for
MINOR registered VMAs. ZEROPAGE maps the VMA to the zero page; but in
the minor fault case, we already have some pre-existing underlying page.
Likewise, UFFDIO_COPY isn't useful if we have a second non-UFFD mapping.
We'd just use memcpy() or similar instead.

It turns out hugetlb_mcopy_atomic_pte() already does very close to what
we want, if an existing page is provided via `struct page **pagep`. We
already special-case the behavior a bit for the UFFDIO_ZEROPAGE case, so
just extend that design: add an enum for the three modes of operation,
and make the small adjustments needed for the MCOPY_ATOMIC_CONTINUE
case. (Basically, look up the existing page, and avoid adding the
existing page to the page cache or calling set_page_huge_active() on
it.)

Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
---
 fs/userfaultfd.c                 | 67 +++++++++++++++++++++++++++++++
 include/linux/hugetlb.h          |  1 +
 include/linux/userfaultfd_k.h    | 18 +++++++++
 include/uapi/linux/userfaultfd.h | 21 +++++++++-
 mm/hugetlb.c                     | 24 ++++++-----
 mm/userfaultfd.c                 | 69 +++++++++++++++++++++-----------
 6 files changed, 166 insertions(+), 34 deletions(-)

Comments

kernel test robot Jan. 25, 2021, 7:53 a.m. UTC | #1
Hi Axel,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on powerpc/next s390/features tip/perf/core linus/master v5.11-rc5 next-20210122]
[cannot apply to hp-parisc/for-next hnaz-linux-mm/master ia64/next sparc-next/master sparc/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Axel-Rasmussen/userfaultfd-add-minor-fault-handling/20210125-104035
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
config: powerpc-randconfig-r006-20210125 (attached as .config)
compiler: powerpc-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/b8fb53c3a341b9b853aa3286286c807088311dbd
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Axel-Rasmussen/userfaultfd-add-minor-fault-handling/20210125-104035
        git checkout b8fb53c3a341b9b853aa3286286c807088311dbd
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=powerpc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All error/warnings (new ones prefixed by >>):

   In file included from fs/proc/task_mmu.c:4:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
--
   In file included from fs/proc/meminfo.c:6:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
   fs/proc/meminfo.c:22:28: warning: no previous prototype for 'arch_report_meminfo' [-Wmissing-prototypes]
      22 | void __attribute__((weak)) arch_report_meminfo(struct seq_file *m)
         |                            ^~~~~~~~~~~~~~~~~~~
--
   In file included from kernel/events/core.c:31:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
   kernel/events/core.c:6535:6: warning: no previous prototype for 'perf_pmu_snapshot_aux' [-Wmissing-prototypes]
    6535 | long perf_pmu_snapshot_aux(struct perf_buffer *rb,
         |      ^~~~~~~~~~~~~~~~~~~~~
--
   In file included from kernel/fork.c:51:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
   kernel/fork.c:161:13: warning: no previous prototype for 'arch_release_task_struct' [-Wmissing-prototypes]
     161 | void __weak arch_release_task_struct(struct task_struct *tsk)
         |             ^~~~~~~~~~~~~~~~~~~~~~~~
   kernel/fork.c:746:20: warning: no previous prototype for 'arch_task_cache_init' [-Wmissing-prototypes]
     746 | void __init __weak arch_task_cache_init(void) { }
         |                    ^~~~~~~~~~~~~~~~~~~~
--
   In file included from arch/powerpc/mm/pgtable.c:25:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
   arch/powerpc/mm/pgtable.c:337:8: warning: no previous prototype for '__find_linux_pte' [-Wmissing-prototypes]
     337 | pte_t *__find_linux_pte(pgd_t *pgdir, unsigned long ea,
         |        ^~~~~~~~~~~~~~~~
--
   In file included from include/linux/migrate.h:8,
                    from mm/page_alloc.c:61:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
   mm/page_alloc.c:3597:15: warning: no previous prototype for 'should_fail_alloc_page' [-Wmissing-prototypes]
    3597 | noinline bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
         |               ^~~~~~~~~~~~~~~~~~~~~~
   mm/page_alloc.c:6258:23: warning: no previous prototype for 'memmap_init' [-Wmissing-prototypes]
    6258 | void __meminit __weak memmap_init(unsigned long size, int nid,
         |                       ^~~~~~~~~~~
--
   In file included from mm/hugetlb.c:39:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
>> mm/hugetlb.c:4659:13: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
    4659 |        enum mcopy_atomic_mode mode,
         |             ^~~~~~~~~~~~~~~~~
>> mm/hugetlb.c:4659:31: error: parameter 6 ('mode') has incomplete type
    4659 |        enum mcopy_atomic_mode mode,
         |        ~~~~~~~~~~~~~~~~~~~~~~~^~~~
   mm/hugetlb.c: In function 'hugetlb_mcopy_atomic_pte':
>> mm/hugetlb.c:4675:25: error: 'MCOPY_ATOMIC_CONTINUE' undeclared (first use in this function)
    4675 |  if (!*pagep && mode != MCOPY_ATOMIC_CONTINUE) {
         |                         ^~~~~~~~~~~~~~~~~~~~~
   mm/hugetlb.c:4675:25: note: each undeclared identifier is reported only once for each function it appears in
--
   In file included from mm/util.c:16:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
   mm/util.c: In function 'page_mapping':
   mm/util.c:700:15: warning: variable 'entry' set but not used [-Wunused-but-set-variable]
     700 |   swp_entry_t entry;
         |               ^~~~~
--
   In file included from include/linux/migrate.h:8,
                    from mm/compaction.c:13:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
   mm/compaction.c:56:27: warning: 'HPAGE_FRAG_CHECK_INTERVAL_MSEC' defined but not used [-Wunused-const-variable=]
      56 | static const unsigned int HPAGE_FRAG_CHECK_INTERVAL_MSEC = 500;
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
   In file included from include/linux/migrate.h:8,
                    from kernel/sched/sched.h:53,
                    from kernel/sched/fair.c:23:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
   kernel/sched/fair.c:5388:6: warning: no previous prototype for 'init_cfs_bandwidth' [-Wmissing-prototypes]
    5388 | void init_cfs_bandwidth(struct cfs_bandwidth *cfs_b) {}
         |      ^~~~~~~~~~~~~~~~~~
   kernel/sched/fair.c:11195:6: warning: no previous prototype for 'free_fair_sched_group' [-Wmissing-prototypes]
   11195 | void free_fair_sched_group(struct task_group *tg) { }
         |      ^~~~~~~~~~~~~~~~~~~~~
   kernel/sched/fair.c:11197:5: warning: no previous prototype for 'alloc_fair_sched_group' [-Wmissing-prototypes]
   11197 | int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
         |     ^~~~~~~~~~~~~~~~~~~~~~
   kernel/sched/fair.c:11202:6: warning: no previous prototype for 'online_fair_sched_group' [-Wmissing-prototypes]
   11202 | void online_fair_sched_group(struct task_group *tg) { }
         |      ^~~~~~~~~~~~~~~~~~~~~~~
   kernel/sched/fair.c:11204:6: warning: no previous prototype for 'unregister_fair_sched_group' [-Wmissing-prototypes]
   11204 | void unregister_fair_sched_group(struct task_group *tg) { }
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
--
   In file included from include/linux/migrate.h:8,
                    from kernel/sched/sched.h:53,
                    from kernel/sched/rt.c:6:
>> include/linux/hugetlb.h:142:10: warning: 'enum mcopy_atomic_mode' declared inside parameter list will not be visible outside of this definition or declaration
     142 |     enum mcopy_atomic_mode mode,
         |          ^~~~~~~~~~~~~~~~~
   kernel/sched/rt.c:253:6: warning: no previous prototype for 'free_rt_sched_group' [-Wmissing-prototypes]
     253 | void free_rt_sched_group(struct task_group *tg) { }
         |      ^~~~~~~~~~~~~~~~~~~
   kernel/sched/rt.c:255:5: warning: no previous prototype for 'alloc_rt_sched_group' [-Wmissing-prototypes]
     255 | int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
         |     ^~~~~~~~~~~~~~~~~~~~
   kernel/sched/rt.c:669:6: warning: no previous prototype for 'sched_rt_bandwidth_account' [-Wmissing-prototypes]
     669 | bool sched_rt_bandwidth_account(struct rt_rq *rt_rq)
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~~
..


vim +4659 mm/hugetlb.c

  4649	
  4650	/*
  4651	 * Used by userfaultfd UFFDIO_COPY.  Based on mcopy_atomic_pte with
  4652	 * modifications for huge pages.
  4653	 */
  4654	int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
  4655				    pte_t *dst_pte,
  4656				    struct vm_area_struct *dst_vma,
  4657				    unsigned long dst_addr,
  4658				    unsigned long src_addr,
> 4659				    enum mcopy_atomic_mode mode,
  4660				    struct page **pagep)
  4661	{
  4662		struct address_space *mapping;
  4663		pgoff_t idx;
  4664		unsigned long size;
  4665		int vm_shared = dst_vma->vm_flags & VM_SHARED;
  4666		struct hstate *h = hstate_vma(dst_vma);
  4667		pte_t _dst_pte;
  4668		spinlock_t *ptl;
  4669		int ret;
  4670		struct page *page;
  4671	
  4672		mapping = dst_vma->vm_file->f_mapping;
  4673		idx = vma_hugecache_offset(h, dst_vma, dst_addr);
  4674	
> 4675		if (!*pagep && mode != MCOPY_ATOMIC_CONTINUE) {
  4676			ret = -ENOMEM;
  4677			page = alloc_huge_page(dst_vma, dst_addr, 0);
  4678			if (IS_ERR(page))
  4679				goto out;
  4680	
  4681			ret = copy_huge_page_from_user(page,
  4682							(const void __user *) src_addr,
  4683							pages_per_huge_page(h), false);
  4684	
  4685			/* fallback to copy_from_user outside mmap_lock */
  4686			if (unlikely(ret)) {
  4687				ret = -ENOENT;
  4688				*pagep = page;
  4689				/* don't free the page */
  4690				goto out;
  4691			}
  4692		} else if (mode == MCOPY_ATOMIC_CONTINUE) {
  4693			ret = -EFAULT;
  4694			page = find_lock_page(mapping, idx);
  4695			*pagep = NULL;
  4696			if (!page)
  4697				goto out;
  4698		} else {
  4699			page = *pagep;
  4700			*pagep = NULL;
  4701		}
  4702	
  4703		/*
  4704		 * The memory barrier inside __SetPageUptodate makes sure that
  4705		 * preceding stores to the page contents become visible before
  4706		 * the set_pte_at() write.
  4707		 */
  4708		__SetPageUptodate(page);
  4709	
  4710		/* Add shared, newly allocated pages to the page cache. */
  4711		if (vm_shared && mode != MCOPY_ATOMIC_CONTINUE) {
  4712			size = i_size_read(mapping->host) >> huge_page_shift(h);
  4713			ret = -EFAULT;
  4714			if (idx >= size)
  4715				goto out_release_nounlock;
  4716	
  4717			/*
  4718			 * Serialization between remove_inode_hugepages() and
  4719			 * huge_add_to_page_cache() below happens through the
  4720			 * hugetlb_fault_mutex_table that here must be hold by
  4721			 * the caller.
  4722			 */
  4723			ret = huge_add_to_page_cache(page, mapping, idx);
  4724			if (ret)
  4725				goto out_release_nounlock;
  4726		}
  4727	
  4728		ptl = huge_pte_lockptr(h, dst_mm, dst_pte);
  4729		spin_lock(ptl);
  4730	
  4731		/*
  4732		 * Recheck the i_size after holding PT lock to make sure not
  4733		 * to leave any page mapped (as page_mapped()) beyond the end
  4734		 * of the i_size (remove_inode_hugepages() is strict about
  4735		 * enforcing that). If we bail out here, we'll also leave a
  4736		 * page in the radix tree in the vm_shared case beyond the end
  4737		 * of the i_size, but remove_inode_hugepages() will take care
  4738		 * of it as soon as we drop the hugetlb_fault_mutex_table.
  4739		 */
  4740		size = i_size_read(mapping->host) >> huge_page_shift(h);
  4741		ret = -EFAULT;
  4742		if (idx >= size)
  4743			goto out_release_unlock;
  4744	
  4745		ret = -EEXIST;
  4746		if (!huge_pte_none(huge_ptep_get(dst_pte)))
  4747			goto out_release_unlock;
  4748	
  4749		if (vm_shared) {
  4750			page_dup_rmap(page, true);
  4751		} else {
  4752			ClearPagePrivate(page);
  4753			hugepage_add_new_anon_rmap(page, dst_vma, dst_addr);
  4754		}
  4755	
  4756		_dst_pte = make_huge_pte(dst_vma, page, dst_vma->vm_flags & VM_WRITE);
  4757		if (dst_vma->vm_flags & VM_WRITE)
  4758			_dst_pte = huge_pte_mkdirty(_dst_pte);
  4759		_dst_pte = pte_mkyoung(_dst_pte);
  4760	
  4761		set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte);
  4762	
  4763		(void)huge_ptep_set_access_flags(dst_vma, dst_addr, dst_pte, _dst_pte,
  4764						dst_vma->vm_flags & VM_WRITE);
  4765		hugetlb_count_add(pages_per_huge_page(h), dst_mm);
  4766	
  4767		/* No need to invalidate - it was non-present before */
  4768		update_mmu_cache(dst_vma, dst_addr, dst_pte);
  4769	
  4770		spin_unlock(ptl);
  4771		if (mode != MCOPY_ATOMIC_CONTINUE)
  4772			set_page_huge_active(page);
  4773		if (vm_shared)
  4774			unlock_page(page);
  4775		ret = 0;
  4776	out:
  4777		return ret;
  4778	out_release_unlock:
  4779		spin_unlock(ptl);
  4780		if (vm_shared)
  4781			unlock_page(page);
  4782	out_release_nounlock:
  4783		put_page(page);
  4784		goto out;
  4785	}
  4786	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Jan. 25, 2021, 8:31 a.m. UTC | #2
Hi Axel,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on arm64/for-next/core]
[also build test WARNING on powerpc/next s390/features tip/perf/core linus/master v5.11-rc5 next-20210122]
[cannot apply to hp-parisc/for-next hnaz-linux-mm/master ia64/next sparc-next/master sparc/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Axel-Rasmussen/userfaultfd-add-minor-fault-handling/20210125-104035
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
config: x86_64-randconfig-a013-20210125 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 12d0753aca22896fda2cf76781b0ee0524d55065)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # https://github.com/0day-ci/linux/commit/b8fb53c3a341b9b853aa3286286c807088311dbd
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Axel-Rasmussen/userfaultfd-add-minor-fault-handling/20210125-104035
        git checkout b8fb53c3a341b9b853aa3286286c807088311dbd
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from kernel/sched/core.c:13:
   In file included from kernel/sched/sched.h:53:
   In file included from include/linux/migrate.h:8:
>> include/linux/hugetlb.h:142:10: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                                   enum mcopy_atomic_mode mode,
                                        ^
   kernel/sched/core.c:2884:20: warning: unused function 'rq_has_pinned_tasks' [-Wunused-function]
   static inline bool rq_has_pinned_tasks(struct rq *rq)
                      ^
   kernel/sched/core.c:4687:20: warning: unused function 'sched_tick_start' [-Wunused-function]
   static inline void sched_tick_start(int cpu) { }
                      ^
   kernel/sched/core.c:4688:20: warning: unused function 'sched_tick_stop' [-Wunused-function]
   static inline void sched_tick_stop(int cpu) { }
                      ^
   4 warnings generated.
--
   In file included from kernel/sched/loadavg.c:9:
   In file included from kernel/sched/sched.h:53:
   In file included from include/linux/migrate.h:8:
>> include/linux/hugetlb.h:142:10: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                                   enum mcopy_atomic_mode mode,
                                        ^
   1 warning generated.
--
   In file included from kernel/sched/fair.c:23:
   In file included from kernel/sched/sched.h:53:
   In file included from include/linux/migrate.h:8:
>> include/linux/hugetlb.h:142:10: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                                   enum mcopy_atomic_mode mode,
                                        ^
   kernel/sched/fair.c:5388:6: warning: no previous prototype for function 'init_cfs_bandwidth' [-Wmissing-prototypes]
   void init_cfs_bandwidth(struct cfs_bandwidth *cfs_b) {}
        ^
   kernel/sched/fair.c:5388:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void init_cfs_bandwidth(struct cfs_bandwidth *cfs_b) {}
   ^
   static 
   kernel/sched/fair.c:11195:6: warning: no previous prototype for function 'free_fair_sched_group' [-Wmissing-prototypes]
   void free_fair_sched_group(struct task_group *tg) { }
        ^
   kernel/sched/fair.c:11195:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void free_fair_sched_group(struct task_group *tg) { }
   ^
   static 
   kernel/sched/fair.c:11197:5: warning: no previous prototype for function 'alloc_fair_sched_group' [-Wmissing-prototypes]
   int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
       ^
   kernel/sched/fair.c:11197:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
   ^
   static 
   kernel/sched/fair.c:11202:6: warning: no previous prototype for function 'online_fair_sched_group' [-Wmissing-prototypes]
   void online_fair_sched_group(struct task_group *tg) { }
        ^
   kernel/sched/fair.c:11202:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void online_fair_sched_group(struct task_group *tg) { }
   ^
   static 
   kernel/sched/fair.c:11204:6: warning: no previous prototype for function 'unregister_fair_sched_group' [-Wmissing-prototypes]
   void unregister_fair_sched_group(struct task_group *tg) { }
        ^
   kernel/sched/fair.c:11204:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void unregister_fair_sched_group(struct task_group *tg) { }
   ^
   static 
   kernel/sched/fair.c:486:20: warning: unused function 'list_del_leaf_cfs_rq' [-Wunused-function]
   static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
                      ^
   kernel/sched/fair.c:2985:20: warning: unused function 'account_numa_enqueue' [-Wunused-function]
   static inline void account_numa_enqueue(struct rq *rq, struct task_struct *p)
                      ^
   kernel/sched/fair.c:2989:20: warning: unused function 'account_numa_dequeue' [-Wunused-function]
   static inline void account_numa_dequeue(struct rq *rq, struct task_struct *p)
                      ^
   kernel/sched/fair.c:2993:20: warning: unused function 'update_scan_period' [-Wunused-function]
   static inline void update_scan_period(struct task_struct *p, int new_cpu)
                      ^
   kernel/sched/fair.c:4083:20: warning: unused function 'remove_entity_load_avg' [-Wunused-function]
   static inline void remove_entity_load_avg(struct sched_entity *se) {}
                      ^
   kernel/sched/fair.c:5369:20: warning: unused function 'sync_throttle' [-Wunused-function]
   static inline void sync_throttle(struct task_group *tg, int cpu) {}
                      ^
   kernel/sched/fair.c:5382:19: warning: unused function 'throttled_lb_pair' [-Wunused-function]
   static inline int throttled_lb_pair(struct task_group *tg,
                     ^
   kernel/sched/fair.c:5394:37: warning: unused function 'tg_cfs_bandwidth' [-Wunused-function]
   static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
                                       ^
   kernel/sched/fair.c:5398:20: warning: unused function 'destroy_cfs_bandwidth' [-Wunused-function]
   static inline void destroy_cfs_bandwidth(struct cfs_bandwidth *cfs_b) {}
                      ^
   kernel/sched/fair.c:5399:20: warning: unused function 'update_runtime_enabled' [-Wunused-function]
   static inline void update_runtime_enabled(struct rq *rq) {}
                      ^
   kernel/sched/fair.c:5400:20: warning: unused function 'unthrottle_offline_cfs_rqs' [-Wunused-function]
   static inline void unthrottle_offline_cfs_rqs(struct rq *rq) {}
                      ^
   17 warnings generated.
--
   In file included from kernel/sched/rt.c:6:
   In file included from kernel/sched/sched.h:53:
   In file included from include/linux/migrate.h:8:
>> include/linux/hugetlb.h:142:10: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                                   enum mcopy_atomic_mode mode,
                                        ^
   kernel/sched/rt.c:253:6: warning: no previous prototype for function 'free_rt_sched_group' [-Wmissing-prototypes]
   void free_rt_sched_group(struct task_group *tg) { }
        ^
   kernel/sched/rt.c:253:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void free_rt_sched_group(struct task_group *tg) { }
   ^
   static 
   kernel/sched/rt.c:255:5: warning: no previous prototype for function 'alloc_rt_sched_group' [-Wmissing-prototypes]
   int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
       ^
   kernel/sched/rt.c:255:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
   ^
   static 
   kernel/sched/rt.c:669:6: warning: no previous prototype for function 'sched_rt_bandwidth_account' [-Wmissing-prototypes]
   bool sched_rt_bandwidth_account(struct rt_rq *rt_rq)
        ^
   kernel/sched/rt.c:669:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   bool sched_rt_bandwidth_account(struct rt_rq *rt_rq)
   ^
   static 
   kernel/sched/rt.c:421:20: warning: unused function 'need_pull_rt_task' [-Wunused-function]
   static inline bool need_pull_rt_task(struct rq *rq, struct task_struct *prev)
                      ^
   kernel/sched/rt.c:426:20: warning: unused function 'pull_rt_task' [-Wunused-function]
   static inline void pull_rt_task(struct rq *this_rq)
                      ^
   kernel/sched/rt.c:476:20: warning: unused function 'rt_task_fits_capacity' [-Wunused-function]
   static inline bool rt_task_fits_capacity(struct task_struct *p, int cpu)
                      ^
   kernel/sched/rt.c:1113:6: warning: unused function 'inc_rt_prio_smp' [-Wunused-function]
   void inc_rt_prio_smp(struct rt_rq *rt_rq, int prio, int prev_prio) {}
        ^
   kernel/sched/rt.c:1115:6: warning: unused function 'dec_rt_prio_smp' [-Wunused-function]
   void dec_rt_prio_smp(struct rt_rq *rt_rq, int prio, int prev_prio) {}
        ^
   9 warnings generated.
--
   In file included from kernel/sched/deadline.c:18:
   In file included from kernel/sched/sched.h:53:
   In file included from include/linux/migrate.h:8:
>> include/linux/hugetlb.h:142:10: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                                   enum mcopy_atomic_mode mode,
                                        ^
   kernel/sched/deadline.c:700:20: warning: unused function 'need_pull_dl_task' [-Wunused-function]
   static inline bool need_pull_dl_task(struct rq *rq, struct task_struct *prev)
                      ^
   kernel/sched/deadline.c:705:20: warning: unused function 'pull_dl_task' [-Wunused-function]
   static inline void pull_dl_task(struct rq *rq)
                      ^
   3 warnings generated.
--
   In file included from mm/page_alloc.c:61:
   In file included from include/linux/migrate.h:8:
>> include/linux/hugetlb.h:142:10: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                                   enum mcopy_atomic_mode mode,
                                        ^
   mm/page_alloc.c:3597:15: warning: no previous prototype for function 'should_fail_alloc_page' [-Wmissing-prototypes]
   noinline bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
                 ^
   mm/page_alloc.c:3597:10: note: declare 'static' if the function is not intended to be used outside of this translation unit
   noinline bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
            ^
            static 
   mm/page_alloc.c:6258:23: warning: no previous prototype for function 'memmap_init' [-Wmissing-prototypes]
   void __meminit __weak memmap_init(unsigned long size, int nid,
                         ^
   mm/page_alloc.c:6258:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void __meminit __weak memmap_init(unsigned long size, int nid,
   ^
   static 
   3 warnings generated.
--
   In file included from mm/hugetlb.c:39:
>> include/linux/hugetlb.h:142:10: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                                   enum mcopy_atomic_mode mode,
                                        ^
>> mm/hugetlb.c:4659:13: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                               enum mcopy_atomic_mode mode,
                                    ^
   mm/hugetlb.c:4654:5: error: conflicting types for 'hugetlb_mcopy_atomic_pte'
   int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
       ^
   include/linux/hugetlb.h:138:5: note: previous declaration is here
   int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm, pte_t *dst_pte,
       ^
   mm/hugetlb.c:4659:31: error: variable has incomplete type 'enum mcopy_atomic_mode'
                               enum mcopy_atomic_mode mode,
                                                      ^
   mm/hugetlb.c:4659:13: note: forward declaration of 'enum mcopy_atomic_mode'
                               enum mcopy_atomic_mode mode,
                                    ^
   mm/hugetlb.c:4675:25: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
           if (!*pagep && mode != MCOPY_ATOMIC_CONTINUE) {
                                  ^
   mm/hugetlb.c:4692:21: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
           } else if (mode == MCOPY_ATOMIC_CONTINUE) {
                              ^
   mm/hugetlb.c:4711:27: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
           if (vm_shared && mode != MCOPY_ATOMIC_CONTINUE) {
                                    ^
   mm/hugetlb.c:4771:14: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
           if (mode != MCOPY_ATOMIC_CONTINUE)
                       ^
   2 warnings and 6 errors generated.
--
   In file included from mm/z3fold.c:33:
   In file included from include/linux/migrate.h:8:
>> include/linux/hugetlb.h:142:10: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                                   enum mcopy_atomic_mode mode,
                                        ^
   mm/z3fold.c:287:37: warning: unused function 'handle_to_z3fold_header' [-Wunused-function]
   static inline struct z3fold_header *handle_to_z3fold_header(unsigned long h)
                                       ^
   2 warnings generated.


vim +142 include/linux/hugetlb.h

   108	
   109	void reset_vma_resv_huge_pages(struct vm_area_struct *vma);
   110	int hugetlb_sysctl_handler(struct ctl_table *, int, void *, size_t *, loff_t *);
   111	int hugetlb_overcommit_handler(struct ctl_table *, int, void *, size_t *,
   112			loff_t *);
   113	int hugetlb_treat_movable_handler(struct ctl_table *, int, void *, size_t *,
   114			loff_t *);
   115	int hugetlb_mempolicy_sysctl_handler(struct ctl_table *, int, void *, size_t *,
   116			loff_t *);
   117	
   118	int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *);
   119	long follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *,
   120				 struct page **, struct vm_area_struct **,
   121				 unsigned long *, unsigned long *, long, unsigned int,
   122				 int *);
   123	void unmap_hugepage_range(struct vm_area_struct *,
   124				  unsigned long, unsigned long, struct page *);
   125	void __unmap_hugepage_range_final(struct mmu_gather *tlb,
   126				  struct vm_area_struct *vma,
   127				  unsigned long start, unsigned long end,
   128				  struct page *ref_page);
   129	void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
   130					unsigned long start, unsigned long end,
   131					struct page *ref_page);
   132	void hugetlb_report_meminfo(struct seq_file *);
   133	int hugetlb_report_node_meminfo(char *buf, int len, int nid);
   134	void hugetlb_show_meminfo(void);
   135	unsigned long hugetlb_total_pages(void);
   136	vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
   137				unsigned long address, unsigned int flags);
   138	int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm, pte_t *dst_pte,
   139					struct vm_area_struct *dst_vma,
   140					unsigned long dst_addr,
   141					unsigned long src_addr,
 > 142					enum mcopy_atomic_mode mode,
   143					struct page **pagep);
   144	int hugetlb_reserve_pages(struct inode *inode, long from, long to,
   145							struct vm_area_struct *vma,
   146							vm_flags_t vm_flags);
   147	long hugetlb_unreserve_pages(struct inode *inode, long start, long end,
   148							long freed);
   149	bool isolate_huge_page(struct page *page, struct list_head *list);
   150	void putback_active_hugepage(struct page *page);
   151	void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason);
   152	void free_huge_page(struct page *page);
   153	void hugetlb_fix_reserve_counts(struct inode *inode);
   154	extern struct mutex *hugetlb_fault_mutex_table;
   155	u32 hugetlb_fault_mutex_hash(struct address_space *mapping, pgoff_t idx);
   156	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Jan. 25, 2021, 1:37 p.m. UTC | #3
Hi Axel,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on powerpc/next s390/features tip/perf/core linus/master v5.11-rc5 next-20210122]
[cannot apply to hp-parisc/for-next hnaz-linux-mm/master ia64/next sparc-next/master sparc/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Axel-Rasmussen/userfaultfd-add-minor-fault-handling/20210125-104035
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
config: x86_64-randconfig-a013-20210125 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 12d0753aca22896fda2cf76781b0ee0524d55065)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # https://github.com/0day-ci/linux/commit/b8fb53c3a341b9b853aa3286286c807088311dbd
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Axel-Rasmussen/userfaultfd-add-minor-fault-handling/20210125-104035
        git checkout b8fb53c3a341b9b853aa3286286c807088311dbd
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from mm/hugetlb.c:39:
   include/linux/hugetlb.h:142:10: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                                   enum mcopy_atomic_mode mode,
                                        ^
   mm/hugetlb.c:4659:13: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
                               enum mcopy_atomic_mode mode,
                                    ^
>> mm/hugetlb.c:4654:5: error: conflicting types for 'hugetlb_mcopy_atomic_pte'
   int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
       ^
   include/linux/hugetlb.h:138:5: note: previous declaration is here
   int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm, pte_t *dst_pte,
       ^
>> mm/hugetlb.c:4659:31: error: variable has incomplete type 'enum mcopy_atomic_mode'
                               enum mcopy_atomic_mode mode,
                                                      ^
   mm/hugetlb.c:4659:13: note: forward declaration of 'enum mcopy_atomic_mode'
                               enum mcopy_atomic_mode mode,
                                    ^
>> mm/hugetlb.c:4675:25: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
           if (!*pagep && mode != MCOPY_ATOMIC_CONTINUE) {
                                  ^
   mm/hugetlb.c:4692:21: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
           } else if (mode == MCOPY_ATOMIC_CONTINUE) {
                              ^
   mm/hugetlb.c:4711:27: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
           if (vm_shared && mode != MCOPY_ATOMIC_CONTINUE) {
                                    ^
   mm/hugetlb.c:4771:14: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
           if (mode != MCOPY_ATOMIC_CONTINUE)
                       ^
   2 warnings and 6 errors generated.


vim +/hugetlb_mcopy_atomic_pte +4654 mm/hugetlb.c

86e5216f8d8aa25 Adam Litke        2006-01-06  4649  
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4650  /*
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4651   * Used by userfaultfd UFFDIO_COPY.  Based on mcopy_atomic_pte with
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4652   * modifications for huge pages.
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4653   */
8fb5debc5fcd450 Mike Kravetz      2017-02-22 @4654  int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4655  			    pte_t *dst_pte,
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4656  			    struct vm_area_struct *dst_vma,
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4657  			    unsigned long dst_addr,
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4658  			    unsigned long src_addr,
b8fb53c3a341b9b Axel Rasmussen    2021-01-22 @4659  			    enum mcopy_atomic_mode mode,
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4660  			    struct page **pagep)
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4661  {
1e3921471354244 Andrea Arcangeli  2017-11-02  4662  	struct address_space *mapping;
1e3921471354244 Andrea Arcangeli  2017-11-02  4663  	pgoff_t idx;
1e3921471354244 Andrea Arcangeli  2017-11-02  4664  	unsigned long size;
1c9e8def43a3452 Mike Kravetz      2017-02-22  4665  	int vm_shared = dst_vma->vm_flags & VM_SHARED;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4666  	struct hstate *h = hstate_vma(dst_vma);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4667  	pte_t _dst_pte;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4668  	spinlock_t *ptl;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4669  	int ret;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4670  	struct page *page;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4671  
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4672  	mapping = dst_vma->vm_file->f_mapping;
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4673  	idx = vma_hugecache_offset(h, dst_vma, dst_addr);
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4674  
b8fb53c3a341b9b Axel Rasmussen    2021-01-22 @4675  	if (!*pagep && mode != MCOPY_ATOMIC_CONTINUE) {
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4676  		ret = -ENOMEM;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4677  		page = alloc_huge_page(dst_vma, dst_addr, 0);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4678  		if (IS_ERR(page))
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4679  			goto out;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4680  
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4681  		ret = copy_huge_page_from_user(page,
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4682  						(const void __user *) src_addr,
810a56b943e265b Mike Kravetz      2017-02-22  4683  						pages_per_huge_page(h), false);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4684  
c1e8d7c6a7a682e Michel Lespinasse 2020-06-08  4685  		/* fallback to copy_from_user outside mmap_lock */
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4686  		if (unlikely(ret)) {
9e368259ad98835 Andrea Arcangeli  2018-11-30  4687  			ret = -ENOENT;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4688  			*pagep = page;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4689  			/* don't free the page */
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4690  			goto out;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4691  		}
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4692  	} else if (mode == MCOPY_ATOMIC_CONTINUE) {
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4693  		ret = -EFAULT;
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4694  		page = find_lock_page(mapping, idx);
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4695  		*pagep = NULL;
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4696  		if (!page)
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4697  			goto out;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4698  	} else {
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4699  		page = *pagep;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4700  		*pagep = NULL;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4701  	}
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4702  
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4703  	/*
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4704  	 * The memory barrier inside __SetPageUptodate makes sure that
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4705  	 * preceding stores to the page contents become visible before
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4706  	 * the set_pte_at() write.
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4707  	 */
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4708  	__SetPageUptodate(page);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4709  
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4710  	/* Add shared, newly allocated pages to the page cache. */
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4711  	if (vm_shared && mode != MCOPY_ATOMIC_CONTINUE) {
1e3921471354244 Andrea Arcangeli  2017-11-02  4712  		size = i_size_read(mapping->host) >> huge_page_shift(h);
1e3921471354244 Andrea Arcangeli  2017-11-02  4713  		ret = -EFAULT;
1e3921471354244 Andrea Arcangeli  2017-11-02  4714  		if (idx >= size)
1e3921471354244 Andrea Arcangeli  2017-11-02  4715  			goto out_release_nounlock;
1c9e8def43a3452 Mike Kravetz      2017-02-22  4716  
1e3921471354244 Andrea Arcangeli  2017-11-02  4717  		/*
1e3921471354244 Andrea Arcangeli  2017-11-02  4718  		 * Serialization between remove_inode_hugepages() and
1e3921471354244 Andrea Arcangeli  2017-11-02  4719  		 * huge_add_to_page_cache() below happens through the
1e3921471354244 Andrea Arcangeli  2017-11-02  4720  		 * hugetlb_fault_mutex_table that here must be hold by
1e3921471354244 Andrea Arcangeli  2017-11-02  4721  		 * the caller.
1e3921471354244 Andrea Arcangeli  2017-11-02  4722  		 */
1c9e8def43a3452 Mike Kravetz      2017-02-22  4723  		ret = huge_add_to_page_cache(page, mapping, idx);
1c9e8def43a3452 Mike Kravetz      2017-02-22  4724  		if (ret)
1c9e8def43a3452 Mike Kravetz      2017-02-22  4725  			goto out_release_nounlock;
1c9e8def43a3452 Mike Kravetz      2017-02-22  4726  	}
1c9e8def43a3452 Mike Kravetz      2017-02-22  4727  
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4728  	ptl = huge_pte_lockptr(h, dst_mm, dst_pte);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4729  	spin_lock(ptl);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4730  
1e3921471354244 Andrea Arcangeli  2017-11-02  4731  	/*
1e3921471354244 Andrea Arcangeli  2017-11-02  4732  	 * Recheck the i_size after holding PT lock to make sure not
1e3921471354244 Andrea Arcangeli  2017-11-02  4733  	 * to leave any page mapped (as page_mapped()) beyond the end
1e3921471354244 Andrea Arcangeli  2017-11-02  4734  	 * of the i_size (remove_inode_hugepages() is strict about
1e3921471354244 Andrea Arcangeli  2017-11-02  4735  	 * enforcing that). If we bail out here, we'll also leave a
1e3921471354244 Andrea Arcangeli  2017-11-02  4736  	 * page in the radix tree in the vm_shared case beyond the end
1e3921471354244 Andrea Arcangeli  2017-11-02  4737  	 * of the i_size, but remove_inode_hugepages() will take care
1e3921471354244 Andrea Arcangeli  2017-11-02  4738  	 * of it as soon as we drop the hugetlb_fault_mutex_table.
1e3921471354244 Andrea Arcangeli  2017-11-02  4739  	 */
1e3921471354244 Andrea Arcangeli  2017-11-02  4740  	size = i_size_read(mapping->host) >> huge_page_shift(h);
1e3921471354244 Andrea Arcangeli  2017-11-02  4741  	ret = -EFAULT;
1e3921471354244 Andrea Arcangeli  2017-11-02  4742  	if (idx >= size)
1e3921471354244 Andrea Arcangeli  2017-11-02  4743  		goto out_release_unlock;
1e3921471354244 Andrea Arcangeli  2017-11-02  4744  
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4745  	ret = -EEXIST;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4746  	if (!huge_pte_none(huge_ptep_get(dst_pte)))
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4747  		goto out_release_unlock;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4748  
1c9e8def43a3452 Mike Kravetz      2017-02-22  4749  	if (vm_shared) {
1c9e8def43a3452 Mike Kravetz      2017-02-22  4750  		page_dup_rmap(page, true);
1c9e8def43a3452 Mike Kravetz      2017-02-22  4751  	} else {
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4752  		ClearPagePrivate(page);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4753  		hugepage_add_new_anon_rmap(page, dst_vma, dst_addr);
1c9e8def43a3452 Mike Kravetz      2017-02-22  4754  	}
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4755  
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4756  	_dst_pte = make_huge_pte(dst_vma, page, dst_vma->vm_flags & VM_WRITE);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4757  	if (dst_vma->vm_flags & VM_WRITE)
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4758  		_dst_pte = huge_pte_mkdirty(_dst_pte);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4759  	_dst_pte = pte_mkyoung(_dst_pte);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4760  
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4761  	set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4762  
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4763  	(void)huge_ptep_set_access_flags(dst_vma, dst_addr, dst_pte, _dst_pte,
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4764  					dst_vma->vm_flags & VM_WRITE);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4765  	hugetlb_count_add(pages_per_huge_page(h), dst_mm);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4766  
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4767  	/* No need to invalidate - it was non-present before */
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4768  	update_mmu_cache(dst_vma, dst_addr, dst_pte);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4769  
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4770  	spin_unlock(ptl);
b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4771  	if (mode != MCOPY_ATOMIC_CONTINUE)
cb6acd01e2e43fd Mike Kravetz      2019-02-28  4772  		set_page_huge_active(page);
1c9e8def43a3452 Mike Kravetz      2017-02-22  4773  	if (vm_shared)
1c9e8def43a3452 Mike Kravetz      2017-02-22  4774  		unlock_page(page);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4775  	ret = 0;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4776  out:
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4777  	return ret;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4778  out_release_unlock:
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4779  	spin_unlock(ptl);
1c9e8def43a3452 Mike Kravetz      2017-02-22  4780  	if (vm_shared)
1c9e8def43a3452 Mike Kravetz      2017-02-22  4781  		unlock_page(page);
5af10dfd0afc559 Andrea Arcangeli  2017-08-10  4782  out_release_nounlock:
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4783  	put_page(page);
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4784  	goto out;
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4785  }
8fb5debc5fcd450 Mike Kravetz      2017-02-22  4786  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Axel Rasmussen Jan. 25, 2021, 5:50 p.m. UTC | #4
This build error seems to be caused by a missing #ifdef
CONFIG_USERFAULTFD. I'll send a v3 with this fix, after waiting for
other feedback on the v2 version.

On Mon, Jan 25, 2021 at 5:37 AM kernel test robot <lkp@intel.com> wrote:
>
> Hi Axel,
>
> Thank you for the patch! Yet something to improve:
>
> [auto build test ERROR on arm64/for-next/core]
> [also build test ERROR on powerpc/next s390/features tip/perf/core linus/master v5.11-rc5 next-20210122]
> [cannot apply to hp-parisc/for-next hnaz-linux-mm/master ia64/next sparc-next/master sparc/master]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
>
> url:    https://github.com/0day-ci/linux/commits/Axel-Rasmussen/userfaultfd-add-minor-fault-handling/20210125-104035
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
> config: x86_64-randconfig-a013-20210125 (attached as .config)
> compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 12d0753aca22896fda2cf76781b0ee0524d55065)
> reproduce (this is a W=1 build):
>         wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # install x86_64 cross compiling tool for clang build
>         # apt-get install binutils-x86-64-linux-gnu
>         # https://github.com/0day-ci/linux/commit/b8fb53c3a341b9b853aa3286286c807088311dbd
>         git remote add linux-review https://github.com/0day-ci/linux
>         git fetch --no-tags linux-review Axel-Rasmussen/userfaultfd-add-minor-fault-handling/20210125-104035
>         git checkout b8fb53c3a341b9b853aa3286286c807088311dbd
>         # save the attached .config to linux build tree
>         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64
>
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
>
> All errors (new ones prefixed by >>):
>
>    In file included from mm/hugetlb.c:39:
>    include/linux/hugetlb.h:142:10: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
>                                    enum mcopy_atomic_mode mode,
>                                         ^
>    mm/hugetlb.c:4659:13: warning: declaration of 'enum mcopy_atomic_mode' will not be visible outside of this function [-Wvisibility]
>                                enum mcopy_atomic_mode mode,
>                                     ^
> >> mm/hugetlb.c:4654:5: error: conflicting types for 'hugetlb_mcopy_atomic_pte'
>    int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
>        ^
>    include/linux/hugetlb.h:138:5: note: previous declaration is here
>    int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm, pte_t *dst_pte,
>        ^
> >> mm/hugetlb.c:4659:31: error: variable has incomplete type 'enum mcopy_atomic_mode'
>                                enum mcopy_atomic_mode mode,
>                                                       ^
>    mm/hugetlb.c:4659:13: note: forward declaration of 'enum mcopy_atomic_mode'
>                                enum mcopy_atomic_mode mode,
>                                     ^
> >> mm/hugetlb.c:4675:25: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
>            if (!*pagep && mode != MCOPY_ATOMIC_CONTINUE) {
>                                   ^
>    mm/hugetlb.c:4692:21: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
>            } else if (mode == MCOPY_ATOMIC_CONTINUE) {
>                               ^
>    mm/hugetlb.c:4711:27: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
>            if (vm_shared && mode != MCOPY_ATOMIC_CONTINUE) {
>                                     ^
>    mm/hugetlb.c:4771:14: error: use of undeclared identifier 'MCOPY_ATOMIC_CONTINUE'
>            if (mode != MCOPY_ATOMIC_CONTINUE)
>                        ^
>    2 warnings and 6 errors generated.
>
>
> vim +/hugetlb_mcopy_atomic_pte +4654 mm/hugetlb.c
>
> 86e5216f8d8aa25 Adam Litke        2006-01-06  4649
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4650  /*
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4651   * Used by userfaultfd UFFDIO_COPY.  Based on mcopy_atomic_pte with
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4652   * modifications for huge pages.
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4653   */
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22 @4654  int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4655                          pte_t *dst_pte,
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4656                          struct vm_area_struct *dst_vma,
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4657                          unsigned long dst_addr,
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4658                          unsigned long src_addr,
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22 @4659                          enum mcopy_atomic_mode mode,
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4660                          struct page **pagep)
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4661  {
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4662      struct address_space *mapping;
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4663      pgoff_t idx;
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4664      unsigned long size;
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4665      int vm_shared = dst_vma->vm_flags & VM_SHARED;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4666      struct hstate *h = hstate_vma(dst_vma);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4667      pte_t _dst_pte;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4668      spinlock_t *ptl;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4669      int ret;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4670      struct page *page;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4671
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4672      mapping = dst_vma->vm_file->f_mapping;
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4673      idx = vma_hugecache_offset(h, dst_vma, dst_addr);
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4674
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22 @4675      if (!*pagep && mode != MCOPY_ATOMIC_CONTINUE) {
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4676              ret = -ENOMEM;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4677              page = alloc_huge_page(dst_vma, dst_addr, 0);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4678              if (IS_ERR(page))
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4679                      goto out;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4680
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4681              ret = copy_huge_page_from_user(page,
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4682                                              (const void __user *) src_addr,
> 810a56b943e265b Mike Kravetz      2017-02-22  4683                                              pages_per_huge_page(h), false);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4684
> c1e8d7c6a7a682e Michel Lespinasse 2020-06-08  4685              /* fallback to copy_from_user outside mmap_lock */
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4686              if (unlikely(ret)) {
> 9e368259ad98835 Andrea Arcangeli  2018-11-30  4687                      ret = -ENOENT;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4688                      *pagep = page;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4689                      /* don't free the page */
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4690                      goto out;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4691              }
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4692      } else if (mode == MCOPY_ATOMIC_CONTINUE) {
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4693              ret = -EFAULT;
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4694              page = find_lock_page(mapping, idx);
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4695              *pagep = NULL;
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4696              if (!page)
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4697                      goto out;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4698      } else {
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4699              page = *pagep;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4700              *pagep = NULL;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4701      }
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4702
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4703      /*
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4704       * The memory barrier inside __SetPageUptodate makes sure that
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4705       * preceding stores to the page contents become visible before
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4706       * the set_pte_at() write.
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4707       */
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4708      __SetPageUptodate(page);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4709
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4710      /* Add shared, newly allocated pages to the page cache. */
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4711      if (vm_shared && mode != MCOPY_ATOMIC_CONTINUE) {
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4712              size = i_size_read(mapping->host) >> huge_page_shift(h);
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4713              ret = -EFAULT;
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4714              if (idx >= size)
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4715                      goto out_release_nounlock;
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4716
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4717              /*
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4718               * Serialization between remove_inode_hugepages() and
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4719               * huge_add_to_page_cache() below happens through the
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4720               * hugetlb_fault_mutex_table that here must be hold by
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4721               * the caller.
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4722               */
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4723              ret = huge_add_to_page_cache(page, mapping, idx);
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4724              if (ret)
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4725                      goto out_release_nounlock;
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4726      }
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4727
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4728      ptl = huge_pte_lockptr(h, dst_mm, dst_pte);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4729      spin_lock(ptl);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4730
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4731      /*
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4732       * Recheck the i_size after holding PT lock to make sure not
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4733       * to leave any page mapped (as page_mapped()) beyond the end
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4734       * of the i_size (remove_inode_hugepages() is strict about
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4735       * enforcing that). If we bail out here, we'll also leave a
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4736       * page in the radix tree in the vm_shared case beyond the end
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4737       * of the i_size, but remove_inode_hugepages() will take care
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4738       * of it as soon as we drop the hugetlb_fault_mutex_table.
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4739       */
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4740      size = i_size_read(mapping->host) >> huge_page_shift(h);
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4741      ret = -EFAULT;
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4742      if (idx >= size)
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4743              goto out_release_unlock;
> 1e3921471354244 Andrea Arcangeli  2017-11-02  4744
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4745      ret = -EEXIST;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4746      if (!huge_pte_none(huge_ptep_get(dst_pte)))
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4747              goto out_release_unlock;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4748
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4749      if (vm_shared) {
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4750              page_dup_rmap(page, true);
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4751      } else {
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4752              ClearPagePrivate(page);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4753              hugepage_add_new_anon_rmap(page, dst_vma, dst_addr);
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4754      }
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4755
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4756      _dst_pte = make_huge_pte(dst_vma, page, dst_vma->vm_flags & VM_WRITE);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4757      if (dst_vma->vm_flags & VM_WRITE)
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4758              _dst_pte = huge_pte_mkdirty(_dst_pte);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4759      _dst_pte = pte_mkyoung(_dst_pte);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4760
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4761      set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4762
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4763      (void)huge_ptep_set_access_flags(dst_vma, dst_addr, dst_pte, _dst_pte,
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4764                                      dst_vma->vm_flags & VM_WRITE);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4765      hugetlb_count_add(pages_per_huge_page(h), dst_mm);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4766
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4767      /* No need to invalidate - it was non-present before */
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4768      update_mmu_cache(dst_vma, dst_addr, dst_pte);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4769
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4770      spin_unlock(ptl);
> b8fb53c3a341b9b Axel Rasmussen    2021-01-22  4771      if (mode != MCOPY_ATOMIC_CONTINUE)
> cb6acd01e2e43fd Mike Kravetz      2019-02-28  4772              set_page_huge_active(page);
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4773      if (vm_shared)
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4774              unlock_page(page);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4775      ret = 0;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4776  out:
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4777      return ret;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4778  out_release_unlock:
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4779      spin_unlock(ptl);
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4780      if (vm_shared)
> 1c9e8def43a3452 Mike Kravetz      2017-02-22  4781              unlock_page(page);
> 5af10dfd0afc559 Andrea Arcangeli  2017-08-10  4782  out_release_nounlock:
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4783      put_page(page);
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4784      goto out;
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4785  }
> 8fb5debc5fcd450 Mike Kravetz      2017-02-22  4786
>
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 968aca3e3ee9..80a3fca389b8 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -1530,6 +1530,10 @@  static int userfaultfd_register(struct userfaultfd_ctx *ctx,
 		if (!(uffdio_register.mode & UFFDIO_REGISTER_MODE_WP))
 			ioctls_out &= ~((__u64)1 << _UFFDIO_WRITEPROTECT);
 
+		/* CONTINUE ioctl is only supported for MINOR ranges. */
+		if (!(uffdio_register.mode & UFFDIO_REGISTER_MODE_MINOR))
+			ioctls_out &= ~((__u64)1 << _UFFDIO_CONTINUE);
+
 		/*
 		 * Now that we scanned all vmas we can already tell
 		 * userland which ioctls methods are guaranteed to
@@ -1883,6 +1887,66 @@  static int userfaultfd_writeprotect(struct userfaultfd_ctx *ctx,
 	return ret;
 }
 
+static int userfaultfd_continue(struct userfaultfd_ctx *ctx, unsigned long arg)
+{
+	__s64 ret;
+	struct uffdio_continue uffdio_continue;
+	struct uffdio_continue __user *user_uffdio_continue;
+	struct userfaultfd_wake_range range;
+
+	user_uffdio_continue = (struct uffdio_continue __user *)arg;
+
+	ret = -EAGAIN;
+	if (READ_ONCE(ctx->mmap_changing))
+		goto out;
+
+	ret = -EFAULT;
+	if (copy_from_user(&uffdio_continue, user_uffdio_continue,
+			   /* don't copy the output fields */
+			   sizeof(uffdio_continue) - (sizeof(__s64))))
+		goto out;
+
+	ret = validate_range(ctx->mm, &uffdio_continue.range.start,
+			     uffdio_continue.range.len);
+	if (ret)
+		goto out;
+
+	ret = -EINVAL;
+	/* double check for wraparound just in case. */
+	if (uffdio_continue.range.start + uffdio_continue.range.len <=
+	    uffdio_continue.range.start) {
+		goto out;
+	}
+	if (uffdio_continue.mode & ~UFFDIO_CONTINUE_MODE_DONTWAKE)
+		goto out;
+
+	if (mmget_not_zero(ctx->mm)) {
+		ret = mcopy_continue(ctx->mm, uffdio_continue.range.start,
+				     uffdio_continue.range.len,
+				     &ctx->mmap_changing);
+		mmput(ctx->mm);
+	} else {
+		return -ESRCH;
+	}
+
+	if (unlikely(put_user(ret, &user_uffdio_continue->mapped)))
+		return -EFAULT;
+	if (ret < 0)
+		goto out;
+
+	/* len == 0 would wake all */
+	BUG_ON(!ret);
+	range.len = ret;
+	if (!(uffdio_continue.mode & UFFDIO_CONTINUE_MODE_DONTWAKE)) {
+		range.start = uffdio_continue.range.start;
+		wake_userfault(ctx, &range);
+	}
+	ret = range.len == uffdio_continue.range.len ? 0 : -EAGAIN;
+
+out:
+	return ret;
+}
+
 static inline unsigned int uffd_ctx_features(__u64 user_features)
 {
 	/*
@@ -1967,6 +2031,9 @@  static long userfaultfd_ioctl(struct file *file, unsigned cmd,
 	case UFFDIO_WRITEPROTECT:
 		ret = userfaultfd_writeprotect(ctx, arg);
 		break;
+	case UFFDIO_CONTINUE:
+		ret = userfaultfd_continue(ctx, arg);
+		break;
 	}
 	return ret;
 }
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index f94a35296618..f9fd7df1d586 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -139,6 +139,7 @@  int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm, pte_t *dst_pte,
 				struct vm_area_struct *dst_vma,
 				unsigned long dst_addr,
 				unsigned long src_addr,
+				enum mcopy_atomic_mode mode,
 				struct page **pagep);
 int hugetlb_reserve_pages(struct inode *inode, long from, long to,
 						struct vm_area_struct *vma,
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index fb9abaeb4194..2fcb686211e8 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -37,6 +37,22 @@  extern int sysctl_unprivileged_userfaultfd;
 
 extern vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason);
 
+/*
+ * The mode of operation for __mcopy_atomic and its helpers.
+ *
+ * This is almost an implementation detail (mcopy_atomic below doesn't take this
+ * as a parameter), but it's exposed here because memory-kind-specific
+ * implementations (e.g. hugetlbfs) need to know the mode of operation.
+ */
+enum mcopy_atomic_mode {
+	/* A normal copy_from_user into the destination range. */
+	MCOPY_ATOMIC_NORMAL,
+	/* Don't copy; map the destination range to the zero page. */
+	MCOPY_ATOMIC_ZEROPAGE,
+	/* Just setup the dst_vma, without modifying the underlying page(s). */
+	MCOPY_ATOMIC_CONTINUE,
+};
+
 extern ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start,
 			    unsigned long src_start, unsigned long len,
 			    bool *mmap_changing, __u64 mode);
@@ -44,6 +60,8 @@  extern ssize_t mfill_zeropage(struct mm_struct *dst_mm,
 			      unsigned long dst_start,
 			      unsigned long len,
 			      bool *mmap_changing);
+extern ssize_t mcopy_continue(struct mm_struct *dst_mm, unsigned long dst_start,
+			      unsigned long len, bool *mmap_changing);
 extern int mwriteprotect_range(struct mm_struct *dst_mm,
 			       unsigned long start, unsigned long len,
 			       bool enable_wp, bool *mmap_changing);
diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h
index f24dd4fcbad9..bafbeb1a2624 100644
--- a/include/uapi/linux/userfaultfd.h
+++ b/include/uapi/linux/userfaultfd.h
@@ -40,10 +40,12 @@ 
 	((__u64)1 << _UFFDIO_WAKE |		\
 	 (__u64)1 << _UFFDIO_COPY |		\
 	 (__u64)1 << _UFFDIO_ZEROPAGE |		\
-	 (__u64)1 << _UFFDIO_WRITEPROTECT)
+	 (__u64)1 << _UFFDIO_WRITEPROTECT |	\
+	 (__u64)1 << _UFFDIO_CONTINUE)
 #define UFFD_API_RANGE_IOCTLS_BASIC		\
 	((__u64)1 << _UFFDIO_WAKE |		\
-	 (__u64)1 << _UFFDIO_COPY)
+	 (__u64)1 << _UFFDIO_COPY |		\
+	 (__u64)1 << _UFFDIO_CONTINUE)
 
 /*
  * Valid ioctl command number range with this API is from 0x00 to
@@ -59,6 +61,7 @@ 
 #define _UFFDIO_COPY			(0x03)
 #define _UFFDIO_ZEROPAGE		(0x04)
 #define _UFFDIO_WRITEPROTECT		(0x06)
+#define _UFFDIO_CONTINUE		(0x07)
 #define _UFFDIO_API			(0x3F)
 
 /* userfaultfd ioctl ids */
@@ -77,6 +80,8 @@ 
 				      struct uffdio_zeropage)
 #define UFFDIO_WRITEPROTECT	_IOWR(UFFDIO, _UFFDIO_WRITEPROTECT, \
 				      struct uffdio_writeprotect)
+#define UFFDIO_CONTINUE		_IOR(UFFDIO, _UFFDIO_CONTINUE,	\
+				     struct uffdio_continue)
 
 /* read() structure */
 struct uffd_msg {
@@ -268,6 +273,18 @@  struct uffdio_writeprotect {
 	__u64 mode;
 };
 
+struct uffdio_continue {
+	struct uffdio_range range;
+#define UFFDIO_CONTINUE_MODE_DONTWAKE		((__u64)1<<0)
+	__u64 mode;
+
+	/*
+	 * Fields below here are written by the ioctl and must be at the end:
+	 * the copy_from_user will not read past here.
+	 */
+	__s64 mapped;
+};
+
 /*
  * Flags for the userfaultfd(2) system call itself.
  */
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 6f9d8349f818..740a090f34d1 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -4656,6 +4656,7 @@  int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
 			    struct vm_area_struct *dst_vma,
 			    unsigned long dst_addr,
 			    unsigned long src_addr,
+			    enum mcopy_atomic_mode mode,
 			    struct page **pagep)
 {
 	struct address_space *mapping;
@@ -4668,7 +4669,10 @@  int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
 	int ret;
 	struct page *page;
 
-	if (!*pagep) {
+	mapping = dst_vma->vm_file->f_mapping;
+	idx = vma_hugecache_offset(h, dst_vma, dst_addr);
+
+	if (!*pagep && mode != MCOPY_ATOMIC_CONTINUE) {
 		ret = -ENOMEM;
 		page = alloc_huge_page(dst_vma, dst_addr, 0);
 		if (IS_ERR(page))
@@ -4685,6 +4689,12 @@  int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
 			/* don't free the page */
 			goto out;
 		}
+	} else if (mode == MCOPY_ATOMIC_CONTINUE) {
+		ret = -EFAULT;
+		page = find_lock_page(mapping, idx);
+		*pagep = NULL;
+		if (!page)
+			goto out;
 	} else {
 		page = *pagep;
 		*pagep = NULL;
@@ -4697,13 +4707,8 @@  int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
 	 */
 	__SetPageUptodate(page);
 
-	mapping = dst_vma->vm_file->f_mapping;
-	idx = vma_hugecache_offset(h, dst_vma, dst_addr);
-
-	/*
-	 * If shared, add to page cache
-	 */
-	if (vm_shared) {
+	/* Add shared, newly allocated pages to the page cache. */
+	if (vm_shared && mode != MCOPY_ATOMIC_CONTINUE) {
 		size = i_size_read(mapping->host) >> huge_page_shift(h);
 		ret = -EFAULT;
 		if (idx >= size)
@@ -4763,7 +4768,8 @@  int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
 	update_mmu_cache(dst_vma, dst_addr, dst_pte);
 
 	spin_unlock(ptl);
-	set_page_huge_active(page);
+	if (mode != MCOPY_ATOMIC_CONTINUE)
+		set_page_huge_active(page);
 	if (vm_shared)
 		unlock_page(page);
 	ret = 0;
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index b2ce61c1b50d..a762b9cefaea 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -207,7 +207,7 @@  static __always_inline ssize_t __mcopy_atomic_hugetlb(struct mm_struct *dst_mm,
 					      unsigned long dst_start,
 					      unsigned long src_start,
 					      unsigned long len,
-					      bool zeropage)
+					      enum mcopy_atomic_mode mode)
 {
 	int vm_alloc_shared = dst_vma->vm_flags & VM_SHARED;
 	int vm_shared = dst_vma->vm_flags & VM_SHARED;
@@ -227,7 +227,7 @@  static __always_inline ssize_t __mcopy_atomic_hugetlb(struct mm_struct *dst_mm,
 	 * by THP.  Since we can not reliably insert a zero page, this
 	 * feature is not supported.
 	 */
-	if (zeropage) {
+	if (mode == MCOPY_ATOMIC_ZEROPAGE) {
 		mmap_read_unlock(dst_mm);
 		return -EINVAL;
 	}
@@ -273,8 +273,6 @@  static __always_inline ssize_t __mcopy_atomic_hugetlb(struct mm_struct *dst_mm,
 	}
 
 	while (src_addr < src_start + len) {
-		pte_t dst_pteval;
-
 		BUG_ON(dst_addr >= dst_start + len);
 
 		/*
@@ -297,16 +295,17 @@  static __always_inline ssize_t __mcopy_atomic_hugetlb(struct mm_struct *dst_mm,
 			goto out_unlock;
 		}
 
-		err = -EEXIST;
-		dst_pteval = huge_ptep_get(dst_pte);
-		if (!huge_pte_none(dst_pteval)) {
-			mutex_unlock(&hugetlb_fault_mutex_table[hash]);
-			i_mmap_unlock_read(mapping);
-			goto out_unlock;
+		if (mode != MCOPY_ATOMIC_CONTINUE) {
+			if (!huge_pte_none(huge_ptep_get(dst_pte))) {
+				err = -EEXIST;
+				mutex_unlock(&hugetlb_fault_mutex_table[hash]);
+				i_mmap_unlock_read(mapping);
+				goto out_unlock;
+			}
 		}
 
 		err = hugetlb_mcopy_atomic_pte(dst_mm, dst_pte, dst_vma,
-						dst_addr, src_addr, &page);
+					       dst_addr, src_addr, mode, &page);
 
 		mutex_unlock(&hugetlb_fault_mutex_table[hash]);
 		i_mmap_unlock_read(mapping);
@@ -408,7 +407,7 @@  extern ssize_t __mcopy_atomic_hugetlb(struct mm_struct *dst_mm,
 				      unsigned long dst_start,
 				      unsigned long src_start,
 				      unsigned long len,
-				      bool zeropage);
+				      enum mcopy_atomic_mode mode);
 #endif /* CONFIG_HUGETLB_PAGE */
 
 static __always_inline ssize_t mfill_atomic_pte(struct mm_struct *dst_mm,
@@ -417,7 +416,7 @@  static __always_inline ssize_t mfill_atomic_pte(struct mm_struct *dst_mm,
 						unsigned long dst_addr,
 						unsigned long src_addr,
 						struct page **page,
-						bool zeropage,
+						enum mcopy_atomic_mode mode,
 						bool wp_copy)
 {
 	ssize_t err;
@@ -433,22 +432,38 @@  static __always_inline ssize_t mfill_atomic_pte(struct mm_struct *dst_mm,
 	 * and not in the radix tree.
 	 */
 	if (!(dst_vma->vm_flags & VM_SHARED)) {
-		if (!zeropage)
+		switch (mode) {
+		case MCOPY_ATOMIC_NORMAL:
 			err = mcopy_atomic_pte(dst_mm, dst_pmd, dst_vma,
 					       dst_addr, src_addr, page,
 					       wp_copy);
-		else
+			break;
+		case MCOPY_ATOMIC_ZEROPAGE:
 			err = mfill_zeropage_pte(dst_mm, dst_pmd,
 						 dst_vma, dst_addr);
+			break;
+		/* It only makes sense to CONTINUE for shared memory. */
+		case MCOPY_ATOMIC_CONTINUE:
+			err = -EINVAL;
+			break;
+		}
 	} else {
 		VM_WARN_ON_ONCE(wp_copy);
-		if (!zeropage)
+		switch (mode) {
+		case MCOPY_ATOMIC_NORMAL:
 			err = shmem_mcopy_atomic_pte(dst_mm, dst_pmd,
 						     dst_vma, dst_addr,
 						     src_addr, page);
-		else
+			break;
+		case MCOPY_ATOMIC_ZEROPAGE:
 			err = shmem_mfill_zeropage_pte(dst_mm, dst_pmd,
 						       dst_vma, dst_addr);
+			break;
+		case MCOPY_ATOMIC_CONTINUE:
+			/* FIXME: Add minor fault interception for shmem. */
+			err = -EINVAL;
+			break;
+		}
 	}
 
 	return err;
@@ -458,7 +473,7 @@  static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm,
 					      unsigned long dst_start,
 					      unsigned long src_start,
 					      unsigned long len,
-					      bool zeropage,
+					      enum mcopy_atomic_mode mcopy_mode,
 					      bool *mmap_changing,
 					      __u64 mode)
 {
@@ -527,7 +542,7 @@  static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm,
 	 */
 	if (is_vm_hugetlb_page(dst_vma))
 		return  __mcopy_atomic_hugetlb(dst_mm, dst_vma, dst_start,
-						src_start, len, zeropage);
+						src_start, len, mcopy_mode);
 
 	if (!vma_is_anonymous(dst_vma) && !vma_is_shmem(dst_vma))
 		goto out_unlock;
@@ -577,7 +592,7 @@  static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm,
 		BUG_ON(pmd_trans_huge(*dst_pmd));
 
 		err = mfill_atomic_pte(dst_mm, dst_pmd, dst_vma, dst_addr,
-				       src_addr, &page, zeropage, wp_copy);
+				       src_addr, &page, mcopy_mode, wp_copy);
 		cond_resched();
 
 		if (unlikely(err == -ENOENT)) {
@@ -626,14 +641,22 @@  ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start,
 		     unsigned long src_start, unsigned long len,
 		     bool *mmap_changing, __u64 mode)
 {
-	return __mcopy_atomic(dst_mm, dst_start, src_start, len, false,
-			      mmap_changing, mode);
+	return __mcopy_atomic(dst_mm, dst_start, src_start, len,
+			      MCOPY_ATOMIC_NORMAL, mmap_changing, mode);
 }
 
 ssize_t mfill_zeropage(struct mm_struct *dst_mm, unsigned long start,
 		       unsigned long len, bool *mmap_changing)
 {
-	return __mcopy_atomic(dst_mm, start, 0, len, true, mmap_changing, 0);
+	return __mcopy_atomic(dst_mm, start, 0, len, MCOPY_ATOMIC_ZEROPAGE,
+			      mmap_changing, 0);
+}
+
+ssize_t mcopy_continue(struct mm_struct *dst_mm, unsigned long start,
+		       unsigned long len, bool *mmap_changing)
+{
+	return __mcopy_atomic(dst_mm, start, 0, len, MCOPY_ATOMIC_CONTINUE,
+			      mmap_changing, 0);
 }
 
 int mwriteprotect_range(struct mm_struct *dst_mm, unsigned long start,