add patch fix-zeroing-of-page-during-writeback
[ext4-patch-queue.git] / add-i_raw_lock
blob0b3859198bead486a48e08890c1348f32124c224
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 Reviewed-by: Jan Kara <jack@suse.cz>
8 ---
9  fs/ext4/ext4.h  |  2 ++
10  fs/ext4/inode.c | 41 ++++++++++++++++++++++-------------------
11  fs/ext4/super.c |  1 +
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
16 --- a/fs/ext4/ext4.h
17 +++ b/fs/ext4/ext4.h
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 */
24         /*
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
29 --- a/fs/ext4/inode.c
30 +++ b/fs/ext4/inode.c
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;
39         uid_t i_uid;
40         gid_t i_gid;
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);
56                 goto out_brelse;
57 +       }
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,
62                 need_datasync = 1;
63         }
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.
72 -                        */
73 -                       err = ext4_journal_get_write_access(handle,
74 -                                       EXT4_SB(sb)->s_sbh);
75 -                       if (err)
76 -                               goto out_brelse;
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);
82 -               }
83 +                   cpu_to_le32(EXT4_GOOD_OLD_REV))
84 +                       set_large_file = 1;
85         }
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);
96         if (!err)
97                 err = rc;
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);
102 +               if (err)
103 +                       goto out_brelse;
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);
109 +       }
110         ext4_update_inode_fsync_trans(handle, inode, need_datasync);
111  out_brelse:
112         brelse(bh);
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)
118                 return NULL;
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);