On Sat 12-04-14 19:20:14, Ted Tso wrote: > To avoid potential data races, use a spinlock which protects the raw > (on-disk) inode. > > Signed-off-by: "Theodore Ts'o" <tytso@xxxxxxx> The patch looks good. You can add: Reviewed-by: Jan Kara <jack@xxxxxxx> Honza > --- > fs/ext4/ext4.h | 2 ++ > fs/ext4/inode.c | 41 ++++++++++++++++++++++------------------- > fs/ext4/super.c | 1 + > 3 files changed, 25 insertions(+), 19 deletions(-) > > diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h > index 86c2cda..1d08a1b 100644 > --- a/fs/ext4/ext4.h > +++ b/fs/ext4/ext4.h > @@ -875,6 +875,8 @@ struct ext4_inode_info { > struct inode vfs_inode; > struct jbd2_inode *jinode; > > + spinlock_t i_raw_lock; /* protects updates to the raw inode */ > + > /* > * File creation time. Its function is same as that of > * struct timespec i_{a,c,m}time in the generic inode. > diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c > index 2eb5fad..7ae10f0 100644 > --- a/fs/ext4/inode.c > +++ b/fs/ext4/inode.c > @@ -4306,12 +4306,15 @@ static int ext4_do_update_inode(handle_t *handle, > struct ext4_inode *raw_inode = ext4_raw_inode(iloc); > struct ext4_inode_info *ei = EXT4_I(inode); > struct buffer_head *bh = iloc->bh; > + struct super_block *sb = inode->i_sb; > int err = 0, rc, block; > - int need_datasync = 0; > + int need_datasync = 0, set_large_file = 0; > uid_t i_uid; > gid_t i_gid; > > - /* For fields not not tracking in the in-memory inode, > + spin_lock(&ei->i_raw_lock); > + > + /* For fields not tracked in the in-memory inode, > * initialise them to zero for new inodes. */ > if (ext4_test_inode_state(inode, EXT4_STATE_NEW)) > memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); > @@ -4349,8 +4352,10 @@ static int ext4_do_update_inode(handle_t *handle, > EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode); > EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode); > > - if (ext4_inode_blocks_set(handle, raw_inode, ei)) > + if (ext4_inode_blocks_set(handle, raw_inode, ei)) { > + spin_unlock(&ei->i_raw_lock); > goto out_brelse; > + } > raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); > raw_inode->i_flags = cpu_to_le32(ei->i_flags & 0xFFFFFFFF); > if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) > @@ -4362,24 +4367,11 @@ static int ext4_do_update_inode(handle_t *handle, > need_datasync = 1; > } > if (ei->i_disksize > 0x7fffffffULL) { > - struct super_block *sb = inode->i_sb; > if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, > EXT4_FEATURE_RO_COMPAT_LARGE_FILE) || > EXT4_SB(sb)->s_es->s_rev_level == > - cpu_to_le32(EXT4_GOOD_OLD_REV)) { > - /* If this is the first large file > - * created, add a flag to the superblock. > - */ > - err = ext4_journal_get_write_access(handle, > - EXT4_SB(sb)->s_sbh); > - if (err) > - goto out_brelse; > - ext4_update_dynamic_rev(sb); > - EXT4_SET_RO_COMPAT_FEATURE(sb, > - EXT4_FEATURE_RO_COMPAT_LARGE_FILE); > - ext4_handle_sync(handle); > - err = ext4_handle_dirty_super(handle, sb); > - } > + cpu_to_le32(EXT4_GOOD_OLD_REV)) > + set_large_file = 1; > } > raw_inode->i_generation = cpu_to_le32(inode->i_generation); > if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { > @@ -4411,12 +4403,23 @@ static int ext4_do_update_inode(handle_t *handle, > > ext4_inode_csum_set(inode, raw_inode, ei); > > + spin_unlock(&ei->i_raw_lock); > + > BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); > rc = ext4_handle_dirty_metadata(handle, NULL, bh); > if (!err) > err = rc; > ext4_clear_inode_state(inode, EXT4_STATE_NEW); > - > + if (set_large_file) { > + err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); > + if (err) > + goto out_brelse; > + ext4_update_dynamic_rev(sb); > + EXT4_SET_RO_COMPAT_FEATURE(sb, > + EXT4_FEATURE_RO_COMPAT_LARGE_FILE); > + ext4_handle_sync(handle); > + err = ext4_handle_dirty_super(handle, sb); > + } > ext4_update_inode_fsync_trans(handle, inode, need_datasync); > out_brelse: > brelse(bh); > diff --git a/fs/ext4/super.c b/fs/ext4/super.c > index c4895c1..1f8cb18 100644 > --- a/fs/ext4/super.c > +++ b/fs/ext4/super.c > @@ -879,6 +879,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) > return NULL; > > ei->vfs_inode.i_version = 1; > + spin_lock_init(&ei->i_raw_lock); > INIT_LIST_HEAD(&ei->i_prealloc_list); > spin_lock_init(&ei->i_prealloc_lock); > ext4_es_init_tree(&ei->i_es_tree); > -- > 1.9.0 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Jan Kara <jack@xxxxxxx> SUSE Labs, CR -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html