diff options
author | Andi Kleen <ak@linux.intel.com> | 2012-12-11 19:01:34 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 20:22:25 -0500 |
commit | 42d7395feb56f0655cd8b68e06fc6063823449f8 (patch) | |
tree | 47cfbad1737d98d9752a2aab7e525f1fe5194d27 /include | |
parent | ff604cf6d41f1e05f34762e1d764fe14a0f5f964 (diff) |
mm: support more pagesizes for MAP_HUGETLB/SHM_HUGETLB
There was some desire in large applications using MAP_HUGETLB or
SHM_HUGETLB to use 1GB huge pages on some mappings, and stay with 2MB on
others. This is useful together with NUMA policy: use 2MB interleaving
on some mappings, but 1GB on local mappings.
This patch extends the IPC/SHM syscall interfaces slightly to allow
specifying the page size.
It borrows some upper bits in the existing flag arguments and allows
encoding the log of the desired page size in addition to the *_HUGETLB
flag. When 0 is specified the default size is used, this makes the
change fully compatible.
Extending the internal hugetlb code to handle this is straight forward.
Instead of a single mount it just keeps an array of them and selects the
right mount based on the specified page size. When no page size is
specified it uses the mount of the default page size.
The change is not visible in /proc/mounts because internal mounts don't
appear there. It also has very little overhead: the additional mounts
just consume a super block, but not more memory when not used.
I also exported the new flags to the user headers (they were previously
under __KERNEL__). Right now only symbols for x86 and some other
architecture for 1GB and 2MB are defined. The interface should already
work for all other architectures though. Only architectures that define
multiple hugetlb sizes actually need it (that is currently x86, tile,
powerpc). However tile and powerpc have user configurable hugetlb
sizes, so it's not easy to add defines. A program on those
architectures would need to query sysfs and use the appropiate log2.
[akpm@linux-foundation.org: cleanups]
[rientjes@google.com: fix build]
[akpm@linux-foundation.org: checkpatch fixes]
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Acked-by: Rik van Riel <riel@redhat.com>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Hillf Danton <dhillf@gmail.com>
Signed-off-by: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/hugetlb.h | 7 | ||||
-rw-r--r-- | include/linux/shm.h | 15 | ||||
-rw-r--r-- | include/uapi/asm-generic/mman-common.h | 11 | ||||
-rw-r--r-- | include/uapi/asm-generic/mman.h | 2 |
4 files changed, 33 insertions, 2 deletions
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 225164842ab6..3e7fa1acf09c 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h | |||
@@ -183,7 +183,8 @@ extern const struct file_operations hugetlbfs_file_operations; | |||
183 | extern const struct vm_operations_struct hugetlb_vm_ops; | 183 | extern const struct vm_operations_struct hugetlb_vm_ops; |
184 | struct file *hugetlb_file_setup(const char *name, unsigned long addr, | 184 | struct file *hugetlb_file_setup(const char *name, unsigned long addr, |
185 | size_t size, vm_flags_t acct, | 185 | size_t size, vm_flags_t acct, |
186 | struct user_struct **user, int creat_flags); | 186 | struct user_struct **user, int creat_flags, |
187 | int page_size_log); | ||
187 | 188 | ||
188 | static inline int is_file_hugepages(struct file *file) | 189 | static inline int is_file_hugepages(struct file *file) |
189 | { | 190 | { |
@@ -195,12 +196,14 @@ static inline int is_file_hugepages(struct file *file) | |||
195 | return 0; | 196 | return 0; |
196 | } | 197 | } |
197 | 198 | ||
199 | |||
198 | #else /* !CONFIG_HUGETLBFS */ | 200 | #else /* !CONFIG_HUGETLBFS */ |
199 | 201 | ||
200 | #define is_file_hugepages(file) 0 | 202 | #define is_file_hugepages(file) 0 |
201 | static inline struct file * | 203 | static inline struct file * |
202 | hugetlb_file_setup(const char *name, unsigned long addr, size_t size, | 204 | hugetlb_file_setup(const char *name, unsigned long addr, size_t size, |
203 | vm_flags_t acctflag, struct user_struct **user, int creat_flags) | 205 | vm_flags_t acctflag, struct user_struct **user, int creat_flags, |
206 | int page_size_log) | ||
204 | { | 207 | { |
205 | return ERR_PTR(-ENOSYS); | 208 | return ERR_PTR(-ENOSYS); |
206 | } | 209 | } |
diff --git a/include/linux/shm.h b/include/linux/shm.h index bcf8a6a3ec00..429c1995d756 100644 --- a/include/linux/shm.h +++ b/include/linux/shm.h | |||
@@ -29,6 +29,21 @@ struct shmid_kernel /* private to the kernel */ | |||
29 | #define SHM_HUGETLB 04000 /* segment will use huge TLB pages */ | 29 | #define SHM_HUGETLB 04000 /* segment will use huge TLB pages */ |
30 | #define SHM_NORESERVE 010000 /* don't check for reservations */ | 30 | #define SHM_NORESERVE 010000 /* don't check for reservations */ |
31 | 31 | ||
32 | /* Bits [26:31] are reserved */ | ||
33 | |||
34 | /* | ||
35 | * When SHM_HUGETLB is set bits [26:31] encode the log2 of the huge page size. | ||
36 | * This gives us 6 bits, which is enough until someone invents 128 bit address | ||
37 | * spaces. | ||
38 | * | ||
39 | * Assume these are all power of twos. | ||
40 | * When 0 use the default page size. | ||
41 | */ | ||
42 | #define SHM_HUGE_SHIFT 26 | ||
43 | #define SHM_HUGE_MASK 0x3f | ||
44 | #define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT) | ||
45 | #define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT) | ||
46 | |||
32 | #ifdef CONFIG_SYSVIPC | 47 | #ifdef CONFIG_SYSVIPC |
33 | long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr, | 48 | long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr, |
34 | unsigned long shmlba); | 49 | unsigned long shmlba); |
diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h index d030d2c2647a..4164529a94f9 100644 --- a/include/uapi/asm-generic/mman-common.h +++ b/include/uapi/asm-generic/mman-common.h | |||
@@ -55,4 +55,15 @@ | |||
55 | /* compatibility flags */ | 55 | /* compatibility flags */ |
56 | #define MAP_FILE 0 | 56 | #define MAP_FILE 0 |
57 | 57 | ||
58 | /* | ||
59 | * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. | ||
60 | * This gives us 6 bits, which is enough until someone invents 128 bit address | ||
61 | * spaces. | ||
62 | * | ||
63 | * Assume these are all power of twos. | ||
64 | * When 0 use the default page size. | ||
65 | */ | ||
66 | #define MAP_HUGE_SHIFT 26 | ||
67 | #define MAP_HUGE_MASK 0x3f | ||
68 | |||
58 | #endif /* __ASM_GENERIC_MMAN_COMMON_H */ | 69 | #endif /* __ASM_GENERIC_MMAN_COMMON_H */ |
diff --git a/include/uapi/asm-generic/mman.h b/include/uapi/asm-generic/mman.h index 32c8bd6a196d..e9fe6fd2a074 100644 --- a/include/uapi/asm-generic/mman.h +++ b/include/uapi/asm-generic/mman.h | |||
@@ -13,6 +13,8 @@ | |||
13 | #define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */ | 13 | #define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */ |
14 | #define MAP_HUGETLB 0x40000 /* create a huge page mapping */ | 14 | #define MAP_HUGETLB 0x40000 /* create a huge page mapping */ |
15 | 15 | ||
16 | /* Bits [26:31] are reserved, see mman-common.h for MAP_HUGETLB usage */ | ||
17 | |||
16 | #define MCL_CURRENT 1 /* lock all current mappings */ | 18 | #define MCL_CURRENT 1 /* lock all current mappings */ |
17 | #define MCL_FUTURE 2 /* lock all future mappings */ | 19 | #define MCL_FUTURE 2 /* lock all future mappings */ |
18 | 20 | ||