diff options
author | Theodore Ts'o <tytso@mit.edu> | 2010-01-24 14:34:07 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2010-01-24 14:34:07 -0500 |
commit | 19f5fb7ad679bb361222c7916086435020c37cce (patch) | |
tree | 9e301163075c4faaf340cf50afd51855c76acd8c /fs/ext4/inode.c | |
parent | d2eecb03936878ec574ade5532fa83df7d75dde7 (diff) |
ext4: Use bitops to read/modify EXT4_I(inode)->i_state
At several places we modify EXT4_I(inode)->i_state without holding
i_mutex (ext4_release_file, ext4_bmap, ext4_journalled_writepage,
ext4_do_update_inode, ...). These modifications are racy and we can
lose updates to i_state. So convert handling of i_state to use bitops
which are atomic.
Cc: Jan Kara <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 38 |
1 files changed, 20 insertions, 18 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 1a3d7b232cd7..3e530119d7f0 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -1307,7 +1307,7 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block, | |||
1307 | * i_data's format changing. Force the migrate | 1307 | * i_data's format changing. Force the migrate |
1308 | * to fail by clearing migrate flags | 1308 | * to fail by clearing migrate flags |
1309 | */ | 1309 | */ |
1310 | EXT4_I(inode)->i_state &= ~EXT4_STATE_EXT_MIGRATE; | 1310 | ext4_clear_inode_state(inode, EXT4_STATE_EXT_MIGRATE); |
1311 | } | 1311 | } |
1312 | 1312 | ||
1313 | /* | 1313 | /* |
@@ -1794,7 +1794,7 @@ static int ext4_journalled_write_end(struct file *file, | |||
1794 | new_i_size = pos + copied; | 1794 | new_i_size = pos + copied; |
1795 | if (new_i_size > inode->i_size) | 1795 | if (new_i_size > inode->i_size) |
1796 | i_size_write(inode, pos+copied); | 1796 | i_size_write(inode, pos+copied); |
1797 | EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; | 1797 | ext4_set_inode_state(inode, EXT4_STATE_JDATA); |
1798 | if (new_i_size > EXT4_I(inode)->i_disksize) { | 1798 | if (new_i_size > EXT4_I(inode)->i_disksize) { |
1799 | ext4_update_i_disksize(inode, new_i_size); | 1799 | ext4_update_i_disksize(inode, new_i_size); |
1800 | ret2 = ext4_mark_inode_dirty(handle, inode); | 1800 | ret2 = ext4_mark_inode_dirty(handle, inode); |
@@ -2632,7 +2632,7 @@ static int __ext4_journalled_writepage(struct page *page, | |||
2632 | ret = err; | 2632 | ret = err; |
2633 | 2633 | ||
2634 | walk_page_buffers(handle, page_bufs, 0, len, NULL, bput_one); | 2634 | walk_page_buffers(handle, page_bufs, 0, len, NULL, bput_one); |
2635 | EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; | 2635 | ext4_set_inode_state(inode, EXT4_STATE_JDATA); |
2636 | out: | 2636 | out: |
2637 | return ret; | 2637 | return ret; |
2638 | } | 2638 | } |
@@ -3303,7 +3303,8 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block) | |||
3303 | filemap_write_and_wait(mapping); | 3303 | filemap_write_and_wait(mapping); |
3304 | } | 3304 | } |
3305 | 3305 | ||
3306 | if (EXT4_JOURNAL(inode) && EXT4_I(inode)->i_state & EXT4_STATE_JDATA) { | 3306 | if (EXT4_JOURNAL(inode) && |
3307 | ext4_test_inode_state(inode, EXT4_STATE_JDATA)) { | ||
3307 | /* | 3308 | /* |
3308 | * This is a REALLY heavyweight approach, but the use of | 3309 | * This is a REALLY heavyweight approach, but the use of |
3309 | * bmap on dirty files is expected to be extremely rare: | 3310 | * bmap on dirty files is expected to be extremely rare: |
@@ -3322,7 +3323,7 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block) | |||
3322 | * everything they get. | 3323 | * everything they get. |
3323 | */ | 3324 | */ |
3324 | 3325 | ||
3325 | EXT4_I(inode)->i_state &= ~EXT4_STATE_JDATA; | 3326 | ext4_clear_inode_state(inode, EXT4_STATE_JDATA); |
3326 | journal = EXT4_JOURNAL(inode); | 3327 | journal = EXT4_JOURNAL(inode); |
3327 | jbd2_journal_lock_updates(journal); | 3328 | jbd2_journal_lock_updates(journal); |
3328 | err = jbd2_journal_flush(journal); | 3329 | err = jbd2_journal_flush(journal); |
@@ -3790,8 +3791,8 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, | |||
3790 | if (ret != -EIOCBQUEUED && ret <= 0 && iocb->private) { | 3791 | if (ret != -EIOCBQUEUED && ret <= 0 && iocb->private) { |
3791 | ext4_free_io_end(iocb->private); | 3792 | ext4_free_io_end(iocb->private); |
3792 | iocb->private = NULL; | 3793 | iocb->private = NULL; |
3793 | } else if (ret > 0 && (EXT4_I(inode)->i_state & | 3794 | } else if (ret > 0 && ext4_test_inode_state(inode, |
3794 | EXT4_STATE_DIO_UNWRITTEN)) { | 3795 | EXT4_STATE_DIO_UNWRITTEN)) { |
3795 | int err; | 3796 | int err; |
3796 | /* | 3797 | /* |
3797 | * for non AIO case, since the IO is already | 3798 | * for non AIO case, since the IO is already |
@@ -3801,7 +3802,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, | |||
3801 | offset, ret); | 3802 | offset, ret); |
3802 | if (err < 0) | 3803 | if (err < 0) |
3803 | ret = err; | 3804 | ret = err; |
3804 | EXT4_I(inode)->i_state &= ~EXT4_STATE_DIO_UNWRITTEN; | 3805 | ext4_clear_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN); |
3805 | } | 3806 | } |
3806 | return ret; | 3807 | return ret; |
3807 | } | 3808 | } |
@@ -4457,7 +4458,7 @@ void ext4_truncate(struct inode *inode) | |||
4457 | return; | 4458 | return; |
4458 | 4459 | ||
4459 | if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC)) | 4460 | if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC)) |
4460 | ei->i_state |= EXT4_STATE_DA_ALLOC_CLOSE; | 4461 | ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE); |
4461 | 4462 | ||
4462 | if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) { | 4463 | if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) { |
4463 | ext4_ext_truncate(inode); | 4464 | ext4_ext_truncate(inode); |
@@ -4743,7 +4744,7 @@ int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc) | |||
4743 | { | 4744 | { |
4744 | /* We have all inode data except xattrs in memory here. */ | 4745 | /* We have all inode data except xattrs in memory here. */ |
4745 | return __ext4_get_inode_loc(inode, iloc, | 4746 | return __ext4_get_inode_loc(inode, iloc, |
4746 | !(EXT4_I(inode)->i_state & EXT4_STATE_XATTR)); | 4747 | !ext4_test_inode_state(inode, EXT4_STATE_XATTR)); |
4747 | } | 4748 | } |
4748 | 4749 | ||
4749 | void ext4_set_inode_flags(struct inode *inode) | 4750 | void ext4_set_inode_flags(struct inode *inode) |
@@ -4837,7 +4838,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4837 | } | 4838 | } |
4838 | inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); | 4839 | inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); |
4839 | 4840 | ||
4840 | ei->i_state = 0; | 4841 | ei->i_state_flags = 0; |
4841 | ei->i_dir_start_lookup = 0; | 4842 | ei->i_dir_start_lookup = 0; |
4842 | ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); | 4843 | ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); |
4843 | /* We now have enough fields to check if the inode was active or not. | 4844 | /* We now have enough fields to check if the inode was active or not. |
@@ -4920,7 +4921,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4920 | EXT4_GOOD_OLD_INODE_SIZE + | 4921 | EXT4_GOOD_OLD_INODE_SIZE + |
4921 | ei->i_extra_isize; | 4922 | ei->i_extra_isize; |
4922 | if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) | 4923 | if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) |
4923 | ei->i_state |= EXT4_STATE_XATTR; | 4924 | ext4_set_inode_state(inode, EXT4_STATE_XATTR); |
4924 | } | 4925 | } |
4925 | } else | 4926 | } else |
4926 | ei->i_extra_isize = 0; | 4927 | ei->i_extra_isize = 0; |
@@ -5060,7 +5061,7 @@ static int ext4_do_update_inode(handle_t *handle, | |||
5060 | 5061 | ||
5061 | /* For fields not not tracking in the in-memory inode, | 5062 | /* For fields not not tracking in the in-memory inode, |
5062 | * initialise them to zero for new inodes. */ | 5063 | * initialise them to zero for new inodes. */ |
5063 | if (ei->i_state & EXT4_STATE_NEW) | 5064 | if (ext4_test_inode_state(inode, EXT4_STATE_NEW)) |
5064 | memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); | 5065 | memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); |
5065 | 5066 | ||
5066 | ext4_get_inode_flags(ei); | 5067 | ext4_get_inode_flags(ei); |
@@ -5156,7 +5157,7 @@ static int ext4_do_update_inode(handle_t *handle, | |||
5156 | rc = ext4_handle_dirty_metadata(handle, inode, bh); | 5157 | rc = ext4_handle_dirty_metadata(handle, inode, bh); |
5157 | if (!err) | 5158 | if (!err) |
5158 | err = rc; | 5159 | err = rc; |
5159 | ei->i_state &= ~EXT4_STATE_NEW; | 5160 | ext4_clear_inode_state(inode, EXT4_STATE_NEW); |
5160 | 5161 | ||
5161 | ext4_update_inode_fsync_trans(handle, inode, 0); | 5162 | ext4_update_inode_fsync_trans(handle, inode, 0); |
5162 | out_brelse: | 5163 | out_brelse: |
@@ -5580,8 +5581,8 @@ static int ext4_expand_extra_isize(struct inode *inode, | |||
5580 | entry = IFIRST(header); | 5581 | entry = IFIRST(header); |
5581 | 5582 | ||
5582 | /* No extended attributes present */ | 5583 | /* No extended attributes present */ |
5583 | if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR) || | 5584 | if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) || |
5584 | header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) { | 5585 | header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) { |
5585 | memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0, | 5586 | memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0, |
5586 | new_extra_isize); | 5587 | new_extra_isize); |
5587 | EXT4_I(inode)->i_extra_isize = new_extra_isize; | 5588 | EXT4_I(inode)->i_extra_isize = new_extra_isize; |
@@ -5625,7 +5626,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) | |||
5625 | err = ext4_reserve_inode_write(handle, inode, &iloc); | 5626 | err = ext4_reserve_inode_write(handle, inode, &iloc); |
5626 | if (ext4_handle_valid(handle) && | 5627 | if (ext4_handle_valid(handle) && |
5627 | EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize && | 5628 | EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize && |
5628 | !(EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND)) { | 5629 | !ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) { |
5629 | /* | 5630 | /* |
5630 | * We need extra buffer credits since we may write into EA block | 5631 | * We need extra buffer credits since we may write into EA block |
5631 | * with this same handle. If journal_extend fails, then it will | 5632 | * with this same handle. If journal_extend fails, then it will |
@@ -5639,7 +5640,8 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) | |||
5639 | sbi->s_want_extra_isize, | 5640 | sbi->s_want_extra_isize, |
5640 | iloc, handle); | 5641 | iloc, handle); |
5641 | if (ret) { | 5642 | if (ret) { |
5642 | EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND; | 5643 | ext4_set_inode_state(inode, |
5644 | EXT4_STATE_NO_EXPAND); | ||
5643 | if (mnt_count != | 5645 | if (mnt_count != |
5644 | le16_to_cpu(sbi->s_es->s_mnt_count)) { | 5646 | le16_to_cpu(sbi->s_es->s_mnt_count)) { |
5645 | ext4_warning(inode->i_sb, __func__, | 5647 | ext4_warning(inode->i_sb, __func__, |