diff options
author | Jan Kara <jack@suse.cz> | 2008-07-11 19:27:31 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2008-07-11 19:27:31 -0400 |
commit | cf108bca465dde0c015f32dd453b99457d31c7c7 (patch) | |
tree | b1c9dfc1936579e4fd2a48f77f702effc39029e2 /fs/ext4/extents.c | |
parent | c7d206b3379f7d6462e778b74f475c470ee3dcaf (diff) |
ext4: Invert the locking order of page_lock and transaction start
This changes are needed to support data=ordered mode handling via
inodes. This enables us to get rid of the journal heads and buffer
heads for data buffers in the ordered mode. With the changes, during
tranasaction commit we writeout the inode pages using the
writepages()/writepage(). That implies we take page lock during
transaction commit. This can cause a deadlock with the locking order
page_lock -> jbd2_journal_start, since the jbd2_journal_start can wait
for the journal_commit to happen and the journal_commit now needs to
take the page lock. To avoid this dead lock reverse the locking order.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Mingming Cao <cmm@us.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 15 |
1 files changed, 4 insertions, 11 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index bb36a28f8ff3..b722bce7d662 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -2749,7 +2749,7 @@ out2: | |||
2749 | return err ? err : allocated; | 2749 | return err ? err : allocated; |
2750 | } | 2750 | } |
2751 | 2751 | ||
2752 | void ext4_ext_truncate(struct inode * inode, struct page *page) | 2752 | void ext4_ext_truncate(struct inode *inode) |
2753 | { | 2753 | { |
2754 | struct address_space *mapping = inode->i_mapping; | 2754 | struct address_space *mapping = inode->i_mapping; |
2755 | struct super_block *sb = inode->i_sb; | 2755 | struct super_block *sb = inode->i_sb; |
@@ -2762,18 +2762,11 @@ void ext4_ext_truncate(struct inode * inode, struct page *page) | |||
2762 | */ | 2762 | */ |
2763 | err = ext4_writepage_trans_blocks(inode) + 3; | 2763 | err = ext4_writepage_trans_blocks(inode) + 3; |
2764 | handle = ext4_journal_start(inode, err); | 2764 | handle = ext4_journal_start(inode, err); |
2765 | if (IS_ERR(handle)) { | 2765 | if (IS_ERR(handle)) |
2766 | if (page) { | ||
2767 | clear_highpage(page); | ||
2768 | flush_dcache_page(page); | ||
2769 | unlock_page(page); | ||
2770 | page_cache_release(page); | ||
2771 | } | ||
2772 | return; | 2766 | return; |
2773 | } | ||
2774 | 2767 | ||
2775 | if (page) | 2768 | if (inode->i_size & (sb->s_blocksize - 1)) |
2776 | ext4_block_truncate_page(handle, page, mapping, inode->i_size); | 2769 | ext4_block_truncate_page(handle, mapping, inode->i_size); |
2777 | 2770 | ||
2778 | down_write(&EXT4_I(inode)->i_data_sem); | 2771 | down_write(&EXT4_I(inode)->i_data_sem); |
2779 | ext4_ext_invalidate_cache(inode); | 2772 | ext4_ext_invalidate_cache(inode); |