mm: fix mbind vma merge problem
authorKOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Fri, 5 Mar 2010 21:41:57 +0000 (13:41 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 6 Mar 2010 19:26:25 +0000 (11:26 -0800)
commit9d8cebd4bcd7c3878462fdfda34bbcdeb4df7ef4
tree0f0a6dadb4430aef18f1491003d70d9351d7b619
parent93e4a89a8c987189b168a530a331ef6d0fcf07a7
mm: fix mbind vma merge problem

Strangely, current mbind() doesn't merge vma with neighbor vma although it's possible.
Unfortunately, many vma can reduce performance...

This patch fixes it.

    reproduced program
    ----------------------------------------------------------------
     #include <numaif.h>
     #include <numa.h>
     #include <sys/mman.h>
     #include <stdio.h>
     #include <unistd.h>
     #include <stdlib.h>
     #include <string.h>

    static unsigned long pagesize;

    int main(int argc, char** argv)
    {
     void* addr;
     int ch;
     int node;
     struct bitmask *nmask = numa_allocate_nodemask();
     int err;
     int node_set = 0;
     char buf[128];

     while ((ch = getopt(argc, argv, "n:")) != -1){
     switch (ch){
     case 'n':
     node = strtol(optarg, NULL, 0);
     numa_bitmask_setbit(nmask, node);
     node_set = 1;
     break;
     default:
     ;
     }
     }
     argc -= optind;
     argv += optind;

     if (!node_set)
     numa_bitmask_setbit(nmask, 0);

     pagesize = getpagesize();

     addr = mmap(NULL, pagesize*3, PROT_READ|PROT_WRITE,
         MAP_ANON|MAP_PRIVATE, 0, 0);
     if (addr == MAP_FAILED)
     perror("mmap "), exit(1);

     fprintf(stderr, "pid = %d \n" "addr = %p\n", getpid(), addr);

     /* make page populate */
     memset(addr, 0, pagesize*3);

     /* first mbind */
     err = mbind(addr+pagesize, pagesize, MPOL_BIND, nmask->maskp,
         nmask->size, MPOL_MF_MOVE_ALL);
     if (err)
     error("mbind1 ");

     /* second mbind */
     err = mbind(addr, pagesize*3, MPOL_DEFAULT, NULL, 0, 0);
     if (err)
     error("mbind2 ");

     sprintf(buf, "cat /proc/%d/maps", getpid());
     system(buf);

     return 0;
    }
    ----------------------------------------------------------------

result without this patch

addr = 0x7fe26ef09000
[snip]
7fe26ef09000-7fe26ef0a000 rw-p 00000000 00:00 0
7fe26ef0a000-7fe26ef0b000 rw-p 00000000 00:00 0
7fe26ef0b000-7fe26ef0c000 rw-p 00000000 00:00 0
7fe26ef0c000-7fe26ef0d000 rw-p 00000000 00:00 0

=> 0x7fe26ef09000-0x7fe26ef0c000 have three vmas.

result with this patch

addr = 0x7fc9ebc76000
[snip]
7fc9ebc76000-7fc9ebc7a000 rw-p 00000000 00:00 0
7fffbe690000-7fffbe6a5000 rw-p 00000000 00:00 0 [stack]

=> 0x7fc9ebc76000-0x7fc9ebc7a000 have only one vma.

[minchan.kim@gmail.com: fix file offset passed to vma_merge()]
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Reviewed-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: Lee Schermerhorn <lee.schermerhorn@hp.com>
Signed-off-by: Minchan Kim <minchan.kim@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
mm/mempolicy.c