]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - mm/shmem.c
shmem: shmem_charge: verify max_block is not exceeded before inode update
[mirror_ubuntu-bionic-kernel.git] / mm / shmem.c
index fbcb3c96a186e8bcf9758189e4d1f17f1bc00cdd..35b524085c449c8092bd35f163715a811f694458 100644 (file)
@@ -266,6 +266,14 @@ bool shmem_charge(struct inode *inode, long pages)
 
        if (shmem_acct_block(info->flags, pages))
                return false;
+
+       if (sbinfo->max_blocks) {
+               if (percpu_counter_compare(&sbinfo->used_blocks,
+                                          sbinfo->max_blocks - pages) > 0)
+                       goto unacct;
+               percpu_counter_add(&sbinfo->used_blocks, pages);
+       }
+
        spin_lock_irqsave(&info->lock, flags);
        info->alloced += pages;
        inode->i_blocks += pages * BLOCKS_PER_PAGE;
@@ -273,20 +281,11 @@ bool shmem_charge(struct inode *inode, long pages)
        spin_unlock_irqrestore(&info->lock, flags);
        inode->i_mapping->nrpages += pages;
 
-       if (!sbinfo->max_blocks)
-               return true;
-       if (percpu_counter_compare(&sbinfo->used_blocks,
-                               sbinfo->max_blocks - pages) > 0) {
-               inode->i_mapping->nrpages -= pages;
-               spin_lock_irqsave(&info->lock, flags);
-               info->alloced -= pages;
-               shmem_recalc_inode(inode);
-               spin_unlock_irqrestore(&info->lock, flags);
-               shmem_unacct_blocks(info->flags, pages);
-               return false;
-       }
-       percpu_counter_add(&sbinfo->used_blocks, pages);
        return true;
+
+unacct:
+       shmem_unacct_blocks(info->flags, pages);
+       return false;
 }
 
 void shmem_uncharge(struct inode *inode, long pages)