Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1370036 > unrolled thread

[PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s)

Started byPiotr Kwapulinski <kwapulinski.piotr@gmail.com>
First post2016-04-02 21:20 +0200
Last post2016-04-07 18:30 +0200
Articles 10 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s) Piotr Kwapulinski <kwapulinski.piotr@gmail.com> - 2016-04-02 21:20 +0200
    [PATCH 1/3] man/mmap.2: don't unmap the overlapping VMA(s) Piotr Kwapulinski <kwapulinski.piotr@gmail.com> - 2016-04-02 21:20 +0200
    Re: [PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s) "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> - 2016-04-03 00:00 +0200
    Re: [PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s) Konstantin Khlebnikov <koct9i@gmail.com> - 2016-04-03 08:00 +0200
    Re: [PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s) Michal Hocko <mhocko@kernel.org> - 2016-04-04 09:40 +0200
      Re: [PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s) Vlastimil Babka <vbabka@suse.cz> - 2016-04-04 17:30 +0200
        Re: [PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s) Piotr Kwapulinski <kwapulinski.piotr@gmail.com> - 2016-04-07 18:20 +0200
          Re: [PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s) Michal Hocko <mhocko@kernel.org> - 2016-04-07 18:40 +0200
            Re: [PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s) Piotr Kwapulinski <kwapulinski.piotr@gmail.com> - 2016-04-08 17:40 +0200
        Re: [PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s) Piotr Kwapulinski <kwapulinski.piotr@gmail.com> - 2016-04-07 18:30 +0200

#1370036 — [PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s)

FromPiotr Kwapulinski <kwapulinski.piotr@gmail.com>
Date2016-04-02 21:20 +0200
Subject[PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s)
Message-ID<rjzfr-8pJ-3@gated-at.bofh.it>
Currently the mmap(MAP_FIXED) discards the overlapping part of the
existing VMA(s).
Introduce the new MAP_DONTUNMAP flag which forces the mmap to fail
with ENOMEM whenever the overlapping occurs and MAP_FIXED is set.
No existing mapping(s) is discarded.
The implementation tests the MAP_DONTUNMAP flag right before unmapping
the VMA. The tile arch is the dependency of mmap_flags.

I did the isolated tests and also tested it with Gentoo full
installation.

Signed-off-by: Piotr Kwapulinski <kwapulinski.piotr@gmail.com>
---
 arch/tile/mm/elf.c                     |  1 +
 include/linux/mm.h                     |  3 ++-
 include/uapi/asm-generic/mman-common.h |  1 +
 mm/mmap.c                              | 10 +++++++---
 4 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c
index 6225cc9..dae4b33 100644
--- a/arch/tile/mm/elf.c
+++ b/arch/tile/mm/elf.c
@@ -142,6 +142,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
 	if (!retval) {
 		unsigned long addr = MEM_USER_INTRPT;
 		addr = mmap_region(NULL, addr, INTRPT_SIZE,
+				   MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
 				   VM_READ|VM_EXEC|
 				   VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 0);
 		if (addr > (unsigned long) -PAGE_SIZE)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index ed6407d..31dcdfb 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2048,7 +2048,8 @@ extern int install_special_mapping(struct mm_struct *mm,
 extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 
 extern unsigned long mmap_region(struct file *file, unsigned long addr,
-	unsigned long len, vm_flags_t vm_flags, unsigned long pgoff);
+	unsigned long len, unsigned long mmap_flags,
+	vm_flags_t vm_flags, unsigned long pgoff);
 extern unsigned long do_mmap(struct file *file, unsigned long addr,
 	unsigned long len, unsigned long prot, unsigned long flags,
 	vm_flags_t vm_flags, unsigned long pgoff, unsigned long *populate);
diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
index 5827438..3655be3 100644
--- a/include/uapi/asm-generic/mman-common.h
+++ b/include/uapi/asm-generic/mman-common.h
@@ -19,6 +19,7 @@
 #define MAP_TYPE	0x0f		/* Mask for type of mapping */
 #define MAP_FIXED	0x10		/* Interpret addr exactly */
 #define MAP_ANONYMOUS	0x20		/* don't use a file */
+#define MAP_DONTUNMAP	0x40		/* don't unmap overlapping VMA */
 #ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED
 # define MAP_UNINITIALIZED 0x4000000	/* For anonymous mmap, memory could be uninitialized */
 #else
diff --git a/mm/mmap.c b/mm/mmap.c
index bd2e1a53..ab429c3 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1286,7 +1286,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
 			vm_flags |= VM_NORESERVE;
 	}
 
-	addr = mmap_region(file, addr, len, vm_flags, pgoff);
+	addr = mmap_region(file, addr, len, flags, vm_flags, pgoff);
 	if (!IS_ERR_VALUE(addr) &&
 	    ((vm_flags & VM_LOCKED) ||
 	     (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))
@@ -1422,7 +1422,8 @@ static inline int accountable_mapping(struct file *file, vm_flags_t vm_flags)
 }
 
 unsigned long mmap_region(struct file *file, unsigned long addr,
-		unsigned long len, vm_flags_t vm_flags, unsigned long pgoff)
+		unsigned long len, unsigned long mmap_flags,
+		vm_flags_t vm_flags, unsigned long pgoff)
 {
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma, *prev;
@@ -1448,7 +1449,10 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
 	/* Clear old maps */
 	while (find_vma_links(mm, addr, addr + len, &prev, &rb_link,
 			      &rb_parent)) {
-		if (do_munmap(mm, addr, len))
+		const bool dont_unmap =
+				(mmap_flags & (MAP_DONTUNMAP | MAP_FIXED))
+				== (MAP_DONTUNMAP | MAP_FIXED);
+		if (dont_unmap || do_munmap(mm, addr, len))
 			return -ENOMEM;
 	}
 
-- 
2.7.4

[toc] | [next] | [standalone]


#1370037 — [PATCH 1/3] man/mmap.2: don't unmap the overlapping VMA(s)

FromPiotr Kwapulinski <kwapulinski.piotr@gmail.com>
Date2016-04-02 21:20 +0200
Subject[PATCH 1/3] man/mmap.2: don't unmap the overlapping VMA(s)
Message-ID<rjzfr-8pJ-9@gated-at.bofh.it>
In reply to#1370036
mmap.2 man page update for MAP_DONTUNMAP flag of mmap.

Signed-off-by: Piotr Kwapulinski <kwapulinski.piotr@gmail.com>
---
It should be considered to be merged only in case the patch
"[PATCH 0/3] mm/mmap.c: don't unmap the overlapping VMA(s)"
is merged.
---
 man2/mmap.2 | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/man2/mmap.2 b/man2/mmap.2
index 0f2f277..0fc5879 100644
--- a/man2/mmap.2
+++ b/man2/mmap.2
@@ -37,7 +37,7 @@
 .\" 2007-07-10, mtk, Added an example program.
 .\" 2008-11-18, mtk, document MAP_STACK
 .\"
-.TH MMAP 2 2016-03-15 "Linux" "Linux Programmer's Manual"
+.TH MMAP 2 2016-04-02 "Linux" "Linux Programmer's Manual"
 .SH NAME
 mmap, munmap \- map or unmap files or devices into memory
 .SH SYNOPSIS
@@ -213,7 +213,9 @@ If the memory region specified by
 .I addr
 and
 .I len
-overlaps pages of any existing mapping(s), then the overlapped
+overlaps pages of any existing mapping(s) and
+.B MAP_DONTUNMAP
+is not set, then the overlapped
 part of the existing mapping(s) will be discarded.
 If the specified address cannot be used,
 .BR mmap ()
@@ -221,6 +223,23 @@ will fail.
 Because requiring a fixed address for a mapping is less portable,
 the use of this option is discouraged.
 .TP
+.BR MAP_DONTUNMAP " (since Linux 4.6)"
+If this flag and
+.B MAP_FIXED
+are set and the memory region specified by
+.I addr
+and
+.I length
+overlaps pages of any existing mapping(s), then the
+.BR mmap ()
+will fail with
+.BR ENOMEM .
+No existing mapping(s) will be
+discarded.
+
+Note: currently, this flag is not implemented in the glibc wrapper.
+Use the numerical hex value 40, if you want to use it.
+.TP
 .B MAP_GROWSDOWN
 Used for stacks.
 Indicates to the kernel virtual memory system that the mapping
@@ -477,6 +496,15 @@ No memory is available.
 .TP
 .B ENOMEM
 The process's maximum number of mappings would have been exceeded.
+Or, both the
+.B MAP_FIXED
+and
+.B MAP_DONTUNMAP
+flags are set and the memory region specified by
+.I addr
+and
+.I length
+overlaps pages of any existing mapping(s).
 This error can also occur for
 .BR munmap (2),
 when unmapping a region in the middle of an existing mapping,
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1370057

From"Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Date2016-04-03 00:00 +0200
Message-ID<rjBKh-1Cj-1@gated-at.bofh.it>
In reply to#1370036
On Sat, Apr 02, 2016 at 09:17:31PM +0200, Piotr Kwapulinski wrote:
> @@ -19,6 +19,7 @@
>  #define MAP_TYPE	0x0f		/* Mask for type of mapping */
>  #define MAP_FIXED	0x10		/* Interpret addr exactly */
>  #define MAP_ANONYMOUS	0x20		/* don't use a file */
> +#define MAP_DONTUNMAP	0x40		/* don't unmap overlapping VMA */

NAK.

arch/powerpc/include/uapi/asm/mman.h:#define MAP_NORESERVE   0x40            /* don't reserve swap pages */
arch/sparc/include/uapi/asm/mman.h:#define MAP_NORESERVE   0x40            /* don't reserve swap pages */
arch/x86/include/uapi/asm/mman.h:#define MAP_32BIT      0x40            /* only give out 32bit addresses */

-- 
 Kirill A. Shutemov

[toc] | [prev] | [next] | [standalone]


#1370113

FromKonstantin Khlebnikov <koct9i@gmail.com>
Date2016-04-03 08:00 +0200
Message-ID<rjJeP-7g4-3@gated-at.bofh.it>
In reply to#1370036
On Sat, Apr 2, 2016 at 10:17 PM, Piotr Kwapulinski
<kwapulinski.piotr@gmail.com> wrote:
> Currently the mmap(MAP_FIXED) discards the overlapping part of the
> existing VMA(s).
> Introduce the new MAP_DONTUNMAP flag which forces the mmap to fail
> with ENOMEM whenever the overlapping occurs and MAP_FIXED is set.
> No existing mapping(s) is discarded.

How userspace is supposed to use this and handle failure?

For now you can get the same behavior in couple syscalls:
mmap without MAP_FIXED if resulting address differs unmmap and handle error.
Twice slower but this is error-path so you anyway have to some extra actions.

> The implementation tests the MAP_DONTUNMAP flag right before unmapping
> the VMA. The tile arch is the dependency of mmap_flags.
>
> I did the isolated tests and also tested it with Gentoo full
> installation.
>
> Signed-off-by: Piotr Kwapulinski <kwapulinski.piotr@gmail.com>
> ---
>  arch/tile/mm/elf.c                     |  1 +
>  include/linux/mm.h                     |  3 ++-
>  include/uapi/asm-generic/mman-common.h |  1 +
>  mm/mmap.c                              | 10 +++++++---
>  4 files changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c
> index 6225cc9..dae4b33 100644
> --- a/arch/tile/mm/elf.c
> +++ b/arch/tile/mm/elf.c
> @@ -142,6 +142,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
>         if (!retval) {
>                 unsigned long addr = MEM_USER_INTRPT;
>                 addr = mmap_region(NULL, addr, INTRPT_SIZE,
> +                                  MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
>                                    VM_READ|VM_EXEC|
>                                    VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 0);
>                 if (addr > (unsigned long) -PAGE_SIZE)
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index ed6407d..31dcdfb 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -2048,7 +2048,8 @@ extern int install_special_mapping(struct mm_struct *mm,
>  extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
>
>  extern unsigned long mmap_region(struct file *file, unsigned long addr,
> -       unsigned long len, vm_flags_t vm_flags, unsigned long pgoff);
> +       unsigned long len, unsigned long mmap_flags,
> +       vm_flags_t vm_flags, unsigned long pgoff);
>  extern unsigned long do_mmap(struct file *file, unsigned long addr,
>         unsigned long len, unsigned long prot, unsigned long flags,
>         vm_flags_t vm_flags, unsigned long pgoff, unsigned long *populate);
> diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
> index 5827438..3655be3 100644
> --- a/include/uapi/asm-generic/mman-common.h
> +++ b/include/uapi/asm-generic/mman-common.h
> @@ -19,6 +19,7 @@
>  #define MAP_TYPE       0x0f            /* Mask for type of mapping */
>  #define MAP_FIXED      0x10            /* Interpret addr exactly */
>  #define MAP_ANONYMOUS  0x20            /* don't use a file */
> +#define MAP_DONTUNMAP  0x40            /* don't unmap overlapping VMA */
>  #ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED
>  # define MAP_UNINITIALIZED 0x4000000   /* For anonymous mmap, memory could be uninitialized */
>  #else
> diff --git a/mm/mmap.c b/mm/mmap.c
> index bd2e1a53..ab429c3 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -1286,7 +1286,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
>                         vm_flags |= VM_NORESERVE;
>         }
>
> -       addr = mmap_region(file, addr, len, vm_flags, pgoff);
> +       addr = mmap_region(file, addr, len, flags, vm_flags, pgoff);
>         if (!IS_ERR_VALUE(addr) &&
>             ((vm_flags & VM_LOCKED) ||
>              (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))
> @@ -1422,7 +1422,8 @@ static inline int accountable_mapping(struct file *file, vm_flags_t vm_flags)
>  }
>
>  unsigned long mmap_region(struct file *file, unsigned long addr,
> -               unsigned long len, vm_flags_t vm_flags, unsigned long pgoff)
> +               unsigned long len, unsigned long mmap_flags,
> +               vm_flags_t vm_flags, unsigned long pgoff)
>  {
>         struct mm_struct *mm = current->mm;
>         struct vm_area_struct *vma, *prev;
> @@ -1448,7 +1449,10 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
>         /* Clear old maps */
>         while (find_vma_links(mm, addr, addr + len, &prev, &rb_link,
>                               &rb_parent)) {
> -               if (do_munmap(mm, addr, len))
> +               const bool dont_unmap =
> +                               (mmap_flags & (MAP_DONTUNMAP | MAP_FIXED))
> +                               == (MAP_DONTUNMAP | MAP_FIXED);
> +               if (dont_unmap || do_munmap(mm, addr, len))
>                         return -ENOMEM;
>         }
>
> --
> 2.7.4
>

[toc] | [prev] | [next] | [standalone]


#1370410

FromMichal Hocko <mhocko@kernel.org>
Date2016-04-04 09:40 +0200
Message-ID<rk7h8-8aW-9@gated-at.bofh.it>
In reply to#1370036
On Sat 02-04-16 21:17:31, Piotr Kwapulinski wrote:
> Currently the mmap(MAP_FIXED) discards the overlapping part of the
> existing VMA(s).
> Introduce the new MAP_DONTUNMAP flag which forces the mmap to fail
> with ENOMEM whenever the overlapping occurs and MAP_FIXED is set.
> No existing mapping(s) is discarded.

You forgot to tell us what is the use case for this new flag.
-- 
Michal Hocko
SUSE Labs

[toc] | [prev] | [next] | [standalone]


#1370688

FromVlastimil Babka <vbabka@suse.cz>
Date2016-04-04 17:30 +0200
Message-ID<rkeBY-52d-13@gated-at.bofh.it>
In reply to#1370410
On 04/04/2016 09:31 AM, Michal Hocko wrote:
> On Sat 02-04-16 21:17:31, Piotr Kwapulinski wrote:
>> Currently the mmap(MAP_FIXED) discards the overlapping part of the
>> existing VMA(s).
>> Introduce the new MAP_DONTUNMAP flag which forces the mmap to fail
>> with ENOMEM whenever the overlapping occurs and MAP_FIXED is set.
>> No existing mapping(s) is discarded.
>
> You forgot to tell us what is the use case for this new flag.

Exactly. Also, returning ENOMEM is strange, EINVAL might be a better 
match, otherwise how would you distinguish a "geunine" ENOMEM from 
passing a wrong address?

[toc] | [prev] | [next] | [standalone]


#1373512

FromPiotr Kwapulinski <kwapulinski.piotr@gmail.com>
Date2016-04-07 18:20 +0200
Message-ID<rlkOZ-6z5-13@gated-at.bofh.it>
In reply to#1370688
On Mon, Apr 04, 2016 at 05:26:43PM +0200, Vlastimil Babka wrote:
> On 04/04/2016 09:31 AM, Michal Hocko wrote:
> >On Sat 02-04-16 21:17:31, Piotr Kwapulinski wrote:
> >>Currently the mmap(MAP_FIXED) discards the overlapping part of the
> >>existing VMA(s).
> >>Introduce the new MAP_DONTUNMAP flag which forces the mmap to fail
> >>with ENOMEM whenever the overlapping occurs and MAP_FIXED is set.
> >>No existing mapping(s) is discarded.
> >
> >You forgot to tell us what is the use case for this new flag.
> 
> Exactly. Also, returning ENOMEM is strange, EINVAL might be a better match,
> otherwise how would you distinguish a "geunine" ENOMEM from passing a wrong
> address?
> 
> 

Thanks to all for suggestions. I'll fix them.

The example use case:
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>

void main(void)
{
  void* addr = (void*)0x1000000;
  size_t size = 0x600000;
  void* start = 0;
  start = mmap(addr,
               size,
               PROT_WRITE,
               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
               -1, 0);

  strcpy(start, "PPPP");
  printf("%s\n", start);        // == PPPP

  addr = (void*)0x1000000;
  size = 0x9000;
  start = mmap(addr,
               size,
               PROT_READ | PROT_WRITE,
               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
               -1, 0);
  
  printf("%s\n", start);        // != PPPP
}

Another use case, this time with huge pages in action.
The limit configured in proc's nr_hugepages is exceeded.
mmap unmaps the area and fails. No new mapping is created.
The program segfaults.

echo 0 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

void main(void)
{
  void* addr = (void*)0x1000000;
  size_t size = 0x600000;
  void* start = 0;
  start = mmap(addr,
               size,
               PROT_WRITE,
               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
               -1, 0);

  strcpy(start, "PPPP");
  printf("%s\n", start);        // == PPPP

  addr = (void*)0x1000000;
  size = 0x400000;
  start = mmap(addr,
               size,
               PROT_READ | PROT_WRITE,
               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB,
               -1, 0);         // mmap fails but unmaps the area

  printf("%s\n", start);       // segfault
}

Piotr

[toc] | [prev] | [next] | [standalone]


#1373546

FromMichal Hocko <mhocko@kernel.org>
Date2016-04-07 18:40 +0200
Message-ID<rll8n-6JT-41@gated-at.bofh.it>
In reply to#1373512
On Thu 07-04-16 18:11:29, Piotr Kwapulinski wrote:
> On Mon, Apr 04, 2016 at 05:26:43PM +0200, Vlastimil Babka wrote:
> > On 04/04/2016 09:31 AM, Michal Hocko wrote:
> > >On Sat 02-04-16 21:17:31, Piotr Kwapulinski wrote:
> > >>Currently the mmap(MAP_FIXED) discards the overlapping part of the
> > >>existing VMA(s).
> > >>Introduce the new MAP_DONTUNMAP flag which forces the mmap to fail
> > >>with ENOMEM whenever the overlapping occurs and MAP_FIXED is set.
> > >>No existing mapping(s) is discarded.
> > >
> > >You forgot to tell us what is the use case for this new flag.
> > 
> > Exactly. Also, returning ENOMEM is strange, EINVAL might be a better match,
> > otherwise how would you distinguish a "geunine" ENOMEM from passing a wrong
> > address?
> > 
> > 
> 
> Thanks to all for suggestions. I'll fix them.
> 
> The example use case:
> #include <stdio.h>
> #include <string.h>
> #include <sys/mman.h>
> 
> void main(void)
> {
>   void* addr = (void*)0x1000000;
>   size_t size = 0x600000;
>   void* start = 0;
>   start = mmap(addr,
>                size,
>                PROT_WRITE,
>                MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
>                -1, 0);
> 
>   strcpy(start, "PPPP");
>   printf("%s\n", start);        // == PPPP
> 
>   addr = (void*)0x1000000;
>   size = 0x9000;
>   start = mmap(addr,
>                size,
>                PROT_READ | PROT_WRITE,
>                MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
>                -1, 0);
>   
>   printf("%s\n", start);        // != PPPP
> }
> 
> Another use case, this time with huge pages in action.
> The limit configured in proc's nr_hugepages is exceeded.
> mmap unmaps the area and fails. No new mapping is created.
> The program segfaults.

Yes and this is the standard behavior for ages. So _why_ somebody wants
non-default behavior. When I've asked for the use case I meant a real
life code (not just an example snippet) which cannot cope with the
standard semantic. In other words why this cannot be handled in the
userspace and we have to add a new API which we have to maintain for
ever?
-- 
Michal Hocko
SUSE Labs

[toc] | [prev] | [next] | [standalone]


#1374315

FromPiotr Kwapulinski <kwapulinski.piotr@gmail.com>
Date2016-04-08 17:40 +0200
Message-ID<rlGFQ-60n-27@gated-at.bofh.it>
In reply to#1373546
On Thu, Apr 07, 2016 at 06:31:09PM +0200, Michal Hocko wrote:
> On Thu 07-04-16 18:11:29, Piotr Kwapulinski wrote:
> > On Mon, Apr 04, 2016 at 05:26:43PM +0200, Vlastimil Babka wrote:
> > > On 04/04/2016 09:31 AM, Michal Hocko wrote:
> > > >On Sat 02-04-16 21:17:31, Piotr Kwapulinski wrote:
> > > >>Currently the mmap(MAP_FIXED) discards the overlapping part of the
> > > >>existing VMA(s).
> > > >>Introduce the new MAP_DONTUNMAP flag which forces the mmap to fail
> > > >>with ENOMEM whenever the overlapping occurs and MAP_FIXED is set.
> > > >>No existing mapping(s) is discarded.
> > > >
> > > >You forgot to tell us what is the use case for this new flag.
> > > 
> > > Exactly. Also, returning ENOMEM is strange, EINVAL might be a better match,
> > > otherwise how would you distinguish a "geunine" ENOMEM from passing a wrong
> > > address?
> > > 
> > > 
> > 
> > Thanks to all for suggestions. I'll fix them.
> > 
> > The example use case:
> > #include <stdio.h>
> > #include <string.h>
> > #include <sys/mman.h>
> > 
> > void main(void)
> > {
> >   void* addr = (void*)0x1000000;
> >   size_t size = 0x600000;
> >   void* start = 0;
> >   start = mmap(addr,
> >                size,
> >                PROT_WRITE,
> >                MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
> >                -1, 0);
> > 
> >   strcpy(start, "PPPP");
> >   printf("%s\n", start);        // == PPPP
> > 
> >   addr = (void*)0x1000000;
> >   size = 0x9000;
> >   start = mmap(addr,
> >                size,
> >                PROT_READ | PROT_WRITE,
> >                MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
> >                -1, 0);
> >   
> >   printf("%s\n", start);        // != PPPP
> > }
> > 
> > Another use case, this time with huge pages in action.
> > The limit configured in proc's nr_hugepages is exceeded.
> > mmap unmaps the area and fails. No new mapping is created.
> > The program segfaults.
> 
> Yes and this is the standard behavior for ages. So _why_ somebody wants
> non-default behavior. When I've asked for the use case I meant a real
> life code (not just an example snippet) which cannot cope with the
> standard semantic. In other words why this cannot be handled in the
> userspace and we have to add a new API which we have to maintain for
> ever?

Ok, I got it. Thanks for feedback.

[toc] | [prev] | [next] | [standalone]


#1373519

FromPiotr Kwapulinski <kwapulinski.piotr@gmail.com>
Date2016-04-07 18:30 +0200
Message-ID<rlkYG-6F9-15@gated-at.bofh.it>
In reply to#1370688
On Mon, Apr 04, 2016 at 05:26:43PM +0200, Vlastimil Babka wrote:
> On 04/04/2016 09:31 AM, Michal Hocko wrote:
> >On Sat 02-04-16 21:17:31, Piotr Kwapulinski wrote:
> >>Currently the mmap(MAP_FIXED) discards the overlapping part of the
> >>existing VMA(s).
> >>Introduce the new MAP_DONTUNMAP flag which forces the mmap to fail
> >>with ENOMEM whenever the overlapping occurs and MAP_FIXED is set.
> >>No existing mapping(s) is discarded.
> >
> >You forgot to tell us what is the use case for this new flag.
> 
> Exactly. Also, returning ENOMEM is strange, EINVAL might be a better match,
> otherwise how would you distinguish a "geunine" ENOMEM from passing a wrong
> address?
> 
> 

Thanks to all for suggestions. I'll fix them.

The example use case:
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>

void main(void)
{
  void* addr = (void*)0x1000000;
  size_t size = 0x600000;
  void* start = 0;
  start = mmap(addr,
               size,
               PROT_WRITE,
               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
               -1, 0);

  strcpy(start, "PPPP");
  printf("%s\n", start);        // == PPPP

  addr = (void*)0x1000000;
  size = 0x9000;
  start = mmap(addr,
               size,
               PROT_READ | PROT_WRITE,
               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
               -1, 0);
  
  printf("%s\n", start);        // != PPPP
}

Another use case, this time with huge pages in action.
The limit configured in proc's nr_hugepages is exceeded.
mmap unmaps the area and fails. No new mapping is created.
The program segfaults.

echo 0 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

void main(void)
{
  void* addr = (void*)0x1000000;
  size_t size = 0x600000;
  void* start = 0;
  start = mmap(addr,
               size,
               PROT_WRITE,
               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
               -1, 0);

  strcpy(start, "PPPP");
  printf("%s\n", start);        // == PPPP

  addr = (void*)0x1000000;
  size = 0x400000;
  start = mmap(addr,
               size,
               PROT_READ | PROT_WRITE,
               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB,
               -1, 0);         // mmap fails but unmaps the area

  printf("%s\n", addr);       // segfault
}

Piotr

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web