Commit f83a275dbc5ca1721143698e844243fcadfabf6a
Committed by
Linus Torvalds
1 parent
32b154c0b0
Exists in
master
and in
4 other branches
mm: account for MAP_SHARED mappings using VM_MAYSHARE and not VM_SHARED in hugetlbfs
Addresses http://bugzilla.kernel.org/show_bug.cgi?id=13302 hugetlbfs reserves huge pages but does not fault them at mmap() time to ensure that future faults succeed. The reservation behaviour differs depending on whether the mapping was mapped MAP_SHARED or MAP_PRIVATE. For MAP_SHARED mappings, hugepages are reserved when mmap() is first called and are tracked based on information associated with the inode. Other processes mapping MAP_SHARED use the same reservation. MAP_PRIVATE track the reservations based on the VMA created as part of the mmap() operation. Each process mapping MAP_PRIVATE must make its own reservation. hugetlbfs currently checks if a VMA is MAP_SHARED with the VM_SHARED flag and not VM_MAYSHARE. For file-backed mappings, such as hugetlbfs, VM_SHARED is set only if the mapping is MAP_SHARED and the file was opened read-write. If a shared memory mapping was mapped shared-read-write for populating of data and mapped shared-read-only by other processes, then hugetlbfs would account for the mapping as if it was MAP_PRIVATE. This causes processes to fail to map the file MAP_SHARED even though it should succeed as the reservation is there. This patch alters mm/hugetlb.c and replaces VM_SHARED with VM_MAYSHARE when the intent of the code was to check whether the VMA was mapped MAP_SHARED or MAP_PRIVATE. Signed-off-by: Mel Gorman <mel@csn.ul.ie> Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk> Cc: Ingo Molnar <mingo@elte.hu> Cc: <stable@kernel.org> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: <starlight@binnacle.cx> Cc: Eric B Munson <ebmunson@us.ibm.com> Cc: Adam Litke <agl@us.ibm.com> Cc: Andy Whitcroft <apw@canonical.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 13 additions and 13 deletions Side-by-side Diff
mm/hugetlb.c
... | ... | @@ -316,7 +316,7 @@ |
316 | 316 | static struct resv_map *vma_resv_map(struct vm_area_struct *vma) |
317 | 317 | { |
318 | 318 | VM_BUG_ON(!is_vm_hugetlb_page(vma)); |
319 | - if (!(vma->vm_flags & VM_SHARED)) | |
319 | + if (!(vma->vm_flags & VM_MAYSHARE)) | |
320 | 320 | return (struct resv_map *)(get_vma_private_data(vma) & |
321 | 321 | ~HPAGE_RESV_MASK); |
322 | 322 | return NULL; |
... | ... | @@ -325,7 +325,7 @@ |
325 | 325 | static void set_vma_resv_map(struct vm_area_struct *vma, struct resv_map *map) |
326 | 326 | { |
327 | 327 | VM_BUG_ON(!is_vm_hugetlb_page(vma)); |
328 | - VM_BUG_ON(vma->vm_flags & VM_SHARED); | |
328 | + VM_BUG_ON(vma->vm_flags & VM_MAYSHARE); | |
329 | 329 | |
330 | 330 | set_vma_private_data(vma, (get_vma_private_data(vma) & |
331 | 331 | HPAGE_RESV_MASK) | (unsigned long)map); |
... | ... | @@ -334,7 +334,7 @@ |
334 | 334 | static void set_vma_resv_flags(struct vm_area_struct *vma, unsigned long flags) |
335 | 335 | { |
336 | 336 | VM_BUG_ON(!is_vm_hugetlb_page(vma)); |
337 | - VM_BUG_ON(vma->vm_flags & VM_SHARED); | |
337 | + VM_BUG_ON(vma->vm_flags & VM_MAYSHARE); | |
338 | 338 | |
339 | 339 | set_vma_private_data(vma, get_vma_private_data(vma) | flags); |
340 | 340 | } |
... | ... | @@ -353,7 +353,7 @@ |
353 | 353 | if (vma->vm_flags & VM_NORESERVE) |
354 | 354 | return; |
355 | 355 | |
356 | - if (vma->vm_flags & VM_SHARED) { | |
356 | + if (vma->vm_flags & VM_MAYSHARE) { | |
357 | 357 | /* Shared mappings always use reserves */ |
358 | 358 | h->resv_huge_pages--; |
359 | 359 | } else if (is_vma_resv_set(vma, HPAGE_RESV_OWNER)) { |
360 | 360 | |
... | ... | @@ -369,14 +369,14 @@ |
369 | 369 | void reset_vma_resv_huge_pages(struct vm_area_struct *vma) |
370 | 370 | { |
371 | 371 | VM_BUG_ON(!is_vm_hugetlb_page(vma)); |
372 | - if (!(vma->vm_flags & VM_SHARED)) | |
372 | + if (!(vma->vm_flags & VM_MAYSHARE)) | |
373 | 373 | vma->vm_private_data = (void *)0; |
374 | 374 | } |
375 | 375 | |
376 | 376 | /* Returns true if the VMA has associated reserve pages */ |
377 | 377 | static int vma_has_reserves(struct vm_area_struct *vma) |
378 | 378 | { |
379 | - if (vma->vm_flags & VM_SHARED) | |
379 | + if (vma->vm_flags & VM_MAYSHARE) | |
380 | 380 | return 1; |
381 | 381 | if (is_vma_resv_set(vma, HPAGE_RESV_OWNER)) |
382 | 382 | return 1; |
... | ... | @@ -924,7 +924,7 @@ |
924 | 924 | struct address_space *mapping = vma->vm_file->f_mapping; |
925 | 925 | struct inode *inode = mapping->host; |
926 | 926 | |
927 | - if (vma->vm_flags & VM_SHARED) { | |
927 | + if (vma->vm_flags & VM_MAYSHARE) { | |
928 | 928 | pgoff_t idx = vma_hugecache_offset(h, vma, addr); |
929 | 929 | return region_chg(&inode->i_mapping->private_list, |
930 | 930 | idx, idx + 1); |
... | ... | @@ -949,7 +949,7 @@ |
949 | 949 | struct address_space *mapping = vma->vm_file->f_mapping; |
950 | 950 | struct inode *inode = mapping->host; |
951 | 951 | |
952 | - if (vma->vm_flags & VM_SHARED) { | |
952 | + if (vma->vm_flags & VM_MAYSHARE) { | |
953 | 953 | pgoff_t idx = vma_hugecache_offset(h, vma, addr); |
954 | 954 | region_add(&inode->i_mapping->private_list, idx, idx + 1); |
955 | 955 | |
... | ... | @@ -1893,7 +1893,7 @@ |
1893 | 1893 | * at the time of fork() could consume its reserves on COW instead |
1894 | 1894 | * of the full address range. |
1895 | 1895 | */ |
1896 | - if (!(vma->vm_flags & VM_SHARED) && | |
1896 | + if (!(vma->vm_flags & VM_MAYSHARE) && | |
1897 | 1897 | is_vma_resv_set(vma, HPAGE_RESV_OWNER) && |
1898 | 1898 | old_page != pagecache_page) |
1899 | 1899 | outside_reserve = 1; |
... | ... | @@ -2000,7 +2000,7 @@ |
2000 | 2000 | clear_huge_page(page, address, huge_page_size(h)); |
2001 | 2001 | __SetPageUptodate(page); |
2002 | 2002 | |
2003 | - if (vma->vm_flags & VM_SHARED) { | |
2003 | + if (vma->vm_flags & VM_MAYSHARE) { | |
2004 | 2004 | int err; |
2005 | 2005 | struct inode *inode = mapping->host; |
2006 | 2006 | |
... | ... | @@ -2104,7 +2104,7 @@ |
2104 | 2104 | goto out_mutex; |
2105 | 2105 | } |
2106 | 2106 | |
2107 | - if (!(vma->vm_flags & VM_SHARED)) | |
2107 | + if (!(vma->vm_flags & VM_MAYSHARE)) | |
2108 | 2108 | pagecache_page = hugetlbfs_pagecache_page(h, |
2109 | 2109 | vma, address); |
2110 | 2110 | } |
... | ... | @@ -2289,7 +2289,7 @@ |
2289 | 2289 | * to reserve the full area even if read-only as mprotect() may be |
2290 | 2290 | * called to make the mapping read-write. Assume !vma is a shm mapping |
2291 | 2291 | */ |
2292 | - if (!vma || vma->vm_flags & VM_SHARED) | |
2292 | + if (!vma || vma->vm_flags & VM_MAYSHARE) | |
2293 | 2293 | chg = region_chg(&inode->i_mapping->private_list, from, to); |
2294 | 2294 | else { |
2295 | 2295 | struct resv_map *resv_map = resv_map_alloc(); |
... | ... | @@ -2330,7 +2330,7 @@ |
2330 | 2330 | * consumed reservations are stored in the map. Hence, nothing |
2331 | 2331 | * else has to be done for private mappings here |
2332 | 2332 | */ |
2333 | - if (!vma || vma->vm_flags & VM_SHARED) | |
2333 | + if (!vma || vma->vm_flags & VM_MAYSHARE) | |
2334 | 2334 | region_add(&inode->i_mapping->private_list, from, to); |
2335 | 2335 | return 0; |
2336 | 2336 | } |