GFS2: Fix uninitialized VFS inode in gfs2_create_inode
authorAbhi Das <adas@redhat.com>
Mon, 31 Mar 2014 15:33:17 +0000 (10:33 -0500)
committerSteven Whitehouse <swhiteho@redhat.com>
Mon, 31 Mar 2014 15:41:39 +0000 (16:41 +0100)
When gfs2_create_inode() fails due to quota violation, the VFS
inode is not completely uninitialized. This can cause a list
corruption error.

This patch correctly uninitializes the VFS inode when a quota
violation occurs in the gfs2_create_inode codepath.

Resolves: rhbz#1059808
Signed-off-by: Abhi Das <adas@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/super.c

index ef26ed98e778e7dea579bdb7fc0c606f5e422bc9..bdf70c18610cfafd26d8d475e7ea939d54487a44 100644 (file)
@@ -371,6 +371,7 @@ enum {
        GIF_ALLOC_FAILED        = 2,
        GIF_SW_PAGED            = 3,
        GIF_ORDERED             = 4,
+       GIF_FREE_VFS_INODE      = 5,
 };
 
 struct gfs2_inode {
index 69ed57a980d0418ffc8ba9df081e08b3c6c71bb1..28cc7bf6575a2147820bb2d67be0a1ba8bbb0b6d 100644 (file)
@@ -597,7 +597,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        struct gfs2_glock *io_gl;
        struct dentry *d;
-       int error;
+       int error, free_vfs_inode = 0;
        u32 aflags = 0;
        unsigned blocks = 1;
        struct gfs2_diradd da = { .bh = NULL, };
@@ -788,15 +788,16 @@ fail_free_acls:
        if (acl)
                posix_acl_release(acl);
 fail_free_vfs_inode:
-       free_inode_nonrcu(inode);
-       inode = NULL;
+       free_vfs_inode = 1;
 fail_gunlock:
        gfs2_dir_no_add(&da);
        gfs2_glock_dq_uninit(ghs);
        if (inode && !IS_ERR(inode)) {
                clear_nlink(inode);
-               mark_inode_dirty(inode);
-               set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags);
+               if (!free_vfs_inode)
+                       mark_inode_dirty(inode);
+               set_bit(free_vfs_inode ? GIF_FREE_VFS_INODE : GIF_ALLOC_FAILED,
+                       &GFS2_I(inode)->i_flags);
                iput(inode);
        }
 fail:
index a08c66e270bf0cc90ad3e7c22bcf874954a4b46b..29cacd57516a2e2af818356b3965dae1a02cf822 100644 (file)
@@ -1248,7 +1248,7 @@ static int gfs2_drop_inode(struct inode *inode)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
 
-       if (inode->i_nlink) {
+       if (!test_bit(GIF_FREE_VFS_INODE, &ip->i_flags) && inode->i_nlink) {
                struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
                if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
                        clear_nlink(inode);
@@ -1463,6 +1463,11 @@ static void gfs2_evict_inode(struct inode *inode)
        struct gfs2_holder gh;
        int error;
 
+       if (test_bit(GIF_FREE_VFS_INODE, &ip->i_flags)) {
+               clear_inode(inode);
+               return;
+       }
+
        if (inode->i_nlink || (sb->s_flags & MS_RDONLY))
                goto out;