Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm...
[linux-block.git] / fs / hugetlbfs / inode.c
index be519fc9559a304fd795b195dfd87037280840be..926eeb9bf4ebeb8a324ec575ea8c6cb09612a9e5 100644 (file)
@@ -131,6 +131,7 @@ static void huge_pagevec_release(struct pagevec *pvec)
 static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct inode *inode = file_inode(file);
+       struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
        loff_t len, vma_len;
        int ret;
        struct hstate *h = hstate_file(file);
@@ -146,6 +147,10 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
        vma->vm_flags |= VM_HUGETLB | VM_DONTEXPAND;
        vma->vm_ops = &hugetlb_vm_ops;
 
+       ret = seal_check_future_write(info->seals, vma);
+       if (ret)
+               return ret;
+
        /*
         * page based offset in vm_pgoff could be sufficiently large to
         * overflow a loff_t when converted to byte offset.  This can
@@ -463,14 +468,11 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
        struct address_space *mapping = &inode->i_data;
        const pgoff_t start = lstart >> huge_page_shift(h);
        const pgoff_t end = lend >> huge_page_shift(h);
-       struct vm_area_struct pseudo_vma;
        struct pagevec pvec;
        pgoff_t next, index;
        int i, freed = 0;
        bool truncate_op = (lend == LLONG_MAX);
 
-       vma_init(&pseudo_vma, current->mm);
-       pseudo_vma.vm_flags = (VM_HUGETLB | VM_MAYSHARE | VM_SHARED);
        pagevec_init(&pvec);
        next = start;
        while (next < end) {
@@ -482,10 +484,9 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
 
                for (i = 0; i < pagevec_count(&pvec); ++i) {
                        struct page *page = pvec.pages[i];
-                       u32 hash;
+                       u32 hash = 0;
 
                        index = page->index;
-                       hash = hugetlb_fault_mutex_hash(mapping, index);
                        if (!truncate_op) {
                                /*
                                 * Only need to hold the fault mutex in the
@@ -493,6 +494,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
                                 * page faults.  Races are not possible in the
                                 * case of truncation.
                                 */
+                               hash = hugetlb_fault_mutex_hash(mapping, index);
                                mutex_lock(&hugetlb_fault_mutex_table[hash]);
                        }
 
@@ -527,7 +529,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
                         * the subpool and global reserve usage count can need
                         * to be adjusted.
                         */
-                       VM_BUG_ON(PagePrivate(page));
+                       VM_BUG_ON(HPageRestoreReserve(page));
                        remove_huge_page(page);
                        freed++;
                        if (!truncate_op) {
@@ -733,6 +735,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
                __SetPageUptodate(page);
                error = huge_add_to_page_cache(page, mapping, index);
                if (unlikely(error)) {
+                       restore_reserve_on_error(h, &pseudo_vma, addr, page);
                        put_page(page);
                        mutex_unlock(&hugetlb_fault_mutex_table[hash]);
                        goto out;
@@ -1435,7 +1438,7 @@ static int get_hstate_idx(int page_size_log)
 
        if (!h)
                return -1;
-       return h - hstates;
+       return hstate_index(h);
 }
 
 /*