Bug 8691

Summary: mremap: Wrong behaviour expanding a MAP_SHARED anonymous mapping
Product: Memory Management Reporter: William Tambe (tambewilliam)
Component: OtherAssignee: Andrew Morton (akpm)
Status: NEW ---    
Severity: blocking CC: alan, eugeneteo, firogm, gangadharan, riel, shrajan
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 3.4 Subsystem:
Regression: No Bisected commit-id:

Description William Tambe 2007-06-29 17:42:37 UTC
Most recent kernel where this bug did not occur:
Distribution:
Hardware Environment:
Software Environment: glibc-2.5 gcc-4.1.2

Problem Description:
bus error when trying to access page created by mremap()

Steps to reproduce:
In the code below, I mmap() a single page of 4096 and simply mremap() the same
page to 2*4096 which is 8192.

Then when I try to write anywhere after 4096 bytes, in the newly expanded area.
I get Bus error.

Can somebody please help me?


#define _GNU_SOURCE
#include <sys/mman.h>
#include <unistd.h>

#include <stdio.h>

main() {
        void *ptr;
        if ((ptr=mmap(0, 4096, PROT_READ|PROT_WRITE,
                MAP_ANONYMOUS|MAP_SHARED|MAP_GROWSDOWN, 0, 0)) == -1) {
                printf("failed to mmap\n");
                return;
        }

        if ((ptr=mremap(ptr, 4096, 8192, MREMAP_MAYMOVE)) == -1) {
                printf("failed to mremap\n");
                return;
        }
        
        //why does this failed. I am well in the interval [4096, 8192]
        *(unsigned int *)(ptr + 4096 + 8)= 10;
}
Comment 1 William Tambe 2007-07-01 19:47:35 UTC
Subject: Re:  New: bus error when trying to access page created
 by mremap()

I don't mean to press anybody, but please, can somebody help to find a 
work around if there is not immediate solutions.

Sincerely,
William Tambe

bugme-daemon@bugzilla.kernel.org wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=8691
> 
>            Summary: bus error when trying to access page created by mremap()
>            Product: Memory Management
>            Version: 2.5
>      KernelVersion: 2.6.21.5
>           Platform: All
>         OS/Version: Linux
>               Tree: Mainline
>             Status: NEW
>           Severity: blocking
>           Priority: P1
>          Component: Page Allocator
>         AssignedTo: akpm@osdl.org
>         ReportedBy: tambewilliam@gmail.com
> 
> 
> Most recent kernel where this bug did not occur:
> Distribution:
> Hardware Environment:
> Software Environment: glibc-2.5 gcc-4.1.2
> 
> Problem Description:
> bus error when trying to access page created by mremap()
> 
> Steps to reproduce:
> In the code below, I mmap() a single page of 4096 and simply mremap() the
> same
> page to 2*4096 which is 8192.
> 
> Then when I try to write anywhere after 4096 bytes, in the newly expanded
> area.
> I get Bus error.
> 
> Can somebody please help me?
> 
> 
> #define _GNU_SOURCE
> #include <sys/mman.h>
> #include <unistd.h>
> 
> #include <stdio.h>
> 
> main() {
>         void *ptr;
>         if ((ptr=mmap(0, 4096, PROT_READ|PROT_WRITE,
>                 MAP_ANONYMOUS|MAP_SHARED|MAP_GROWSDOWN, 0, 0)) == -1) {
>                 printf("failed to mmap\n");
>                 return;
>         }
> 
>         if ((ptr=mremap(ptr, 4096, 8192, MREMAP_MAYMOVE)) == -1) {
>                 printf("failed to mremap\n");
>                 return;
>         }
> 
>         //why does this failed. I am well in the interval [4096, 8192]
>         *(unsigned int *)(ptr + 4096 + 8)= 10;
> }
> 
> 
Comment 2 Andrew Morton 2007-07-01 21:30:16 UTC
Subject: Re:  bus error when trying to access page created by
 mremap()

On Sun,  1 Jul 2007 19:43:25 -0700 (PDT) bugme-daemon@bugzilla.kernel.org wrote:

> http://bugzilla.kernel.org/show_bug.cgi?id=8691
> 
> 
> 
> 
> 
> ------- Comment #1 from tambewilliam@gmail.com  2007-07-01 19:47 -------
> Subject: Re:  New: bus error when trying to access page created
>  by mremap()
> 
> I don't mean to press anybody, but please, can somebody help to find a 
> work around if there is not immediate solutions.
> 
> Sincerely,
> William Tambe
> 
> bugme-daemon@bugzilla.kernel.org wrote:
> > http://bugzilla.kernel.org/show_bug.cgi?id=8691
> > 
> >            Summary: bus error when trying to access page created by
> mremap()
> >            Product: Memory Management
> >            Version: 2.5
> >      KernelVersion: 2.6.21.5
> >           Platform: All
> >         OS/Version: Linux
> >               Tree: Mainline
> >             Status: NEW
> >           Severity: blocking
> >           Priority: P1
> >          Component: Page Allocator
> >         AssignedTo: akpm@osdl.org
> >         ReportedBy: tambewilliam@gmail.com
> > 
> > 
> > Most recent kernel where this bug did not occur:
> > Distribution:
> > Hardware Environment:
> > Software Environment: glibc-2.5 gcc-4.1.2
> > 
> > Problem Description:
> > bus error when trying to access page created by mremap()
> > 
> > Steps to reproduce:
> > In the code below, I mmap() a single page of 4096 and simply mremap() the
> same
> > page to 2*4096 which is 8192.
> > 
> > Then when I try to write anywhere after 4096 bytes, in the newly expanded
> area.
> > I get Bus error.
> > 
> > Can somebody please help me?
> > 
> > 
> > #define _GNU_SOURCE
> > #include <sys/mman.h>
> > #include <unistd.h>
> > 
> > #include <stdio.h>
> > 
> > main() {
> >         void *ptr;
> >         if ((ptr=mmap(0, 4096, PROT_READ|PROT_WRITE,
> >                 MAP_ANONYMOUS|MAP_SHARED|MAP_GROWSDOWN, 0, 0)) == -1) {
> >                 printf("failed to mmap\n");
> >                 return;
> >         }
> > 
> >         if ((ptr=mremap(ptr, 4096, 8192, MREMAP_MAYMOVE)) == -1) {
> >                 printf("failed to mremap\n");
> >                 return;
> >         }
> > 
> >         //why does this failed. I am well in the interval [4096, 8192]
> >         *(unsigned int *)(ptr + 4096 + 8)= 10;
> > }
> > 
> > 

maybe mremap() failed and your (incorrect) comparison with -1 didn't
detect it.  Try using MAP_FAILED as the manpage says.
Comment 3 William Tambe 2007-07-01 22:22:35 UTC
Subject: Re:  bus error when trying to access page created by mremap()

I did replace -1 with MAP_FAILED but it does the same thing: Bus error.

Even if mremap() had failed while I using -1, I would have gotten 
instead a segmentation fault. But I get a Bus error. I am guessing that 
the new expended memory area, is not backed by any kind of actual memory 
(shared memory or file)
I am not a kernel expert, I am just guessing.

Please I need help.

Sincerely,
William Tambe


bugme-daemon@bugzilla.kernel.org wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=8691
> 
> 
> 
> 
> 
> ------- Comment #2 from akpm@osdl.org  2007-07-01 21:30 -------
> Subject: Re:  bus error when trying to access page created by
>  mremap()
> 
> On Sun,  1 Jul 2007 19:43:25 -0700 (PDT) bugme-daemon@bugzilla.kernel.org
> wrote:
> 
>> http://bugzilla.kernel.org/show_bug.cgi?id=8691
>>
>>
>>
>>
>>
>> ------- Comment #1 from tambewilliam@gmail.com  2007-07-01 19:47 -------
>> Subject: Re:  New: bus error when trying to access page created
>>  by mremap()
>>
>> I don't mean to press anybody, but please, can somebody help to find a 
>> work around if there is not immediate solutions.
>>
>> Sincerely,
>> William Tambe
>>
>> bugme-daemon@bugzilla.kernel.org wrote:
>>> http://bugzilla.kernel.org/show_bug.cgi?id=8691
>>>
>>>            Summary: bus error when trying to access page created by
>>>            mremap()
>>>            Product: Memory Management
>>>            Version: 2.5
>>>      KernelVersion: 2.6.21.5
>>>           Platform: All
>>>         OS/Version: Linux
>>>               Tree: Mainline
>>>             Status: NEW
>>>           Severity: blocking
>>>           Priority: P1
>>>          Component: Page Allocator
>>>         AssignedTo: akpm@osdl.org
>>>         ReportedBy: tambewilliam@gmail.com
>>>
>>>
>>> Most recent kernel where this bug did not occur:
>>> Distribution:
>>> Hardware Environment:
>>> Software Environment: glibc-2.5 gcc-4.1.2
>>>
>>> Problem Description:
>>> bus error when trying to access page created by mremap()
>>>
>>> Steps to reproduce:
>>> In the code below, I mmap() a single page of 4096 and simply mremap() the
>>> same
>>> page to 2*4096 which is 8192.
>>>
>>> Then when I try to write anywhere after 4096 bytes, in the newly expanded
>>> area.
>>> I get Bus error.
>>>
>>> Can somebody please help me?
>>>
>>>
>>> #define _GNU_SOURCE
>>> #include <sys/mman.h>
>>> #include <unistd.h>
>>>
>>> #include <stdio.h>
>>>
>>> main() {
>>>         void *ptr;
>>>         if ((ptr=mmap(0, 4096, PROT_READ|PROT_WRITE,
>>>                 MAP_ANONYMOUS|MAP_SHARED|MAP_GROWSDOWN, 0, 0)) == -1) {
>>>                 printf("failed to mmap\n");
>>>                 return;
>>>         }
>>>
>>>         if ((ptr=mremap(ptr, 4096, 8192, MREMAP_MAYMOVE)) == -1) {
>>>                 printf("failed to mremap\n");
>>>                 return;
>>>         }
>>>
>>>         //why does this failed. I am well in the interval [4096, 8192]
>>>         *(unsigned int *)(ptr + 4096 + 8)= 10;
>>> }
>>>
>>>
> 
> maybe mremap() failed and your (incorrect) comparison with -1 didn't
> detect it.  Try using MAP_FAILED as the manpage says.
> 
> 
Comment 4 Alan 2008-09-23 05:40:32 UTC
Verified - critical element is that MAP_SHARED is set
Comment 5 Gangadharan S.A. 2008-10-28 11:50:05 UTC
Yes, the file in shmemfs is not being grown along with the vm_area_struct.
As a result, we fail the check at shmem_fault ( http://lxr.linux.no/linux+v2.6.27/mm/shmem.c#L1441 )

The question I have is, what is right behavior when one grows a shared mapping with mremap?

If it is to grow the shmemfs file backing the vm_area_struct, then:
How about invoking shmem_file_setup with size=SHMEM_MAX_BYTES or some such when initially creating the file at shmem_zero_setup? ( http://lxr.linux.no/linux+v2.6.27/mm/shmem.c#L2595 ).
That way, the file will grow by itself whenever someone mremaps it (and then accesses any address from the new page frames).

I would be interested in implementing this fix or any other, if there is something better. Please let me know if the above sounds like a good idea.
Comment 6 Rik van Riel 2008-10-30 14:47:47 UTC
Creating the shmem segment with SMEM_MAX_BYTES is not going to work, due to the call to shmem_acct_size in shmem_file_setup.

I suspect we will have to teach mremap to resize the shmem segment.

Refusing to grow a MAP_ANONYMOUS|MAP_SHARED region through mremap might break applications (I'm not sure that it will, though).
Comment 7 Gangadharan S.A. 2008-11-01 03:17:38 UTC
> I suspect we will have to teach mremap to resize the shmem segment.

I guess we could do this by checking for a shmem backing file for the vma in do_mremap and then truncating the file to the new size. 

But then, what if one of the processes sharing the shmem segment shrinks it? Now the other processes will start getting bus errors when they try to access the now-truncated-out part of the the shmem file.
Comment 8 Gangadharan S.A. 2008-12-07 06:00:54 UTC
If anyone can tell me what the right behavior is supposed to be, I will be happy to try and write a fix
Comment 9 supercool1251 2010-04-03 20:41:29 UTC
If we decrease the shmem backing file size and some other process gets a bus error then isnt it a programming error.