diff options
author | Abhi Das <adas@redhat.com> | 2014-03-31 11:33:17 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2014-03-31 11:41:39 -0400 |
commit | 059788039f1e6343f34f46d202f8d9f2158c2783 (patch) | |
tree | f122d85bf11e42c4b1babb1b720df747386ba95d /fs/gfs2 | |
parent | e9fb7c73a43e0551e689b7024f1581af5fa36a03 (diff) |
GFS2: Fix uninitialized VFS inode in gfs2_create_inode
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>
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/incore.h | 1 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 11 | ||||
-rw-r--r-- | fs/gfs2/super.c | 7 |
3 files changed, 13 insertions, 6 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index ef26ed98e778..bdf70c18610c 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -371,6 +371,7 @@ enum { | |||
371 | GIF_ALLOC_FAILED = 2, | 371 | GIF_ALLOC_FAILED = 2, |
372 | GIF_SW_PAGED = 3, | 372 | GIF_SW_PAGED = 3, |
373 | GIF_ORDERED = 4, | 373 | GIF_ORDERED = 4, |
374 | GIF_FREE_VFS_INODE = 5, | ||
374 | }; | 375 | }; |
375 | 376 | ||
376 | struct gfs2_inode { | 377 | struct gfs2_inode { |
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 69ed57a980d0..28cc7bf6575a 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -597,7 +597,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, | |||
597 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 597 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
598 | struct gfs2_glock *io_gl; | 598 | struct gfs2_glock *io_gl; |
599 | struct dentry *d; | 599 | struct dentry *d; |
600 | int error; | 600 | int error, free_vfs_inode = 0; |
601 | u32 aflags = 0; | 601 | u32 aflags = 0; |
602 | unsigned blocks = 1; | 602 | unsigned blocks = 1; |
603 | struct gfs2_diradd da = { .bh = NULL, }; | 603 | struct gfs2_diradd da = { .bh = NULL, }; |
@@ -788,15 +788,16 @@ fail_free_acls: | |||
788 | if (acl) | 788 | if (acl) |
789 | posix_acl_release(acl); | 789 | posix_acl_release(acl); |
790 | fail_free_vfs_inode: | 790 | fail_free_vfs_inode: |
791 | free_inode_nonrcu(inode); | 791 | free_vfs_inode = 1; |
792 | inode = NULL; | ||
793 | fail_gunlock: | 792 | fail_gunlock: |
794 | gfs2_dir_no_add(&da); | 793 | gfs2_dir_no_add(&da); |
795 | gfs2_glock_dq_uninit(ghs); | 794 | gfs2_glock_dq_uninit(ghs); |
796 | if (inode && !IS_ERR(inode)) { | 795 | if (inode && !IS_ERR(inode)) { |
797 | clear_nlink(inode); | 796 | clear_nlink(inode); |
798 | mark_inode_dirty(inode); | 797 | if (!free_vfs_inode) |
799 | set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags); | 798 | mark_inode_dirty(inode); |
799 | set_bit(free_vfs_inode ? GIF_FREE_VFS_INODE : GIF_ALLOC_FAILED, | ||
800 | &GFS2_I(inode)->i_flags); | ||
800 | iput(inode); | 801 | iput(inode); |
801 | } | 802 | } |
802 | fail: | 803 | fail: |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index a08c66e270bf..29cacd57516a 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
@@ -1248,7 +1248,7 @@ static int gfs2_drop_inode(struct inode *inode) | |||
1248 | { | 1248 | { |
1249 | struct gfs2_inode *ip = GFS2_I(inode); | 1249 | struct gfs2_inode *ip = GFS2_I(inode); |
1250 | 1250 | ||
1251 | if (inode->i_nlink) { | 1251 | if (!test_bit(GIF_FREE_VFS_INODE, &ip->i_flags) && inode->i_nlink) { |
1252 | struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl; | 1252 | struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl; |
1253 | if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags)) | 1253 | if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags)) |
1254 | clear_nlink(inode); | 1254 | clear_nlink(inode); |
@@ -1463,6 +1463,11 @@ static void gfs2_evict_inode(struct inode *inode) | |||
1463 | struct gfs2_holder gh; | 1463 | struct gfs2_holder gh; |
1464 | int error; | 1464 | int error; |
1465 | 1465 | ||
1466 | if (test_bit(GIF_FREE_VFS_INODE, &ip->i_flags)) { | ||
1467 | clear_inode(inode); | ||
1468 | return; | ||
1469 | } | ||
1470 | |||
1466 | if (inode->i_nlink || (sb->s_flags & MS_RDONLY)) | 1471 | if (inode->i_nlink || (sb->s_flags & MS_RDONLY)) |
1467 | goto out; | 1472 | goto out; |
1468 | 1473 | ||