diff options
Diffstat (limited to 'fs/hugetlbfs')
-rw-r--r-- | fs/hugetlbfs/inode.c | 138 |
1 files changed, 77 insertions, 61 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 81932fa1861a..ea251749d9d5 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -41,6 +41,25 @@ const struct file_operations hugetlbfs_file_operations; | |||
41 | static const struct inode_operations hugetlbfs_dir_inode_operations; | 41 | static const struct inode_operations hugetlbfs_dir_inode_operations; |
42 | static const struct inode_operations hugetlbfs_inode_operations; | 42 | static const struct inode_operations hugetlbfs_inode_operations; |
43 | 43 | ||
44 | struct hugetlbfs_config { | ||
45 | uid_t uid; | ||
46 | gid_t gid; | ||
47 | umode_t mode; | ||
48 | long nr_blocks; | ||
49 | long nr_inodes; | ||
50 | struct hstate *hstate; | ||
51 | }; | ||
52 | |||
53 | struct hugetlbfs_inode_info { | ||
54 | struct shared_policy policy; | ||
55 | struct inode vfs_inode; | ||
56 | }; | ||
57 | |||
58 | static inline struct hugetlbfs_inode_info *HUGETLBFS_I(struct inode *inode) | ||
59 | { | ||
60 | return container_of(inode, struct hugetlbfs_inode_info, vfs_inode); | ||
61 | } | ||
62 | |||
44 | static struct backing_dev_info hugetlbfs_backing_dev_info = { | 63 | static struct backing_dev_info hugetlbfs_backing_dev_info = { |
45 | .name = "hugetlbfs", | 64 | .name = "hugetlbfs", |
46 | .ra_pages = 0, /* No readahead */ | 65 | .ra_pages = 0, /* No readahead */ |
@@ -154,10 +173,12 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
154 | return addr; | 173 | return addr; |
155 | } | 174 | } |
156 | 175 | ||
157 | start_addr = mm->free_area_cache; | 176 | if (len > mm->cached_hole_size) |
158 | 177 | start_addr = mm->free_area_cache; | |
159 | if (len <= mm->cached_hole_size) | 178 | else { |
160 | start_addr = TASK_UNMAPPED_BASE; | 179 | start_addr = TASK_UNMAPPED_BASE; |
180 | mm->cached_hole_size = 0; | ||
181 | } | ||
161 | 182 | ||
162 | full_search: | 183 | full_search: |
163 | addr = ALIGN(start_addr, huge_page_size(h)); | 184 | addr = ALIGN(start_addr, huge_page_size(h)); |
@@ -171,13 +192,18 @@ full_search: | |||
171 | */ | 192 | */ |
172 | if (start_addr != TASK_UNMAPPED_BASE) { | 193 | if (start_addr != TASK_UNMAPPED_BASE) { |
173 | start_addr = TASK_UNMAPPED_BASE; | 194 | start_addr = TASK_UNMAPPED_BASE; |
195 | mm->cached_hole_size = 0; | ||
174 | goto full_search; | 196 | goto full_search; |
175 | } | 197 | } |
176 | return -ENOMEM; | 198 | return -ENOMEM; |
177 | } | 199 | } |
178 | 200 | ||
179 | if (!vma || addr + len <= vma->vm_start) | 201 | if (!vma || addr + len <= vma->vm_start) { |
202 | mm->free_area_cache = addr + len; | ||
180 | return addr; | 203 | return addr; |
204 | } | ||
205 | if (addr + mm->cached_hole_size < vma->vm_start) | ||
206 | mm->cached_hole_size = vma->vm_start - addr; | ||
181 | addr = ALIGN(vma->vm_end, huge_page_size(h)); | 207 | addr = ALIGN(vma->vm_end, huge_page_size(h)); |
182 | } | 208 | } |
183 | } | 209 | } |
@@ -238,17 +264,10 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf, | |||
238 | loff_t isize; | 264 | loff_t isize; |
239 | ssize_t retval = 0; | 265 | ssize_t retval = 0; |
240 | 266 | ||
241 | mutex_lock(&inode->i_mutex); | ||
242 | |||
243 | /* validate length */ | 267 | /* validate length */ |
244 | if (len == 0) | 268 | if (len == 0) |
245 | goto out; | 269 | goto out; |
246 | 270 | ||
247 | isize = i_size_read(inode); | ||
248 | if (!isize) | ||
249 | goto out; | ||
250 | |||
251 | end_index = (isize - 1) >> huge_page_shift(h); | ||
252 | for (;;) { | 271 | for (;;) { |
253 | struct page *page; | 272 | struct page *page; |
254 | unsigned long nr, ret; | 273 | unsigned long nr, ret; |
@@ -256,18 +275,21 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf, | |||
256 | 275 | ||
257 | /* nr is the maximum number of bytes to copy from this page */ | 276 | /* nr is the maximum number of bytes to copy from this page */ |
258 | nr = huge_page_size(h); | 277 | nr = huge_page_size(h); |
278 | isize = i_size_read(inode); | ||
279 | if (!isize) | ||
280 | goto out; | ||
281 | end_index = (isize - 1) >> huge_page_shift(h); | ||
259 | if (index >= end_index) { | 282 | if (index >= end_index) { |
260 | if (index > end_index) | 283 | if (index > end_index) |
261 | goto out; | 284 | goto out; |
262 | nr = ((isize - 1) & ~huge_page_mask(h)) + 1; | 285 | nr = ((isize - 1) & ~huge_page_mask(h)) + 1; |
263 | if (nr <= offset) { | 286 | if (nr <= offset) |
264 | goto out; | 287 | goto out; |
265 | } | ||
266 | } | 288 | } |
267 | nr = nr - offset; | 289 | nr = nr - offset; |
268 | 290 | ||
269 | /* Find the page */ | 291 | /* Find the page */ |
270 | page = find_get_page(mapping, index); | 292 | page = find_lock_page(mapping, index); |
271 | if (unlikely(page == NULL)) { | 293 | if (unlikely(page == NULL)) { |
272 | /* | 294 | /* |
273 | * We have a HOLE, zero out the user-buffer for the | 295 | * We have a HOLE, zero out the user-buffer for the |
@@ -279,17 +301,18 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf, | |||
279 | else | 301 | else |
280 | ra = 0; | 302 | ra = 0; |
281 | } else { | 303 | } else { |
304 | unlock_page(page); | ||
305 | |||
282 | /* | 306 | /* |
283 | * We have the page, copy it to user space buffer. | 307 | * We have the page, copy it to user space buffer. |
284 | */ | 308 | */ |
285 | ra = hugetlbfs_read_actor(page, offset, buf, len, nr); | 309 | ra = hugetlbfs_read_actor(page, offset, buf, len, nr); |
286 | ret = ra; | 310 | ret = ra; |
311 | page_cache_release(page); | ||
287 | } | 312 | } |
288 | if (ra < 0) { | 313 | if (ra < 0) { |
289 | if (retval == 0) | 314 | if (retval == 0) |
290 | retval = ra; | 315 | retval = ra; |
291 | if (page) | ||
292 | page_cache_release(page); | ||
293 | goto out; | 316 | goto out; |
294 | } | 317 | } |
295 | 318 | ||
@@ -299,16 +322,12 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf, | |||
299 | index += offset >> huge_page_shift(h); | 322 | index += offset >> huge_page_shift(h); |
300 | offset &= ~huge_page_mask(h); | 323 | offset &= ~huge_page_mask(h); |
301 | 324 | ||
302 | if (page) | ||
303 | page_cache_release(page); | ||
304 | |||
305 | /* short read or no more work */ | 325 | /* short read or no more work */ |
306 | if ((ret != nr) || (len == 0)) | 326 | if ((ret != nr) || (len == 0)) |
307 | break; | 327 | break; |
308 | } | 328 | } |
309 | out: | 329 | out: |
310 | *ppos = ((loff_t)index << huge_page_shift(h)) + offset; | 330 | *ppos = ((loff_t)index << huge_page_shift(h)) + offset; |
311 | mutex_unlock(&inode->i_mutex); | ||
312 | return retval; | 331 | return retval; |
313 | } | 332 | } |
314 | 333 | ||
@@ -607,9 +626,15 @@ static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
607 | spin_lock(&sbinfo->stat_lock); | 626 | spin_lock(&sbinfo->stat_lock); |
608 | /* If no limits set, just report 0 for max/free/used | 627 | /* If no limits set, just report 0 for max/free/used |
609 | * blocks, like simple_statfs() */ | 628 | * blocks, like simple_statfs() */ |
610 | if (sbinfo->max_blocks >= 0) { | 629 | if (sbinfo->spool) { |
611 | buf->f_blocks = sbinfo->max_blocks; | 630 | long free_pages; |
612 | buf->f_bavail = buf->f_bfree = sbinfo->free_blocks; | 631 | |
632 | spin_lock(&sbinfo->spool->lock); | ||
633 | buf->f_blocks = sbinfo->spool->max_hpages; | ||
634 | free_pages = sbinfo->spool->max_hpages | ||
635 | - sbinfo->spool->used_hpages; | ||
636 | buf->f_bavail = buf->f_bfree = free_pages; | ||
637 | spin_unlock(&sbinfo->spool->lock); | ||
613 | buf->f_files = sbinfo->max_inodes; | 638 | buf->f_files = sbinfo->max_inodes; |
614 | buf->f_ffree = sbinfo->free_inodes; | 639 | buf->f_ffree = sbinfo->free_inodes; |
615 | } | 640 | } |
@@ -625,6 +650,10 @@ static void hugetlbfs_put_super(struct super_block *sb) | |||
625 | 650 | ||
626 | if (sbi) { | 651 | if (sbi) { |
627 | sb->s_fs_info = NULL; | 652 | sb->s_fs_info = NULL; |
653 | |||
654 | if (sbi->spool) | ||
655 | hugepage_put_subpool(sbi->spool); | ||
656 | |||
628 | kfree(sbi); | 657 | kfree(sbi); |
629 | } | 658 | } |
630 | } | 659 | } |
@@ -853,10 +882,14 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) | |||
853 | sb->s_fs_info = sbinfo; | 882 | sb->s_fs_info = sbinfo; |
854 | sbinfo->hstate = config.hstate; | 883 | sbinfo->hstate = config.hstate; |
855 | spin_lock_init(&sbinfo->stat_lock); | 884 | spin_lock_init(&sbinfo->stat_lock); |
856 | sbinfo->max_blocks = config.nr_blocks; | ||
857 | sbinfo->free_blocks = config.nr_blocks; | ||
858 | sbinfo->max_inodes = config.nr_inodes; | 885 | sbinfo->max_inodes = config.nr_inodes; |
859 | sbinfo->free_inodes = config.nr_inodes; | 886 | sbinfo->free_inodes = config.nr_inodes; |
887 | sbinfo->spool = NULL; | ||
888 | if (config.nr_blocks != -1) { | ||
889 | sbinfo->spool = hugepage_new_subpool(config.nr_blocks); | ||
890 | if (!sbinfo->spool) | ||
891 | goto out_free; | ||
892 | } | ||
860 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 893 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
861 | sb->s_blocksize = huge_page_size(config.hstate); | 894 | sb->s_blocksize = huge_page_size(config.hstate); |
862 | sb->s_blocksize_bits = huge_page_shift(config.hstate); | 895 | sb->s_blocksize_bits = huge_page_shift(config.hstate); |
@@ -868,38 +901,12 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) | |||
868 | goto out_free; | 901 | goto out_free; |
869 | return 0; | 902 | return 0; |
870 | out_free: | 903 | out_free: |
904 | if (sbinfo->spool) | ||
905 | kfree(sbinfo->spool); | ||
871 | kfree(sbinfo); | 906 | kfree(sbinfo); |
872 | return -ENOMEM; | 907 | return -ENOMEM; |
873 | } | 908 | } |
874 | 909 | ||
875 | int hugetlb_get_quota(struct address_space *mapping, long delta) | ||
876 | { | ||
877 | int ret = 0; | ||
878 | struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb); | ||
879 | |||
880 | if (sbinfo->free_blocks > -1) { | ||
881 | spin_lock(&sbinfo->stat_lock); | ||
882 | if (sbinfo->free_blocks - delta >= 0) | ||
883 | sbinfo->free_blocks -= delta; | ||
884 | else | ||
885 | ret = -ENOMEM; | ||
886 | spin_unlock(&sbinfo->stat_lock); | ||
887 | } | ||
888 | |||
889 | return ret; | ||
890 | } | ||
891 | |||
892 | void hugetlb_put_quota(struct address_space *mapping, long delta) | ||
893 | { | ||
894 | struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb); | ||
895 | |||
896 | if (sbinfo->free_blocks > -1) { | ||
897 | spin_lock(&sbinfo->stat_lock); | ||
898 | sbinfo->free_blocks += delta; | ||
899 | spin_unlock(&sbinfo->stat_lock); | ||
900 | } | ||
901 | } | ||
902 | |||
903 | static struct dentry *hugetlbfs_mount(struct file_system_type *fs_type, | 910 | static struct dentry *hugetlbfs_mount(struct file_system_type *fs_type, |
904 | int flags, const char *dev_name, void *data) | 911 | int flags, const char *dev_name, void *data) |
905 | { | 912 | { |
@@ -919,8 +926,8 @@ static int can_do_hugetlb_shm(void) | |||
919 | return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group); | 926 | return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group); |
920 | } | 927 | } |
921 | 928 | ||
922 | struct file *hugetlb_file_setup(const char *name, size_t size, | 929 | struct file *hugetlb_file_setup(const char *name, unsigned long addr, |
923 | vm_flags_t acctflag, | 930 | size_t size, vm_flags_t acctflag, |
924 | struct user_struct **user, int creat_flags) | 931 | struct user_struct **user, int creat_flags) |
925 | { | 932 | { |
926 | int error = -ENOMEM; | 933 | int error = -ENOMEM; |
@@ -929,6 +936,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size, | |||
929 | struct path path; | 936 | struct path path; |
930 | struct dentry *root; | 937 | struct dentry *root; |
931 | struct qstr quick_string; | 938 | struct qstr quick_string; |
939 | struct hstate *hstate; | ||
940 | unsigned long num_pages; | ||
932 | 941 | ||
933 | *user = NULL; | 942 | *user = NULL; |
934 | if (!hugetlbfs_vfsmount) | 943 | if (!hugetlbfs_vfsmount) |
@@ -937,7 +946,11 @@ struct file *hugetlb_file_setup(const char *name, size_t size, | |||
937 | if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) { | 946 | if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) { |
938 | *user = current_user(); | 947 | *user = current_user(); |
939 | if (user_shm_lock(size, *user)) { | 948 | if (user_shm_lock(size, *user)) { |
940 | printk_once(KERN_WARNING "Using mlock ulimits for SHM_HUGETLB is deprecated\n"); | 949 | task_lock(current); |
950 | printk_once(KERN_WARNING | ||
951 | "%s (%d): Using mlock ulimits for SHM_HUGETLB is deprecated\n", | ||
952 | current->comm, current->pid); | ||
953 | task_unlock(current); | ||
941 | } else { | 954 | } else { |
942 | *user = NULL; | 955 | *user = NULL; |
943 | return ERR_PTR(-EPERM); | 956 | return ERR_PTR(-EPERM); |
@@ -958,10 +971,12 @@ struct file *hugetlb_file_setup(const char *name, size_t size, | |||
958 | if (!inode) | 971 | if (!inode) |
959 | goto out_dentry; | 972 | goto out_dentry; |
960 | 973 | ||
974 | hstate = hstate_inode(inode); | ||
975 | size += addr & ~huge_page_mask(hstate); | ||
976 | num_pages = ALIGN(size, huge_page_size(hstate)) >> | ||
977 | huge_page_shift(hstate); | ||
961 | error = -ENOMEM; | 978 | error = -ENOMEM; |
962 | if (hugetlb_reserve_pages(inode, 0, | 979 | if (hugetlb_reserve_pages(inode, 0, num_pages, NULL, acctflag)) |
963 | size >> huge_page_shift(hstate_inode(inode)), NULL, | ||
964 | acctflag)) | ||
965 | goto out_inode; | 980 | goto out_inode; |
966 | 981 | ||
967 | d_instantiate(path.dentry, inode); | 982 | d_instantiate(path.dentry, inode); |
@@ -997,6 +1012,7 @@ static int __init init_hugetlbfs_fs(void) | |||
997 | if (error) | 1012 | if (error) |
998 | return error; | 1013 | return error; |
999 | 1014 | ||
1015 | error = -ENOMEM; | ||
1000 | hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache", | 1016 | hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache", |
1001 | sizeof(struct hugetlbfs_inode_info), | 1017 | sizeof(struct hugetlbfs_inode_info), |
1002 | 0, 0, init_once); | 1018 | 0, 0, init_once); |
@@ -1015,10 +1031,10 @@ static int __init init_hugetlbfs_fs(void) | |||
1015 | } | 1031 | } |
1016 | 1032 | ||
1017 | error = PTR_ERR(vfsmount); | 1033 | error = PTR_ERR(vfsmount); |
1034 | unregister_filesystem(&hugetlbfs_fs_type); | ||
1018 | 1035 | ||
1019 | out: | 1036 | out: |
1020 | if (error) | 1037 | kmem_cache_destroy(hugetlbfs_inode_cachep); |
1021 | kmem_cache_destroy(hugetlbfs_inode_cachep); | ||
1022 | out2: | 1038 | out2: |
1023 | bdi_destroy(&hugetlbfs_backing_dev_info); | 1039 | bdi_destroy(&hugetlbfs_backing_dev_info); |
1024 | return error; | 1040 | return error; |