1 ext4: add a new spinlock i_raw_lock to protect the ext4's raw inode
3 To avoid potential data races, use a spinlock which protects the raw
6 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
7 Reviewed-by: Jan Kara <jack@suse.cz>
10 fs/ext4/inode.c | 41 ++++++++++++++++++++++-------------------
12 3 files changed, 25 insertions(+), 19 deletions(-)
14 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
15 index 86c2cda..1d08a1b 100644
18 @@ -875,6 +875,8 @@ struct ext4_inode_info {
19 struct inode vfs_inode;
20 struct jbd2_inode *jinode;
22 + spinlock_t i_raw_lock; /* protects updates to the raw inode */
25 * File creation time. Its function is same as that of
26 * struct timespec i_{a,c,m}time in the generic inode.
27 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
28 index 2eb5fad..7ae10f0 100644
31 @@ -4306,12 +4306,15 @@ static int ext4_do_update_inode(handle_t *handle,
32 struct ext4_inode *raw_inode = ext4_raw_inode(iloc);
33 struct ext4_inode_info *ei = EXT4_I(inode);
34 struct buffer_head *bh = iloc->bh;
35 + struct super_block *sb = inode->i_sb;
36 int err = 0, rc, block;
37 - int need_datasync = 0;
38 + int need_datasync = 0, set_large_file = 0;
42 - /* For fields not not tracking in the in-memory inode,
43 + spin_lock(&ei->i_raw_lock);
45 + /* For fields not tracked in the in-memory inode,
46 * initialise them to zero for new inodes. */
47 if (ext4_test_inode_state(inode, EXT4_STATE_NEW))
48 memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
49 @@ -4349,8 +4352,10 @@ static int ext4_do_update_inode(handle_t *handle,
50 EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
51 EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
53 - if (ext4_inode_blocks_set(handle, raw_inode, ei))
54 + if (ext4_inode_blocks_set(handle, raw_inode, ei)) {
55 + spin_unlock(&ei->i_raw_lock);
58 raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
59 raw_inode->i_flags = cpu_to_le32(ei->i_flags & 0xFFFFFFFF);
60 if (likely(!test_opt2(inode->i_sb, HURD_COMPAT)))
61 @@ -4362,24 +4367,11 @@ static int ext4_do_update_inode(handle_t *handle,
64 if (ei->i_disksize > 0x7fffffffULL) {
65 - struct super_block *sb = inode->i_sb;
66 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
67 EXT4_FEATURE_RO_COMPAT_LARGE_FILE) ||
68 EXT4_SB(sb)->s_es->s_rev_level ==
69 - cpu_to_le32(EXT4_GOOD_OLD_REV)) {
70 - /* If this is the first large file
71 - * created, add a flag to the superblock.
73 - err = ext4_journal_get_write_access(handle,
74 - EXT4_SB(sb)->s_sbh);
77 - ext4_update_dynamic_rev(sb);
78 - EXT4_SET_RO_COMPAT_FEATURE(sb,
79 - EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
80 - ext4_handle_sync(handle);
81 - err = ext4_handle_dirty_super(handle, sb);
83 + cpu_to_le32(EXT4_GOOD_OLD_REV))
86 raw_inode->i_generation = cpu_to_le32(inode->i_generation);
87 if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
88 @@ -4411,12 +4403,23 @@ static int ext4_do_update_inode(handle_t *handle,
90 ext4_inode_csum_set(inode, raw_inode, ei);
92 + spin_unlock(&ei->i_raw_lock);
94 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
95 rc = ext4_handle_dirty_metadata(handle, NULL, bh);
98 ext4_clear_inode_state(inode, EXT4_STATE_NEW);
100 + if (set_large_file) {
101 + err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
104 + ext4_update_dynamic_rev(sb);
105 + EXT4_SET_RO_COMPAT_FEATURE(sb,
106 + EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
107 + ext4_handle_sync(handle);
108 + err = ext4_handle_dirty_super(handle, sb);
110 ext4_update_inode_fsync_trans(handle, inode, need_datasync);
113 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
114 index c4895c1..1f8cb18 100644
115 --- a/fs/ext4/super.c
116 +++ b/fs/ext4/super.c
117 @@ -879,6 +879,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
120 ei->vfs_inode.i_version = 1;
121 + spin_lock_init(&ei->i_raw_lock);
122 INIT_LIST_HEAD(&ei->i_prealloc_list);
123 spin_lock_init(&ei->i_prealloc_lock);
124 ext4_es_init_tree(&ei->i_es_tree);