From: Mingming Cao This patch fixed another use-before-initialize bug in ext3 reservation code. There are some error path in ext3_new_inode() which calls iput() before we initialize the reservation fields, then iput() will call ext3_discard_reservation(), there we will deference an uninitilized pointer. That cause oops happen. We have seen exactly same problem on ext3_read_inode() and fixed that. On ext3_read_inode() error path, it also calls ext3_discard_reservation before the reservation window initialized. The solution at that time is avoid ext3_discard_reservation() for bad inode (add a check in ext3_clear_inode()). This seems not a good solution for ext3_new_inode() case. This patch should fix both try-to-discard-uninitialized-reservation problems. The solution here is to mark the reservation window as un-allocated in the path to call ext3_discard_reservation(), to make sure we don't remove reservation window node that not linked to the per-fs reservation tree. Signed-off-by: Andrew Morton --- 25-akpm/fs/ext3/balloc.c | 6 +++--- 25-akpm/fs/ext3/ialloc.c | 4 ++-- 25-akpm/fs/ext3/inode.c | 2 ++ 25-akpm/fs/ext3/super.c | 8 ++++---- 25-akpm/include/linux/ext3_fs.h | 1 + 5 files changed, 12 insertions(+), 9 deletions(-) diff -puN fs/ext3/balloc.c~ext3-rsv-use-before-initialise-fix fs/ext3/balloc.c --- 25/fs/ext3/balloc.c~ext3-rsv-use-before-initialise-fix 2004-10-21 14:54:22.773461400 -0700 +++ 25-akpm/fs/ext3/balloc.c 2004-10-21 14:54:22.784459728 -0700 @@ -248,8 +248,8 @@ void rsv_window_add(struct super_block * static void rsv_window_remove(struct super_block *sb, struct reserve_window_node *rsv) { - rsv->rsv_start = 0; - rsv->rsv_end = 0; + rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; atomic_set(&rsv->rsv_alloc_hit, 0); rb_erase(&rsv->rsv_node, &EXT3_SB(sb)->s_rsv_window_root); } @@ -257,7 +257,7 @@ static void rsv_window_remove(struct sup static inline int rsv_is_empty(struct reserve_window *rsv) { /* a valid reservation end block could not be 0 */ - return (rsv->_rsv_end == 0); + return (rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED); } void ext3_discard_reservation(struct inode *inode) diff -puN fs/ext3/ialloc.c~ext3-rsv-use-before-initialise-fix fs/ext3/ialloc.c --- 25/fs/ext3/ialloc.c~ext3-rsv-use-before-initialise-fix 2004-10-21 14:54:22.775461096 -0700 +++ 25-akpm/fs/ext3/ialloc.c 2004-10-21 14:54:22.784459728 -0700 @@ -582,8 +582,8 @@ got: ei->i_file_acl = 0; ei->i_dir_acl = 0; ei->i_dtime = 0; - ei->i_rsv_window.rsv_start = 0; - ei->i_rsv_window.rsv_end = 0; + ei->i_rsv_window.rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS); atomic_set(&ei->i_rsv_window.rsv_alloc_hit, 0); seqlock_init(&ei->i_rsv_window.rsv_seqlock); diff -puN fs/ext3/inode.c~ext3-rsv-use-before-initialise-fix fs/ext3/inode.c --- 25/fs/ext3/inode.c~ext3-rsv-use-before-initialise-fix 2004-10-21 14:54:22.776460944 -0700 +++ 25-akpm/fs/ext3/inode.c 2004-10-21 14:54:22.787459272 -0700 @@ -2409,6 +2409,8 @@ void ext3_read_inode(struct inode * inod ei->i_acl = EXT3_ACL_NOT_CACHED; ei->i_default_acl = EXT3_ACL_NOT_CACHED; #endif + ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + if (ext3_get_inode_loc(inode, &iloc, 0)) goto bad_inode; bh = iloc.bh; diff -puN fs/ext3/super.c~ext3-rsv-use-before-initialise-fix fs/ext3/super.c --- 25/fs/ext3/super.c~ext3-rsv-use-before-initialise-fix 2004-10-21 14:54:22.778460640 -0700 +++ 25-akpm/fs/ext3/super.c 2004-10-21 14:54:22.789458968 -0700 @@ -449,6 +449,7 @@ static struct inode *ext3_alloc_inode(st ei->i_acl = EXT3_ACL_NOT_CACHED; ei->i_default_acl = EXT3_ACL_NOT_CACHED; #endif + ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; ei->vfs_inode.i_version = 1; return &ei->vfs_inode; } @@ -504,8 +505,7 @@ static void ext3_clear_inode(struct inod EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED; } #endif - if (!is_bad_inode(inode)) - ext3_discard_reservation(inode); + ext3_discard_reservation(inode); } #ifdef CONFIG_QUOTA @@ -1484,8 +1484,8 @@ static int ext3_fill_super (struct super * reservation window list --- it gives us a placeholder for * append-at-start-of-list which makes the allocation logic * _much_ simpler. */ - sbi->s_rsv_window_head.rsv_start = 0; - sbi->s_rsv_window_head.rsv_end = 0; + sbi->s_rsv_window_head.rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + sbi->s_rsv_window_head.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; atomic_set(&sbi->s_rsv_window_head.rsv_alloc_hit, 0); atomic_set(&sbi->s_rsv_window_head.rsv_goal_size, 0); rsv_window_add(sb, &sbi->s_rsv_window_head); diff -puN include/linux/ext3_fs.h~ext3-rsv-use-before-initialise-fix include/linux/ext3_fs.h --- 25/include/linux/ext3_fs.h~ext3-rsv-use-before-initialise-fix 2004-10-21 14:54:22.779460488 -0700 +++ 25-akpm/include/linux/ext3_fs.h 2004-10-21 14:54:22.790458816 -0700 @@ -37,6 +37,7 @@ struct statfs; */ #define EXT3_DEFAULT_RESERVE_BLOCKS 8 #define EXT3_MAX_RESERVE_BLOCKS 1024 +#define EXT3_RESERVE_WINDOW_NOT_ALLOCATED 0 /* * Always enable hashed directories */ _