diff options
Diffstat (limited to 'fs/hugetlbfs/inode.c')
| -rw-r--r-- | fs/hugetlbfs/inode.c | 92 |
1 files changed, 24 insertions, 68 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index b35195289945..25fa8bba8cb5 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
| @@ -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 | ||
| @@ -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: |
