diff options
-rw-r--r-- | arch/alpha/include/asm/mman.h | 11 | ||||
-rw-r--r-- | arch/mips/include/uapi/asm/mman.h | 11 | ||||
-rw-r--r-- | arch/parisc/include/uapi/asm/mman.h | 11 | ||||
-rw-r--r-- | arch/x86/include/asm/mman.h | 3 | ||||
-rw-r--r-- | arch/xtensa/include/uapi/asm/mman.h | 11 | ||||
-rw-r--r-- | fs/hugetlbfs/inode.c | 63 | ||||
-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 | ||||
-rw-r--r-- | ipc/shm.c | 3 | ||||
-rw-r--r-- | mm/mmap.c | 5 |
12 files changed, 135 insertions, 18 deletions
diff --git a/arch/alpha/include/asm/mman.h b/arch/alpha/include/asm/mman.h index cbeb3616a28e..0086b472bc2b 100644 --- a/arch/alpha/include/asm/mman.h +++ b/arch/alpha/include/asm/mman.h | |||
@@ -63,4 +63,15 @@ | |||
63 | /* compatibility flags */ | 63 | /* compatibility flags */ |
64 | #define MAP_FILE 0 | 64 | #define MAP_FILE 0 |
65 | 65 | ||
66 | /* | ||
67 | * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. | ||
68 | * This gives us 6 bits, which is enough until someone invents 128 bit address | ||
69 | * spaces. | ||
70 | * | ||
71 | * Assume these are all power of twos. | ||
72 | * When 0 use the default page size. | ||
73 | */ | ||
74 | #define MAP_HUGE_SHIFT 26 | ||
75 | #define MAP_HUGE_MASK 0x3f | ||
76 | |||
66 | #endif /* __ALPHA_MMAN_H__ */ | 77 | #endif /* __ALPHA_MMAN_H__ */ |
diff --git a/arch/mips/include/uapi/asm/mman.h b/arch/mips/include/uapi/asm/mman.h index 46d3da0d4b92..9a936ac9a942 100644 --- a/arch/mips/include/uapi/asm/mman.h +++ b/arch/mips/include/uapi/asm/mman.h | |||
@@ -87,4 +87,15 @@ | |||
87 | /* compatibility flags */ | 87 | /* compatibility flags */ |
88 | #define MAP_FILE 0 | 88 | #define MAP_FILE 0 |
89 | 89 | ||
90 | /* | ||
91 | * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. | ||
92 | * This gives us 6 bits, which is enough until someone invents 128 bit address | ||
93 | * spaces. | ||
94 | * | ||
95 | * Assume these are all power of twos. | ||
96 | * When 0 use the default page size. | ||
97 | */ | ||
98 | #define MAP_HUGE_SHIFT 26 | ||
99 | #define MAP_HUGE_MASK 0x3f | ||
100 | |||
90 | #endif /* _ASM_MMAN_H */ | 101 | #endif /* _ASM_MMAN_H */ |
diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h index 12219ebce869..294d251ca7b2 100644 --- a/arch/parisc/include/uapi/asm/mman.h +++ b/arch/parisc/include/uapi/asm/mman.h | |||
@@ -70,4 +70,15 @@ | |||
70 | #define MAP_FILE 0 | 70 | #define MAP_FILE 0 |
71 | #define MAP_VARIABLE 0 | 71 | #define MAP_VARIABLE 0 |
72 | 72 | ||
73 | /* | ||
74 | * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. | ||
75 | * This gives us 6 bits, which is enough until someone invents 128 bit address | ||
76 | * spaces. | ||
77 | * | ||
78 | * Assume these are all power of twos. | ||
79 | * When 0 use the default page size. | ||
80 | */ | ||
81 | #define MAP_HUGE_SHIFT 26 | ||
82 | #define MAP_HUGE_MASK 0x3f | ||
83 | |||
73 | #endif /* __PARISC_MMAN_H__ */ | 84 | #endif /* __PARISC_MMAN_H__ */ |
diff --git a/arch/x86/include/asm/mman.h b/arch/x86/include/asm/mman.h index 593e51d4643f..513b05f15bb4 100644 --- a/arch/x86/include/asm/mman.h +++ b/arch/x86/include/asm/mman.h | |||
@@ -3,6 +3,9 @@ | |||
3 | 3 | ||
4 | #define MAP_32BIT 0x40 /* only give out 32bit addresses */ | 4 | #define MAP_32BIT 0x40 /* only give out 32bit addresses */ |
5 | 5 | ||
6 | #define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT) | ||
7 | #define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) | ||
8 | |||
6 | #include <asm-generic/mman.h> | 9 | #include <asm-generic/mman.h> |
7 | 10 | ||
8 | #endif /* _ASM_X86_MMAN_H */ | 11 | #endif /* _ASM_X86_MMAN_H */ |
diff --git a/arch/xtensa/include/uapi/asm/mman.h b/arch/xtensa/include/uapi/asm/mman.h index 25bc6c1309c3..00eed6786d7e 100644 --- a/arch/xtensa/include/uapi/asm/mman.h +++ b/arch/xtensa/include/uapi/asm/mman.h | |||
@@ -93,4 +93,15 @@ | |||
93 | /* compatibility flags */ | 93 | /* compatibility flags */ |
94 | #define MAP_FILE 0 | 94 | #define MAP_FILE 0 |
95 | 95 | ||
96 | /* | ||
97 | * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. | ||
98 | * This gives us 6 bits, which is enough until someone invents 128 bit address | ||
99 | * spaces. | ||
100 | * | ||
101 | * Assume these are all power of twos. | ||
102 | * When 0 use the default page size. | ||
103 | */ | ||
104 | #define MAP_HUGE_SHIFT 26 | ||
105 | #define MAP_HUGE_MASK 0x3f | ||
106 | |||
96 | #endif /* _XTENSA_MMAN_H */ | 107 | #endif /* _XTENSA_MMAN_H */ |
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index c5bc355d8243..21b8a4875237 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -923,7 +923,7 @@ static struct file_system_type hugetlbfs_fs_type = { | |||
923 | .kill_sb = kill_litter_super, | 923 | .kill_sb = kill_litter_super, |
924 | }; | 924 | }; |
925 | 925 | ||
926 | static struct vfsmount *hugetlbfs_vfsmount; | 926 | static struct vfsmount *hugetlbfs_vfsmount[HUGE_MAX_HSTATE]; |
927 | 927 | ||
928 | static int can_do_hugetlb_shm(void) | 928 | static int can_do_hugetlb_shm(void) |
929 | { | 929 | { |
@@ -932,9 +932,22 @@ static int can_do_hugetlb_shm(void) | |||
932 | return capable(CAP_IPC_LOCK) || in_group_p(shm_group); | 932 | return capable(CAP_IPC_LOCK) || in_group_p(shm_group); |
933 | } | 933 | } |
934 | 934 | ||
935 | static int get_hstate_idx(int page_size_log) | ||
936 | { | ||
937 | struct hstate *h; | ||
938 | |||
939 | if (!page_size_log) | ||
940 | return default_hstate_idx; | ||
941 | h = size_to_hstate(1 << page_size_log); | ||
942 | if (!h) | ||
943 | return -1; | ||
944 | return h - hstates; | ||
945 | } | ||
946 | |||
935 | struct file *hugetlb_file_setup(const char *name, unsigned long addr, | 947 | struct file *hugetlb_file_setup(const char *name, unsigned long addr, |
936 | size_t size, vm_flags_t acctflag, | 948 | size_t size, vm_flags_t acctflag, |
937 | struct user_struct **user, int creat_flags) | 949 | struct user_struct **user, |
950 | int creat_flags, int page_size_log) | ||
938 | { | 951 | { |
939 | int error = -ENOMEM; | 952 | int error = -ENOMEM; |
940 | struct file *file; | 953 | struct file *file; |
@@ -944,9 +957,14 @@ struct file *hugetlb_file_setup(const char *name, unsigned long addr, | |||
944 | struct qstr quick_string; | 957 | struct qstr quick_string; |
945 | struct hstate *hstate; | 958 | struct hstate *hstate; |
946 | unsigned long num_pages; | 959 | unsigned long num_pages; |
960 | int hstate_idx; | ||
961 | |||
962 | hstate_idx = get_hstate_idx(page_size_log); | ||
963 | if (hstate_idx < 0) | ||
964 | return ERR_PTR(-ENODEV); | ||
947 | 965 | ||
948 | *user = NULL; | 966 | *user = NULL; |
949 | if (!hugetlbfs_vfsmount) | 967 | if (!hugetlbfs_vfsmount[hstate_idx]) |
950 | return ERR_PTR(-ENOENT); | 968 | return ERR_PTR(-ENOENT); |
951 | 969 | ||
952 | if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) { | 970 | if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) { |
@@ -963,7 +981,7 @@ struct file *hugetlb_file_setup(const char *name, unsigned long addr, | |||
963 | } | 981 | } |
964 | } | 982 | } |
965 | 983 | ||
966 | root = hugetlbfs_vfsmount->mnt_root; | 984 | root = hugetlbfs_vfsmount[hstate_idx]->mnt_root; |
967 | quick_string.name = name; | 985 | quick_string.name = name; |
968 | quick_string.len = strlen(quick_string.name); | 986 | quick_string.len = strlen(quick_string.name); |
969 | quick_string.hash = 0; | 987 | quick_string.hash = 0; |
@@ -971,7 +989,7 @@ struct file *hugetlb_file_setup(const char *name, unsigned long addr, | |||
971 | if (!path.dentry) | 989 | if (!path.dentry) |
972 | goto out_shm_unlock; | 990 | goto out_shm_unlock; |
973 | 991 | ||
974 | path.mnt = mntget(hugetlbfs_vfsmount); | 992 | path.mnt = mntget(hugetlbfs_vfsmount[hstate_idx]); |
975 | error = -ENOSPC; | 993 | error = -ENOSPC; |
976 | inode = hugetlbfs_get_inode(root->d_sb, NULL, S_IFREG | S_IRWXUGO, 0); | 994 | inode = hugetlbfs_get_inode(root->d_sb, NULL, S_IFREG | S_IRWXUGO, 0); |
977 | if (!inode) | 995 | if (!inode) |
@@ -1011,8 +1029,9 @@ out_shm_unlock: | |||
1011 | 1029 | ||
1012 | static int __init init_hugetlbfs_fs(void) | 1030 | static int __init init_hugetlbfs_fs(void) |
1013 | { | 1031 | { |
1032 | struct hstate *h; | ||
1014 | int error; | 1033 | int error; |
1015 | struct vfsmount *vfsmount; | 1034 | int i; |
1016 | 1035 | ||
1017 | error = bdi_init(&hugetlbfs_backing_dev_info); | 1036 | error = bdi_init(&hugetlbfs_backing_dev_info); |
1018 | if (error) | 1037 | if (error) |
@@ -1029,14 +1048,26 @@ static int __init init_hugetlbfs_fs(void) | |||
1029 | if (error) | 1048 | if (error) |
1030 | goto out; | 1049 | goto out; |
1031 | 1050 | ||
1032 | vfsmount = kern_mount(&hugetlbfs_fs_type); | 1051 | i = 0; |
1052 | for_each_hstate(h) { | ||
1053 | char buf[50]; | ||
1054 | unsigned ps_kb = 1U << (h->order + PAGE_SHIFT - 10); | ||
1033 | 1055 | ||
1034 | if (!IS_ERR(vfsmount)) { | 1056 | snprintf(buf, sizeof(buf), "pagesize=%uK", ps_kb); |
1035 | hugetlbfs_vfsmount = vfsmount; | 1057 | hugetlbfs_vfsmount[i] = kern_mount_data(&hugetlbfs_fs_type, |
1036 | return 0; | 1058 | buf); |
1037 | } | ||
1038 | 1059 | ||
1039 | error = PTR_ERR(vfsmount); | 1060 | if (IS_ERR(hugetlbfs_vfsmount[i])) { |
1061 | pr_err("hugetlb: Cannot mount internal hugetlbfs for " | ||
1062 | "page size %uK", ps_kb); | ||
1063 | error = PTR_ERR(hugetlbfs_vfsmount[i]); | ||
1064 | hugetlbfs_vfsmount[i] = NULL; | ||
1065 | } | ||
1066 | i++; | ||
1067 | } | ||
1068 | /* Non default hstates are optional */ | ||
1069 | if (!IS_ERR_OR_NULL(hugetlbfs_vfsmount[default_hstate_idx])) | ||
1070 | return 0; | ||
1040 | 1071 | ||
1041 | out: | 1072 | out: |
1042 | kmem_cache_destroy(hugetlbfs_inode_cachep); | 1073 | kmem_cache_destroy(hugetlbfs_inode_cachep); |
@@ -1047,13 +1078,19 @@ static int __init init_hugetlbfs_fs(void) | |||
1047 | 1078 | ||
1048 | static void __exit exit_hugetlbfs_fs(void) | 1079 | static void __exit exit_hugetlbfs_fs(void) |
1049 | { | 1080 | { |
1081 | struct hstate *h; | ||
1082 | int i; | ||
1083 | |||
1084 | |||
1050 | /* | 1085 | /* |
1051 | * Make sure all delayed rcu free inodes are flushed before we | 1086 | * Make sure all delayed rcu free inodes are flushed before we |
1052 | * destroy cache. | 1087 | * destroy cache. |
1053 | */ | 1088 | */ |
1054 | rcu_barrier(); | 1089 | rcu_barrier(); |
1055 | kmem_cache_destroy(hugetlbfs_inode_cachep); | 1090 | kmem_cache_destroy(hugetlbfs_inode_cachep); |
1056 | kern_unmount(hugetlbfs_vfsmount); | 1091 | i = 0; |
1092 | for_each_hstate(h) | ||
1093 | kern_unmount(hugetlbfs_vfsmount[i++]); | ||
1057 | unregister_filesystem(&hugetlbfs_fs_type); | 1094 | unregister_filesystem(&hugetlbfs_fs_type); |
1058 | bdi_destroy(&hugetlbfs_backing_dev_info); | 1095 | bdi_destroy(&hugetlbfs_backing_dev_info); |
1059 | } | 1096 | } |
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 | ||
@@ -495,7 +495,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) | |||
495 | if (shmflg & SHM_NORESERVE) | 495 | if (shmflg & SHM_NORESERVE) |
496 | acctflag = VM_NORESERVE; | 496 | acctflag = VM_NORESERVE; |
497 | file = hugetlb_file_setup(name, 0, size, acctflag, | 497 | file = hugetlb_file_setup(name, 0, size, acctflag, |
498 | &shp->mlock_user, HUGETLB_SHMFS_INODE); | 498 | &shp->mlock_user, HUGETLB_SHMFS_INODE, |
499 | (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK); | ||
499 | } else { | 500 | } else { |
500 | /* | 501 | /* |
501 | * Do not allow no accounting for OVERCOMMIT_NEVER, even | 502 | * Do not allow no accounting for OVERCOMMIT_NEVER, even |
@@ -1153,8 +1153,9 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, | |||
1153 | * memory so no accounting is necessary | 1153 | * memory so no accounting is necessary |
1154 | */ | 1154 | */ |
1155 | file = hugetlb_file_setup(HUGETLB_ANON_FILE, addr, len, | 1155 | file = hugetlb_file_setup(HUGETLB_ANON_FILE, addr, len, |
1156 | VM_NORESERVE, &user, | 1156 | VM_NORESERVE, |
1157 | HUGETLB_ANONHUGE_INODE); | 1157 | &user, HUGETLB_ANONHUGE_INODE, |
1158 | (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK); | ||
1158 | if (IS_ERR(file)) | 1159 | if (IS_ERR(file)) |
1159 | return PTR_ERR(file); | 1160 | return PTR_ERR(file); |
1160 | } | 1161 | } |