Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1370036 > unrolled thread
| Started by | Piotr Kwapulinski <kwapulinski.piotr@gmail.com> |
|---|---|
| First post | 2016-04-02 21:20 +0200 |
| Last post | 2016-04-07 18:30 +0200 |
| Articles | 10 — 5 participants |
Back to article view | Back to linux.kernel
[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
| From | Piotr Kwapulinski <kwapulinski.piotr@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Piotr Kwapulinski <kwapulinski.piotr@gmail.com> |
|---|---|
| Date | 2016-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]
| From | "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> |
|---|---|
| Date | 2016-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]
| From | Konstantin Khlebnikov <koct9i@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2016-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]
| From | Vlastimil Babka <vbabka@suse.cz> |
|---|---|
| Date | 2016-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]
| From | Piotr Kwapulinski <kwapulinski.piotr@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2016-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]
| From | Piotr Kwapulinski <kwapulinski.piotr@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Piotr Kwapulinski <kwapulinski.piotr@gmail.com> |
|---|---|
| Date | 2016-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