Skip to content

Commit

Permalink
ext3: fix broken handling of EXT3_STATE_NEW
Browse files Browse the repository at this point in the history
In commit 9df9393 ("ext3: Use bitops to read/modify
EXT3_I(inode)->i_state") ext3 changed its internal 'i_state' variable to
use bitops for its state handling.  However, unline the same ext4
change, it didn't actually change the name of the field when it changed
the semantics of it.

As a result, an old use of 'i_state' remained in fs/ext3/ialloc.c that
initialized the field to EXT3_STATE_NEW.  And that does not work
_at_all_ when we're now working with individually named bits rather than
values that get masked.  So the code tried to mark the state to be new,
but in actual fact set the field to EXT3_STATE_JDATA.  Which makes no
sense at all, and screws up all the code that checks whether the inode
was newly allocated.

In particular, it made the xattr code unhappy, and caused various random
behavior, like apparently

	https://bugzilla.redhat.com/show_bug.cgi?id=577911

So fix the initialization, and rename the field to match ext4 so that we
don't have this happen again.

Cc: James Morris <[email protected]>
Cc: Stephen Smalley <[email protected]>
Cc: Daniel J Walsh <[email protected]>
Cc: Eric Paris <[email protected]>
Cc: Jan Kara <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
torvalds committed Mar 29, 2010
1 parent ad4ba05 commit de32982
Show file tree
Hide file tree
Showing 4 changed files with 8 additions and 6 deletions.
4 changes: 3 additions & 1 deletion fs/ext3/ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,9 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode)
inode->i_generation = sbi->s_next_generation++;
spin_unlock(&sbi->s_next_gen_lock);

ei->i_state = EXT3_STATE_NEW;
ei->i_state_flags = 0;
ext3_set_inode_state(inode, EXT3_STATE_NEW);

ei->i_extra_isize =
(EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ?
sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE : 0;
Expand Down
2 changes: 1 addition & 1 deletion fs/ext3/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2811,7 +2811,7 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;

ei->i_state = 0;
ei->i_state_flags = 0;
ei->i_dir_start_lookup = 0;
ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
/* We now have enough fields to check if the inode was active or not.
Expand Down
6 changes: 3 additions & 3 deletions include/linux/ext3_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -565,17 +565,17 @@ enum {

static inline int ext3_test_inode_state(struct inode *inode, int bit)
{
return test_bit(bit, &EXT3_I(inode)->i_state);
return test_bit(bit, &EXT3_I(inode)->i_state_flags);
}

static inline void ext3_set_inode_state(struct inode *inode, int bit)
{
set_bit(bit, &EXT3_I(inode)->i_state);
set_bit(bit, &EXT3_I(inode)->i_state_flags);
}

static inline void ext3_clear_inode_state(struct inode *inode, int bit)
{
clear_bit(bit, &EXT3_I(inode)->i_state);
clear_bit(bit, &EXT3_I(inode)->i_state_flags);
}
#else
/* Assume that user mode programs are passing in an ext3fs superblock, not
Expand Down
2 changes: 1 addition & 1 deletion include/linux/ext3_fs_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ struct ext3_inode_info {
* near to their parent directory's inode.
*/
__u32 i_block_group;
unsigned long i_state; /* Dynamic state flags for ext3 */
unsigned long i_state_flags; /* Dynamic state flags for ext3 */

/* block reservation info */
struct ext3_block_alloc_info *i_block_alloc_info;
Expand Down

0 comments on commit de32982

Please sign in to comment.