diff options
author | Hugh Dickins <hughd@google.com> | 2016-07-26 18:26:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-26 19:19:19 -0400 |
commit | c01d5b300774d130a24d787825b01eb24e6e20cb (patch) | |
tree | e56b92aa5cf8f25ab812da30db5b36a6126e877b /drivers/char/mem.c | |
parent | 5a6e75f8110c97e2a5488894d4e922187e6cb343 (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 'drivers/char/mem.c')
-rw-r--r-- | drivers/char/mem.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index d633974e7f8b..a33163dbb913 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
23 | #include <linux/highmem.h> | 23 | #include <linux/highmem.h> |
24 | #include <linux/backing-dev.h> | 24 | #include <linux/backing-dev.h> |
25 | #include <linux/shmem_fs.h> | ||
25 | #include <linux/splice.h> | 26 | #include <linux/splice.h> |
26 | #include <linux/pfn.h> | 27 | #include <linux/pfn.h> |
27 | #include <linux/export.h> | 28 | #include <linux/export.h> |
@@ -657,6 +658,28 @@ static int mmap_zero(struct file *file, struct vm_area_struct *vma) | |||
657 | return 0; | 658 | return 0; |
658 | } | 659 | } |
659 | 660 | ||
661 | static unsigned long get_unmapped_area_zero(struct file *file, | ||
662 | unsigned long addr, unsigned long len, | ||
663 | unsigned long pgoff, unsigned long flags) | ||
664 | { | ||
665 | #ifdef CONFIG_MMU | ||
666 | if (flags & MAP_SHARED) { | ||
667 | /* | ||
668 | * mmap_zero() will call shmem_zero_setup() to create a file, | ||
669 | * so use shmem's get_unmapped_area in case it can be huge; | ||
670 | * and pass NULL for file as in mmap.c's get_unmapped_area(), | ||
671 | * so as not to confuse shmem with our handle on "/dev/zero". | ||
672 | */ | ||
673 | return shmem_get_unmapped_area(NULL, addr, len, pgoff, flags); | ||
674 | } | ||
675 | |||
676 | /* Otherwise flags & MAP_PRIVATE: with no shmem object beneath it */ | ||
677 | return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); | ||
678 | #else | ||
679 | return -ENOSYS; | ||
680 | #endif | ||
681 | } | ||
682 | |||
660 | static ssize_t write_full(struct file *file, const char __user *buf, | 683 | static ssize_t write_full(struct file *file, const char __user *buf, |
661 | size_t count, loff_t *ppos) | 684 | size_t count, loff_t *ppos) |
662 | { | 685 | { |
@@ -764,6 +787,7 @@ static const struct file_operations zero_fops = { | |||
764 | .read_iter = read_iter_zero, | 787 | .read_iter = read_iter_zero, |
765 | .write_iter = write_iter_zero, | 788 | .write_iter = write_iter_zero, |
766 | .mmap = mmap_zero, | 789 | .mmap = mmap_zero, |
790 | .get_unmapped_area = get_unmapped_area_zero, | ||
767 | #ifndef CONFIG_MMU | 791 | #ifndef CONFIG_MMU |
768 | .mmap_capabilities = zero_mmap_capabilities, | 792 | .mmap_capabilities = zero_mmap_capabilities, |
769 | #endif | 793 | #endif |