add patch always-check-ext4_ext_find_extent-result
[ext4-patch-queue.git] / add-i_raw_lock
blob71ab6fe7972008687c8269b36d00b7b30b684479
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
4 (on-disk) inode.
6 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
7 ---
8  fs/ext4/ext4.h  |  2 ++
9  fs/ext4/inode.c | 41 ++++++++++++++++++++++-------------------
10  fs/ext4/super.c |  1 +
11  3 files changed, 25 insertions(+), 19 deletions(-)
13 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
14 index 86c2cda..1d08a1b 100644
15 --- a/fs/ext4/ext4.h
16 +++ b/fs/ext4/ext4.h
17 @@ -875,6 +875,8 @@ struct ext4_inode_info {
18         struct inode vfs_inode;
19         struct jbd2_inode *jinode;
21 +       spinlock_t i_raw_lock;  /* protects updates to the raw inode */
23         /*
24          * File creation time. Its function is same as that of
25          * struct timespec i_{a,c,m}time in the generic inode.
26 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
27 index 2eb5fad..7ae10f0 100644
28 --- a/fs/ext4/inode.c
29 +++ b/fs/ext4/inode.c
30 @@ -4306,12 +4306,15 @@ static int ext4_do_update_inode(handle_t *handle,
31         struct ext4_inode *raw_inode = ext4_raw_inode(iloc);
32         struct ext4_inode_info *ei = EXT4_I(inode);
33         struct buffer_head *bh = iloc->bh;
34 +       struct super_block *sb = inode->i_sb;
35         int err = 0, rc, block;
36 -       int need_datasync = 0;
37 +       int need_datasync = 0, set_large_file = 0;
38         uid_t i_uid;
39         gid_t i_gid;
41 -       /* For fields not not tracking in the in-memory inode,
42 +       spin_lock(&ei->i_raw_lock);
44 +       /* For fields not tracked in the in-memory inode,
45          * initialise them to zero for new inodes. */
46         if (ext4_test_inode_state(inode, EXT4_STATE_NEW))
47                 memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
48 @@ -4349,8 +4352,10 @@ static int ext4_do_update_inode(handle_t *handle,
49         EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
50         EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
52 -       if (ext4_inode_blocks_set(handle, raw_inode, ei))
53 +       if (ext4_inode_blocks_set(handle, raw_inode, ei)) {
54 +               spin_unlock(&ei->i_raw_lock);
55                 goto out_brelse;
56 +       }
57         raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
58         raw_inode->i_flags = cpu_to_le32(ei->i_flags & 0xFFFFFFFF);
59         if (likely(!test_opt2(inode->i_sb, HURD_COMPAT)))
60 @@ -4362,24 +4367,11 @@ static int ext4_do_update_inode(handle_t *handle,
61                 need_datasync = 1;
62         }
63         if (ei->i_disksize > 0x7fffffffULL) {
64 -               struct super_block *sb = inode->i_sb;
65                 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
66                                 EXT4_FEATURE_RO_COMPAT_LARGE_FILE) ||
67                                 EXT4_SB(sb)->s_es->s_rev_level ==
68 -                               cpu_to_le32(EXT4_GOOD_OLD_REV)) {
69 -                       /* If this is the first large file
70 -                        * created, add a flag to the superblock.
71 -                        */
72 -                       err = ext4_journal_get_write_access(handle,
73 -                                       EXT4_SB(sb)->s_sbh);
74 -                       if (err)
75 -                               goto out_brelse;
76 -                       ext4_update_dynamic_rev(sb);
77 -                       EXT4_SET_RO_COMPAT_FEATURE(sb,
78 -                                       EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
79 -                       ext4_handle_sync(handle);
80 -                       err = ext4_handle_dirty_super(handle, sb);
81 -               }
82 +                   cpu_to_le32(EXT4_GOOD_OLD_REV))
83 +                       set_large_file = 1;
84         }
85         raw_inode->i_generation = cpu_to_le32(inode->i_generation);
86         if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
87 @@ -4411,12 +4403,23 @@ static int ext4_do_update_inode(handle_t *handle,
89         ext4_inode_csum_set(inode, raw_inode, ei);
91 +       spin_unlock(&ei->i_raw_lock);
93         BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
94         rc = ext4_handle_dirty_metadata(handle, NULL, bh);
95         if (!err)
96                 err = rc;
97         ext4_clear_inode_state(inode, EXT4_STATE_NEW);
99 +       if (set_large_file) {
100 +               err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
101 +               if (err)
102 +                       goto out_brelse;
103 +               ext4_update_dynamic_rev(sb);
104 +               EXT4_SET_RO_COMPAT_FEATURE(sb,
105 +                                          EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
106 +               ext4_handle_sync(handle);
107 +               err = ext4_handle_dirty_super(handle, sb);
108 +       }
109         ext4_update_inode_fsync_trans(handle, inode, need_datasync);
110  out_brelse:
111         brelse(bh);
112 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
113 index c4895c1..1f8cb18 100644
114 --- a/fs/ext4/super.c
115 +++ b/fs/ext4/super.c
116 @@ -879,6 +879,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
117                 return NULL;
119         ei->vfs_inode.i_version = 1;
120 +       spin_lock_init(&ei->i_raw_lock);
121         INIT_LIST_HEAD(&ei->i_prealloc_list);
122         spin_lock_init(&ei->i_prealloc_lock);
123         ext4_es_init_tree(&ei->i_es_tree);