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

2016-04-08 Thread Piotr Kwapulinski
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 
> > #include 
> > #include 
> > 
> > void main(void)
> > {
> >   void* addr = (void*)0x100;
> >   size_t size = 0x60;
> >   void* start = 0;
> >   start = mmap(addr,
> >size,
> >PROT_WRITE,
> >MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
> >-1, 0);
> > 
> >   strcpy(start, "");
> >   printf("%s\n", start);// == 
> > 
> >   addr = (void*)0x100;
> >   size = 0x9000;
> >   start = mmap(addr,
> >size,
> >PROT_READ | PROT_WRITE,
> >MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
> >-1, 0);
> >   
> >   printf("%s\n", start);// != 
> > }
> > 
> > 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.



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

2016-04-08 Thread Piotr Kwapulinski
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 
> > #include 
> > #include 
> > 
> > void main(void)
> > {
> >   void* addr = (void*)0x100;
> >   size_t size = 0x60;
> >   void* start = 0;
> >   start = mmap(addr,
> >size,
> >PROT_WRITE,
> >MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
> >-1, 0);
> > 
> >   strcpy(start, "");
> >   printf("%s\n", start);// == 
> > 
> >   addr = (void*)0x100;
> >   size = 0x9000;
> >   start = mmap(addr,
> >size,
> >PROT_READ | PROT_WRITE,
> >MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
> >-1, 0);
> >   
> >   printf("%s\n", start);// != 
> > }
> > 
> > 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.



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

2016-04-07 Thread Michal Hocko
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 
> #include 
> #include 
> 
> void main(void)
> {
>   void* addr = (void*)0x100;
>   size_t size = 0x60;
>   void* start = 0;
>   start = mmap(addr,
>size,
>PROT_WRITE,
>MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
>-1, 0);
> 
>   strcpy(start, "");
>   printf("%s\n", start);// == 
> 
>   addr = (void*)0x100;
>   size = 0x9000;
>   start = mmap(addr,
>size,
>PROT_READ | PROT_WRITE,
>MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
>-1, 0);
>   
>   printf("%s\n", start);// != 
> }
> 
> 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


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

2016-04-07 Thread Michal Hocko
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 
> #include 
> #include 
> 
> void main(void)
> {
>   void* addr = (void*)0x100;
>   size_t size = 0x60;
>   void* start = 0;
>   start = mmap(addr,
>size,
>PROT_WRITE,
>MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
>-1, 0);
> 
>   strcpy(start, "");
>   printf("%s\n", start);// == 
> 
>   addr = (void*)0x100;
>   size = 0x9000;
>   start = mmap(addr,
>size,
>PROT_READ | PROT_WRITE,
>MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
>-1, 0);
>   
>   printf("%s\n", start);// != 
> }
> 
> 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


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

2016-04-07 Thread Piotr Kwapulinski
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 
#include 
#include 

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

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

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

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 
#include 
#include 
#include 

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

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

  addr = (void*)0x100;
  size = 0x40;
  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



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

2016-04-07 Thread Piotr Kwapulinski
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 
#include 
#include 

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

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

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

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 
#include 
#include 
#include 

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

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

  addr = (void*)0x100;
  size = 0x40;
  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



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

2016-04-07 Thread Piotr Kwapulinski
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 
#include 
#include 

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

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

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

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 
#include 
#include 
#include 

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

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

  addr = (void*)0x100;
  size = 0x40;
  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



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

2016-04-07 Thread Piotr Kwapulinski
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 
#include 
#include 

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

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

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

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 
#include 
#include 
#include 

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

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

  addr = (void*)0x100;
  size = 0x40;
  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



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

2016-04-04 Thread Vlastimil Babka

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?





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

2016-04-04 Thread Vlastimil Babka

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?





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

2016-04-04 Thread Michal Hocko
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


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

2016-04-04 Thread Michal Hocko
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


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

2016-04-02 Thread Konstantin Khlebnikov
On Sat, Apr 2, 2016 at 10:17 PM, 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.

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 
> ---
>  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 0x400   /* 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, , _link,
>   _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
>


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

2016-04-02 Thread Konstantin Khlebnikov
On Sat, Apr 2, 2016 at 10:17 PM, 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.

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 
> ---
>  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 0x400   /* 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, , _link,
>   _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
>


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

2016-04-02 Thread Kirill A. Shutemov
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_FIXED0x10/* Interpret addr exactly */
>  #define MAP_ANONYMOUS0x20/* don't use a file */
> +#define MAP_DONTUNMAP0x40/* 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


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

2016-04-02 Thread Kirill A. Shutemov
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_FIXED0x10/* Interpret addr exactly */
>  #define MAP_ANONYMOUS0x20/* don't use a file */
> +#define MAP_DONTUNMAP0x40/* 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


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

2016-04-02 Thread Piotr Kwapulinski
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 
---
 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 0x400   /* 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, , _link,
  _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



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

2016-04-02 Thread Piotr Kwapulinski
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 
---
 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 0x400   /* 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, , _link,
  _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