diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-03-31 15:34:58 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-03-31 15:34:58 -0500 |
commit | 86579dd06deecfa6ac88d5e84e4d63c397cd6f6d (patch) | |
tree | b4475d3ccde53015ad84a06e4e55e64591171b75 /fs/hugetlbfs | |
parent | 7ea9ea832212c4a755650f7c7cc1ff0b63292a41 (diff) | |
parent | a0f067802576d4eb4c65d40b8ee7d6ea3c81dd61 (diff) |
Merge branch 'master'
Diffstat (limited to 'fs/hugetlbfs')
-rw-r--r-- | fs/hugetlbfs/inode.c | 96 |
1 files changed, 26 insertions, 70 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index b35195289945..3a5b4e923455 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -35,7 +35,7 @@ | |||
35 | 35 | ||
36 | static struct super_operations hugetlbfs_ops; | 36 | static struct super_operations hugetlbfs_ops; |
37 | static struct address_space_operations hugetlbfs_aops; | 37 | static struct address_space_operations hugetlbfs_aops; |
38 | struct file_operations hugetlbfs_file_operations; | 38 | const struct file_operations hugetlbfs_file_operations; |
39 | static struct inode_operations hugetlbfs_dir_inode_operations; | 39 | static struct inode_operations hugetlbfs_dir_inode_operations; |
40 | static struct inode_operations hugetlbfs_inode_operations; | 40 | static struct inode_operations hugetlbfs_inode_operations; |
41 | 41 | ||
@@ -56,48 +56,10 @@ static void huge_pagevec_release(struct pagevec *pvec) | |||
56 | pagevec_reinit(pvec); | 56 | pagevec_reinit(pvec); |
57 | } | 57 | } |
58 | 58 | ||
59 | /* | ||
60 | * huge_pages_needed tries to determine the number of new huge pages that | ||
61 | * will be required to fully populate this VMA. This will be equal to | ||
62 | * the size of the VMA in huge pages minus the number of huge pages | ||
63 | * (covered by this VMA) that are found in the page cache. | ||
64 | * | ||
65 | * Result is in bytes to be compatible with is_hugepage_mem_enough() | ||
66 | */ | ||
67 | static unsigned long | ||
68 | huge_pages_needed(struct address_space *mapping, struct vm_area_struct *vma) | ||
69 | { | ||
70 | int i; | ||
71 | struct pagevec pvec; | ||
72 | unsigned long start = vma->vm_start; | ||
73 | unsigned long end = vma->vm_end; | ||
74 | unsigned long hugepages = (end - start) >> HPAGE_SHIFT; | ||
75 | pgoff_t next = vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT); | ||
76 | pgoff_t endpg = next + hugepages; | ||
77 | |||
78 | pagevec_init(&pvec, 0); | ||
79 | while (next < endpg) { | ||
80 | if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) | ||
81 | break; | ||
82 | for (i = 0; i < pagevec_count(&pvec); i++) { | ||
83 | struct page *page = pvec.pages[i]; | ||
84 | if (page->index > next) | ||
85 | next = page->index; | ||
86 | if (page->index >= endpg) | ||
87 | break; | ||
88 | next++; | ||
89 | hugepages--; | ||
90 | } | ||
91 | huge_pagevec_release(&pvec); | ||
92 | } | ||
93 | return hugepages << HPAGE_SHIFT; | ||
94 | } | ||
95 | |||
96 | static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) | 59 | static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) |
97 | { | 60 | { |
98 | struct inode *inode = file->f_dentry->d_inode; | 61 | struct inode *inode = file->f_dentry->d_inode; |
99 | struct address_space *mapping = inode->i_mapping; | 62 | struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode); |
100 | unsigned long bytes; | ||
101 | loff_t len, vma_len; | 63 | loff_t len, vma_len; |
102 | int ret; | 64 | int ret; |
103 | 65 | ||
@@ -113,10 +75,6 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
113 | if (vma->vm_end - vma->vm_start < HPAGE_SIZE) | 75 | if (vma->vm_end - vma->vm_start < HPAGE_SIZE) |
114 | return -EINVAL; | 76 | return -EINVAL; |
115 | 77 | ||
116 | bytes = huge_pages_needed(mapping, vma); | ||
117 | if (!is_hugepage_mem_enough(bytes)) | ||
118 | return -ENOMEM; | ||
119 | |||
120 | vma_len = (loff_t)(vma->vm_end - vma->vm_start); | 78 | vma_len = (loff_t)(vma->vm_end - vma->vm_start); |
121 | 79 | ||
122 | mutex_lock(&inode->i_mutex); | 80 | mutex_lock(&inode->i_mutex); |
@@ -129,6 +87,10 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
129 | if (!(vma->vm_flags & VM_WRITE) && len > inode->i_size) | 87 | if (!(vma->vm_flags & VM_WRITE) && len > inode->i_size) |
130 | goto out; | 88 | goto out; |
131 | 89 | ||
90 | if (vma->vm_flags & VM_MAYSHARE) | ||
91 | if (hugetlb_extend_reservation(info, len >> HPAGE_SHIFT) != 0) | ||
92 | goto out; | ||
93 | |||
132 | ret = 0; | 94 | ret = 0; |
133 | hugetlb_prefault_arch_hook(vma->vm_mm); | 95 | hugetlb_prefault_arch_hook(vma->vm_mm); |
134 | if (inode->i_size < len) | 96 | if (inode->i_size < len) |
@@ -227,13 +189,18 @@ static void truncate_huge_page(struct page *page) | |||
227 | put_page(page); | 189 | put_page(page); |
228 | } | 190 | } |
229 | 191 | ||
230 | static void truncate_hugepages(struct address_space *mapping, loff_t lstart) | 192 | static void truncate_hugepages(struct inode *inode, loff_t lstart) |
231 | { | 193 | { |
194 | struct address_space *mapping = &inode->i_data; | ||
232 | const pgoff_t start = lstart >> HPAGE_SHIFT; | 195 | const pgoff_t start = lstart >> HPAGE_SHIFT; |
233 | struct pagevec pvec; | 196 | struct pagevec pvec; |
234 | pgoff_t next; | 197 | pgoff_t next; |
235 | int i; | 198 | int i; |
236 | 199 | ||
200 | hugetlb_truncate_reservation(HUGETLBFS_I(inode), | ||
201 | lstart >> HPAGE_SHIFT); | ||
202 | if (!mapping->nrpages) | ||
203 | return; | ||
237 | pagevec_init(&pvec, 0); | 204 | pagevec_init(&pvec, 0); |
238 | next = start; | 205 | next = start; |
239 | while (1) { | 206 | while (1) { |
@@ -262,8 +229,7 @@ static void truncate_hugepages(struct address_space *mapping, loff_t lstart) | |||
262 | 229 | ||
263 | static void hugetlbfs_delete_inode(struct inode *inode) | 230 | static void hugetlbfs_delete_inode(struct inode *inode) |
264 | { | 231 | { |
265 | if (inode->i_data.nrpages) | 232 | truncate_hugepages(inode, 0); |
266 | truncate_hugepages(&inode->i_data, 0); | ||
267 | clear_inode(inode); | 233 | clear_inode(inode); |
268 | } | 234 | } |
269 | 235 | ||
@@ -296,8 +262,7 @@ static void hugetlbfs_forget_inode(struct inode *inode) | |||
296 | inode->i_state |= I_FREEING; | 262 | inode->i_state |= I_FREEING; |
297 | inodes_stat.nr_inodes--; | 263 | inodes_stat.nr_inodes--; |
298 | spin_unlock(&inode_lock); | 264 | spin_unlock(&inode_lock); |
299 | if (inode->i_data.nrpages) | 265 | truncate_hugepages(inode, 0); |
300 | truncate_hugepages(&inode->i_data, 0); | ||
301 | clear_inode(inode); | 266 | clear_inode(inode); |
302 | destroy_inode(inode); | 267 | destroy_inode(inode); |
303 | } | 268 | } |
@@ -356,7 +321,7 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) | |||
356 | if (!prio_tree_empty(&mapping->i_mmap)) | 321 | if (!prio_tree_empty(&mapping->i_mmap)) |
357 | hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff); | 322 | hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff); |
358 | spin_unlock(&mapping->i_mmap_lock); | 323 | spin_unlock(&mapping->i_mmap_lock); |
359 | truncate_hugepages(mapping, offset); | 324 | truncate_hugepages(inode, offset); |
360 | return 0; | 325 | return 0; |
361 | } | 326 | } |
362 | 327 | ||
@@ -573,6 +538,7 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb) | |||
573 | hugetlbfs_inc_free_inodes(sbinfo); | 538 | hugetlbfs_inc_free_inodes(sbinfo); |
574 | return NULL; | 539 | return NULL; |
575 | } | 540 | } |
541 | p->prereserved_hpages = 0; | ||
576 | return &p->vfs_inode; | 542 | return &p->vfs_inode; |
577 | } | 543 | } |
578 | 544 | ||
@@ -600,7 +566,7 @@ static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) | |||
600 | inode_init_once(&ei->vfs_inode); | 566 | inode_init_once(&ei->vfs_inode); |
601 | } | 567 | } |
602 | 568 | ||
603 | struct file_operations hugetlbfs_file_operations = { | 569 | const struct file_operations hugetlbfs_file_operations = { |
604 | .mmap = hugetlbfs_file_mmap, | 570 | .mmap = hugetlbfs_file_mmap, |
605 | .fsync = simple_sync_file, | 571 | .fsync = simple_sync_file, |
606 | .get_unmapped_area = hugetlb_get_unmapped_area, | 572 | .get_unmapped_area = hugetlb_get_unmapped_area, |
@@ -771,21 +737,6 @@ static struct file_system_type hugetlbfs_fs_type = { | |||
771 | 737 | ||
772 | static struct vfsmount *hugetlbfs_vfsmount; | 738 | static struct vfsmount *hugetlbfs_vfsmount; |
773 | 739 | ||
774 | /* | ||
775 | * Return the next identifier for a shm file | ||
776 | */ | ||
777 | static unsigned long hugetlbfs_counter(void) | ||
778 | { | ||
779 | static DEFINE_SPINLOCK(lock); | ||
780 | static unsigned long counter; | ||
781 | unsigned long ret; | ||
782 | |||
783 | spin_lock(&lock); | ||
784 | ret = ++counter; | ||
785 | spin_unlock(&lock); | ||
786 | return ret; | ||
787 | } | ||
788 | |||
789 | static int can_do_hugetlb_shm(void) | 740 | static int can_do_hugetlb_shm(void) |
790 | { | 741 | { |
791 | return likely(capable(CAP_IPC_LOCK) || | 742 | return likely(capable(CAP_IPC_LOCK) || |
@@ -801,18 +752,16 @@ struct file *hugetlb_zero_setup(size_t size) | |||
801 | struct dentry *dentry, *root; | 752 | struct dentry *dentry, *root; |
802 | struct qstr quick_string; | 753 | struct qstr quick_string; |
803 | char buf[16]; | 754 | char buf[16]; |
755 | static atomic_t counter; | ||
804 | 756 | ||
805 | if (!can_do_hugetlb_shm()) | 757 | if (!can_do_hugetlb_shm()) |
806 | return ERR_PTR(-EPERM); | 758 | return ERR_PTR(-EPERM); |
807 | 759 | ||
808 | if (!is_hugepage_mem_enough(size)) | ||
809 | return ERR_PTR(-ENOMEM); | ||
810 | |||
811 | if (!user_shm_lock(size, current->user)) | 760 | if (!user_shm_lock(size, current->user)) |
812 | return ERR_PTR(-ENOMEM); | 761 | return ERR_PTR(-ENOMEM); |
813 | 762 | ||
814 | root = hugetlbfs_vfsmount->mnt_root; | 763 | root = hugetlbfs_vfsmount->mnt_root; |
815 | snprintf(buf, 16, "%lu", hugetlbfs_counter()); | 764 | snprintf(buf, 16, "%u", atomic_inc_return(&counter)); |
816 | quick_string.name = buf; | 765 | quick_string.name = buf; |
817 | quick_string.len = strlen(quick_string.name); | 766 | quick_string.len = strlen(quick_string.name); |
818 | quick_string.hash = 0; | 767 | quick_string.hash = 0; |
@@ -831,6 +780,11 @@ struct file *hugetlb_zero_setup(size_t size) | |||
831 | if (!inode) | 780 | if (!inode) |
832 | goto out_file; | 781 | goto out_file; |
833 | 782 | ||
783 | error = -ENOMEM; | ||
784 | if (hugetlb_extend_reservation(HUGETLBFS_I(inode), | ||
785 | size >> HPAGE_SHIFT) != 0) | ||
786 | goto out_inode; | ||
787 | |||
834 | d_instantiate(dentry, inode); | 788 | d_instantiate(dentry, inode); |
835 | inode->i_size = size; | 789 | inode->i_size = size; |
836 | inode->i_nlink = 0; | 790 | inode->i_nlink = 0; |
@@ -841,6 +795,8 @@ struct file *hugetlb_zero_setup(size_t size) | |||
841 | file->f_mode = FMODE_WRITE | FMODE_READ; | 795 | file->f_mode = FMODE_WRITE | FMODE_READ; |
842 | return file; | 796 | return file; |
843 | 797 | ||
798 | out_inode: | ||
799 | iput(inode); | ||
844 | out_file: | 800 | out_file: |
845 | put_filp(file); | 801 | put_filp(file); |
846 | out_dentry: | 802 | out_dentry: |