Merge branch 'work.iov_iter' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / fs / hugetlbfs / inode.c
index 701c82c..926eeb9 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);
 }
 
 /*
@@ -1443,7 +1446,7 @@ static int get_hstate_idx(int page_size_log)
  * otherwise hugetlb_reserve_pages reserves one less hugepages than intended.
  */
 struct file *hugetlb_file_setup(const char *name, size_t size,
-                               vm_flags_t acctflag, struct user_struct **user,
+                               vm_flags_t acctflag, struct ucounts **ucounts,
                                int creat_flags, int page_size_log)
 {
        struct inode *inode;
@@ -1455,20 +1458,20 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
        if (hstate_idx < 0)
                return ERR_PTR(-ENODEV);
 
-       *user = NULL;
+       *ucounts = NULL;
        mnt = hugetlbfs_vfsmount[hstate_idx];
        if (!mnt)
                return ERR_PTR(-ENOENT);
 
        if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
-               *user = current_user();
-               if (user_shm_lock(size, *user)) {
+               *ucounts = current_ucounts();
+               if (user_shm_lock(size, *ucounts)) {
                        task_lock(current);
                        pr_warn_once("%s (%d): Using mlock ulimits for SHM_HUGETLB is deprecated\n",
                                current->comm, current->pid);
                        task_unlock(current);
                } else {
-                       *user = NULL;
+                       *ucounts = NULL;
                        return ERR_PTR(-EPERM);
                }
        }
@@ -1495,9 +1498,9 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
 
        iput(inode);
 out:
-       if (*user) {
-               user_shm_unlock(size, *user);
-               *user = NULL;
+       if (*ucounts) {
+               user_shm_unlock(size, *ucounts);
+               *ucounts = NULL;
        }
        return file;
 }