summaryrefslogtreecommitdiffstats
path: root/mm/mmap.c
diff options
context:
space:
mode:
authorHugh Dickins <hughd@google.com>2016-07-26 18:26:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-26 19:19:19 -0400
commitc01d5b300774d130a24d787825b01eb24e6e20cb (patch)
treee56b92aa5cf8f25ab812da30db5b36a6126e877b /mm/mmap.c
parent5a6e75f8110c97e2a5488894d4e922187e6cb343 (diff)
shmem: get_unmapped_area align huge page
Provide a shmem_get_unmapped_area method in file_operations, called at mmap time to decide the mapping address. It could be conditional on CONFIG_TRANSPARENT_HUGEPAGE, but save #ifdefs in other places by making it unconditional. shmem_get_unmapped_area() first calls the usual mm->get_unmapped_area (which we treat as a black box, highly dependent on architecture and config and executable layout). Lots of conditions, and in most cases it just goes with the address that chose; but when our huge stars are rightly aligned, yet that did not provide a suitable address, go back to ask for a larger arena, within which to align the mapping suitably. There have to be some direct calls to shmem_get_unmapped_area(), not via the file_operations: because of the way shmem_zero_setup() is called to create a shmem object late in the mmap sequence, when MAP_SHARED is requested with MAP_ANONYMOUS or /dev/zero. Though this only matters when /proc/sys/vm/shmem_huge has been set. Link: http://lkml.kernel.org/r/1466021202-61880-29-git-send-email-kirill.shutemov@linux.intel.com Signed-off-by: Hugh Dickins <hughd@google.com> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/mmap.c')
-rw-r--r--mm/mmap.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/mm/mmap.c b/mm/mmap.c
index a41872c8f2af..86b18f334f4f 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -25,6 +25,7 @@
25#include <linux/personality.h> 25#include <linux/personality.h>
26#include <linux/security.h> 26#include <linux/security.h>
27#include <linux/hugetlb.h> 27#include <linux/hugetlb.h>
28#include <linux/shmem_fs.h>
28#include <linux/profile.h> 29#include <linux/profile.h>
29#include <linux/export.h> 30#include <linux/export.h>
30#include <linux/mount.h> 31#include <linux/mount.h>
@@ -1897,8 +1898,19 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
1897 return -ENOMEM; 1898 return -ENOMEM;
1898 1899
1899 get_area = current->mm->get_unmapped_area; 1900 get_area = current->mm->get_unmapped_area;
1900 if (file && file->f_op->get_unmapped_area) 1901 if (file) {
1901 get_area = file->f_op->get_unmapped_area; 1902 if (file->f_op->get_unmapped_area)
1903 get_area = file->f_op->get_unmapped_area;
1904 } else if (flags & MAP_SHARED) {
1905 /*
1906 * mmap_region() will call shmem_zero_setup() to create a file,
1907 * so use shmem's get_unmapped_area in case it can be huge.
1908 * do_mmap_pgoff() will clear pgoff, so match alignment.
1909 */
1910 pgoff = 0;
1911 get_area = shmem_get_unmapped_area;
1912 }
1913
1902 addr = get_area(file, addr, len, pgoff, flags); 1914 addr = get_area(file, addr, len, pgoff, flags);
1903 if (IS_ERR_VALUE(addr)) 1915 if (IS_ERR_VALUE(addr))
1904 return addr; 1916 return addr;