shmem: fix double uncharge in __shmem_file_setup()
authorKonstantin Khlebnikov <koct9i@gmail.com>
Wed, 6 Aug 2014 23:06:32 +0000 (16:06 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Aug 2014 01:01:18 +0000 (18:01 -0700)
If __shmem_file_setup() fails on struct file allocation it uncharges
memory commitment twice: first by shmem_unacct_size() and second time
implicitly in shmem_evict_inode() when it kills the newly created inode.

This patch removes shmem_unacct_size() from error path if the inode was
already there.

Signed-off-by: Konstantin Khlebnikov <koct9i@gmail.com>
Acked-by: Hugh Dickins <hughd@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
mm/shmem.c

index af68b15..3609d31 100644 (file)
@@ -2932,16 +2932,16 @@ static struct file *__shmem_file_setup(const char *name, loff_t size,
        this.len = strlen(name);
        this.hash = 0; /* will go */
        sb = shm_mnt->mnt_sb;
+       path.mnt = mntget(shm_mnt);
        path.dentry = d_alloc_pseudo(sb, &this);
        if (!path.dentry)
                goto put_memory;
        d_set_d_op(path.dentry, &anon_ops);
-       path.mnt = mntget(shm_mnt);
 
        res = ERR_PTR(-ENOSPC);
        inode = shmem_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0, flags);
        if (!inode)
-               goto put_dentry;
+               goto put_memory;
 
        inode->i_flags |= i_flags;
        d_instantiate(path.dentry, inode);
@@ -2949,19 +2949,19 @@ static struct file *__shmem_file_setup(const char *name, loff_t size,
        clear_nlink(inode);     /* It is unlinked */
        res = ERR_PTR(ramfs_nommu_expand_for_mapping(inode, size));
        if (IS_ERR(res))
-               goto put_dentry;
+               goto put_path;
 
        res = alloc_file(&path, FMODE_WRITE | FMODE_READ,
                  &shmem_file_operations);
        if (IS_ERR(res))
-               goto put_dentry;
+               goto put_path;
 
        return res;
 
-put_dentry:
-       path_put(&path);
 put_memory:
        shmem_unacct_size(flags, size);
+put_path:
+       path_put(&path);
        return res;
 }