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 | } |
