diff mbox series

[2/2,2/2] mm: add merging after mremap resize

Message ID 20220527104810.24736-3-matenajakub@gmail.com (mailing list archive)
State New
Headers show
Series Refactor of vma_merge and new merge call | expand

Commit Message

Jakub Matěna May 27, 2022, 10:48 a.m. UTC
When mremap call results in expansion, it might be possible to merge the
VMA with the next VMA which might become adjacent. This patch adds
vma_merge call after the expansion is done to try and merge.

Signed-off-by: Jakub Matěna <matenajakub@gmail.com>
---
 mm/mremap.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

Comments

kernel test robot May 27, 2022, 4:19 p.m. UTC | #1
Hi "Jakub,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on v5.18]
[cannot apply to akpm-mm/mm-everything linus/master next-20220527]
[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/intel-lab-lkp/linux/commits/Jakub-Mat-na/Refactor-of-vma_merge-and-new-merge-call/20220527-184844
base:    4b0986a3613c92f4ec1bdc7f60ec66fea135991f
config: mips-pic32mzda_defconfig (https://download.01.org/0day-ci/archive/20220527/202205272341.dFRSUlfS-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 134d7f9a4b97e9035150d970bd9e376043c4577e)
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 mips cross compiling tool for clang build
        # apt-get install binutils-mips-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/fae2b6e81c73c0517e3be864608d069a2d4fb8b3
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Jakub-Mat-na/Refactor-of-vma_merge-and-new-merge-call/20220527-184844
        git checkout fae2b6e81c73c0517e3be864608d069a2d4fb8b3
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=mips SHELL=/bin/bash

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

All errors (new ones prefixed by >>):

>> mm/mremap.c:1028:47: error: call to undeclared function 'vma_policy'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
                                           vma->vm_pgoff + (old_len >> PAGE_SHIFT), vma_policy(vma),
                                                                                    ^
   mm/mremap.c:1028:47: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'struct mempolicy *' [-Wint-conversion]
                                           vma->vm_pgoff + (old_len >> PAGE_SHIFT), vma_policy(vma),
                                                                                    ^~~~~~~~~~~~~~~
   include/linux/mm.h:2628:20: note: passing argument to parameter here
           struct mempolicy *, struct vm_userfaultfd_ctx, struct anon_vma_name *);
                             ^
   1 warning and 1 error generated.


vim +/vma_policy +1028 mm/mremap.c

   885	
   886	/*
   887	 * Expand (or shrink) an existing mapping, potentially moving it at the
   888	 * same time (controlled by the MREMAP_MAYMOVE flag and available VM space)
   889	 *
   890	 * MREMAP_FIXED option added 5-Dec-1999 by Benjamin LaHaise
   891	 * This option implies MREMAP_MAYMOVE.
   892	 */
   893	SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
   894			unsigned long, new_len, unsigned long, flags,
   895			unsigned long, new_addr)
   896	{
   897		struct mm_struct *mm = current->mm;
   898		struct vm_area_struct *vma;
   899		unsigned long ret = -EINVAL;
   900		bool locked = false;
   901		bool downgraded = false;
   902		struct vm_userfaultfd_ctx uf = NULL_VM_UFFD_CTX;
   903		LIST_HEAD(uf_unmap_early);
   904		LIST_HEAD(uf_unmap);
   905	
   906		/*
   907		 * There is a deliberate asymmetry here: we strip the pointer tag
   908		 * from the old address but leave the new address alone. This is
   909		 * for consistency with mmap(), where we prevent the creation of
   910		 * aliasing mappings in userspace by leaving the tag bits of the
   911		 * mapping address intact. A non-zero tag will cause the subsequent
   912		 * range checks to reject the address as invalid.
   913		 *
   914		 * See Documentation/arm64/tagged-address-abi.rst for more information.
   915		 */
   916		addr = untagged_addr(addr);
   917	
   918		if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP))
   919			return ret;
   920	
   921		if (flags & MREMAP_FIXED && !(flags & MREMAP_MAYMOVE))
   922			return ret;
   923	
   924		/*
   925		 * MREMAP_DONTUNMAP is always a move and it does not allow resizing
   926		 * in the process.
   927		 */
   928		if (flags & MREMAP_DONTUNMAP &&
   929				(!(flags & MREMAP_MAYMOVE) || old_len != new_len))
   930			return ret;
   931	
   932	
   933		if (offset_in_page(addr))
   934			return ret;
   935	
   936		old_len = PAGE_ALIGN(old_len);
   937		new_len = PAGE_ALIGN(new_len);
   938	
   939		/*
   940		 * We allow a zero old-len as a special case
   941		 * for DOS-emu "duplicate shm area" thing. But
   942		 * a zero new-len is nonsensical.
   943		 */
   944		if (!new_len)
   945			return ret;
   946	
   947		if (mmap_write_lock_killable(current->mm))
   948			return -EINTR;
   949		vma = vma_lookup(mm, addr);
   950		if (!vma) {
   951			ret = -EFAULT;
   952			goto out;
   953		}
   954	
   955		if (is_vm_hugetlb_page(vma)) {
   956			struct hstate *h __maybe_unused = hstate_vma(vma);
   957	
   958			old_len = ALIGN(old_len, huge_page_size(h));
   959			new_len = ALIGN(new_len, huge_page_size(h));
   960	
   961			/* addrs must be huge page aligned */
   962			if (addr & ~huge_page_mask(h))
   963				goto out;
   964			if (new_addr & ~huge_page_mask(h))
   965				goto out;
   966	
   967			/*
   968			 * Don't allow remap expansion, because the underlying hugetlb
   969			 * reservation is not yet capable to handle split reservation.
   970			 */
   971			if (new_len > old_len)
   972				goto out;
   973		}
   974	
   975		if (flags & (MREMAP_FIXED | MREMAP_DONTUNMAP)) {
   976			ret = mremap_to(addr, old_len, new_addr, new_len,
   977					&locked, flags, &uf, &uf_unmap_early,
   978					&uf_unmap);
   979			goto out;
   980		}
   981	
   982		/*
   983		 * Always allow a shrinking remap: that just unmaps
   984		 * the unnecessary pages..
   985		 * __do_munmap does all the needed commit accounting, and
   986		 * downgrades mmap_lock to read if so directed.
   987		 */
   988		if (old_len >= new_len) {
   989			int retval;
   990	
   991			retval = __do_munmap(mm, addr+new_len, old_len - new_len,
   992					  &uf_unmap, true);
   993			if (retval < 0 && old_len != new_len) {
   994				ret = retval;
   995				goto out;
   996			/* Returning 1 indicates mmap_lock is downgraded to read. */
   997			} else if (retval == 1)
   998				downgraded = true;
   999			ret = addr;
  1000			goto out;
  1001		}
  1002	
  1003		/*
  1004		 * Ok, we need to grow..
  1005		 */
  1006		vma = vma_to_resize(addr, old_len, new_len, flags);
  1007		if (IS_ERR(vma)) {
  1008			ret = PTR_ERR(vma);
  1009			goto out;
  1010		}
  1011	
  1012		/* old_len exactly to the end of the area..
  1013		 */
  1014		if (old_len == vma->vm_end - addr) {
  1015			/* can we just expand the current mapping? */
  1016			if (vma_expandable(vma, new_len - old_len)) {
  1017				long pages = (new_len - old_len) >> PAGE_SHIFT;
  1018	
  1019				if (vma->vm_flags & VM_ACCOUNT) {
  1020					if (security_vm_enough_memory_mm(mm, pages)) {
  1021						ret = -ENOMEM;
  1022						goto out;
  1023					}
  1024				}
  1025	
  1026				vma = vma_merge(mm, vma, addr + old_len, addr + new_len,
  1027						vma->vm_flags, vma->anon_vma, vma->vm_file,
> 1028						vma->vm_pgoff + (old_len >> PAGE_SHIFT), vma_policy(vma),
Kirill A . Shutemov May 27, 2022, 11:46 p.m. UTC | #2
On Fri, May 27, 2022 at 12:48:10PM +0200, Jakub Matěna wrote:
> When mremap call results in expansion, it might be possible to merge the
> VMA with the next VMA which might become adjacent. This patch adds
> vma_merge call after the expansion is done to try and merge.
> 
> Signed-off-by: Jakub Matěna <matenajakub@gmail.com>
> ---
>  mm/mremap.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/mm/mremap.c b/mm/mremap.c
> index 303d3290b938..c41237e62156 100644
> --- a/mm/mremap.c
> +++ b/mm/mremap.c
> @@ -9,6 +9,7 @@
>   */
>  
>  #include <linux/mm.h>
> +#include <linux/mm_inline.h>
>  #include <linux/hugetlb.h>
>  #include <linux/shm.h>
>  #include <linux/ksm.h>
> @@ -1022,8 +1023,11 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
>  				}
>  			}
>  
> -			if (vma_adjust(vma, vma->vm_start, addr + new_len,
> -				       vma->vm_pgoff, NULL)) {
> +			vma = vma_merge(mm, vma, addr + old_len, addr + new_len,
> +					vma->vm_flags, vma->anon_vma, vma->vm_file,
> +					vma->vm_pgoff + (old_len >> PAGE_SHIFT), vma_policy(vma),
> +					vma->vm_userfaultfd_ctx, anon_vma_name(vma));

The arguement list gets busy. Maybe some variables would help.
Calculation around vm_pgoff is not obvious and requires some explanation.

> +			if (!vma) {
>  				vm_unacct_memory(pages);
>  				ret = -ENOMEM;
>  				goto out;
> -- 
> 2.35.1
>
Jakub Matěna May 30, 2022, 10:53 a.m. UTC | #3
On Sat, May 28, 2022 at 1:45 AM Kirill A. Shutemov <kirill@shutemov.name> wrote:
>
> On Fri, May 27, 2022 at 12:48:10PM +0200, Jakub Matěna wrote:
> > When mremap call results in expansion, it might be possible to merge the
> > VMA with the next VMA which might become adjacent. This patch adds
> > vma_merge call after the expansion is done to try and merge.
> >
> > Signed-off-by: Jakub Matěna <matenajakub@gmail.com>
> > ---
> >  mm/mremap.c | 8 ++++++--
> >  1 file changed, 6 insertions(+), 2 deletions(-)
> >
> > diff --git a/mm/mremap.c b/mm/mremap.c
> > index 303d3290b938..c41237e62156 100644
> > --- a/mm/mremap.c
> > +++ b/mm/mremap.c
> > @@ -9,6 +9,7 @@
> >   */
> >
> >  #include <linux/mm.h>
> > +#include <linux/mm_inline.h>
> >  #include <linux/hugetlb.h>
> >  #include <linux/shm.h>
> >  #include <linux/ksm.h>
> > @@ -1022,8 +1023,11 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
> >                               }
> >                       }
> >
> > -                     if (vma_adjust(vma, vma->vm_start, addr + new_len,
> > -                                    vma->vm_pgoff, NULL)) {
> > +                     vma = vma_merge(mm, vma, addr + old_len, addr + new_len,
> > +                                     vma->vm_flags, vma->anon_vma, vma->vm_file,
> > +                                     vma->vm_pgoff + (old_len >> PAGE_SHIFT), vma_policy(vma),
> > +                                     vma->vm_userfaultfd_ctx, anon_vma_name(vma));
>
> The arguement list gets busy. Maybe some variables would help.
> Calculation around vm_pgoff is not obvious and requires some explanation.

Ok, I will add the following comment:

"Function vma_merge() is called on the extension we are adding to the
already existing vma, vma_merge() will merge this extension with the
already existing vma (expand operation itself) and possibly also with
the next vma if it becomes adjacent to the expanded vma and otherwise
compatible."

And I will also introduce three new variables to better explain some
of the arguments:

unsigned long extension_start = addr + old_len;
unsigned long extension_end = addr + new_len;
pgoff_t extension_pgoff = vma->vm_pgoff + (old_len >> PAGE_SHIFT);

>
> > +                     if (!vma) {
> >                               vm_unacct_memory(pages);
> >                               ret = -ENOMEM;
> >                               goto out;
> > --
> > 2.35.1
> >
>
> --
>  Kirill A. Shutemov

Jakub Matěna
diff mbox series

Patch

diff --git a/mm/mremap.c b/mm/mremap.c
index 303d3290b938..c41237e62156 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -9,6 +9,7 @@ 
  */
 
 #include <linux/mm.h>
+#include <linux/mm_inline.h>
 #include <linux/hugetlb.h>
 #include <linux/shm.h>
 #include <linux/ksm.h>
@@ -1022,8 +1023,11 @@  SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
 				}
 			}
 
-			if (vma_adjust(vma, vma->vm_start, addr + new_len,
-				       vma->vm_pgoff, NULL)) {
+			vma = vma_merge(mm, vma, addr + old_len, addr + new_len,
+					vma->vm_flags, vma->anon_vma, vma->vm_file,
+					vma->vm_pgoff + (old_len >> PAGE_SHIFT), vma_policy(vma),
+					vma->vm_userfaultfd_ctx, anon_vma_name(vma));
+			if (!vma) {
 				vm_unacct_memory(pages);
 				ret = -ENOMEM;
 				goto out;