aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext3
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-05-21 17:46:51 -0400
committerJan Kara <jack@suse.cz>2014-05-22 11:26:11 -0400
commit166418ccefc3cec0e8de54515af826687f036895 (patch)
tree01a801811614e88c600632716746395ceac17b1f /fs/ext3
parent22e7478ddbcb670e33fab72d0bbe7c394c3a2c84 (diff)
ext3: Fix deadlock in data=journal mode when fs is frozen
When ext3 is used in data=journal mode, syncing filesystem makes sure all the data is committed in the journal but the data doesn't have to be checkpointed. ext3_freeze() then takes care of checkpointing all the data so all buffer heads are clean but pages can still have dangling dirty bits. So when flusher thread comes later when filesystem is frozen, it tries to write back dirty pages, ext3_journalled_writepage() tries to start a transaction and hangs waiting for frozen fs causing a deadlock because a holder of s_umount semaphore may be waiting for flusher thread to complete. The fix is luckily relatively easy. We don't have to start a transaction in ext3_journalled_writepage() when a page is just dirty (and doesn't have PageChecked set) because in that case all buffers should be already mapped (mapping must happen before writing a buffer to the journal) and it is enough to write them out. This optimization also solves the deadlock because block_write_full_page() will just find out there's no buffer to write and do nothing. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/ext3')
-rw-r--r--fs/ext3/inode.c33
1 files changed, 17 insertions, 16 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index f5157d0d1b43..695abe738a24 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1716,17 +1716,17 @@ static int ext3_journalled_writepage(struct page *page,
1716 WARN_ON_ONCE(IS_RDONLY(inode) && 1716 WARN_ON_ONCE(IS_RDONLY(inode) &&
1717 !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS)); 1717 !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS));
1718 1718
1719 if (ext3_journal_current_handle())
1720 goto no_write;
1721
1722 trace_ext3_journalled_writepage(page); 1719 trace_ext3_journalled_writepage(page);
1723 handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode));
1724 if (IS_ERR(handle)) {
1725 ret = PTR_ERR(handle);
1726 goto no_write;
1727 }
1728
1729 if (!page_has_buffers(page) || PageChecked(page)) { 1720 if (!page_has_buffers(page) || PageChecked(page)) {
1721 if (ext3_journal_current_handle())
1722 goto no_write;
1723
1724 handle = ext3_journal_start(inode,
1725 ext3_writepage_trans_blocks(inode));
1726 if (IS_ERR(handle)) {
1727 ret = PTR_ERR(handle);
1728 goto no_write;
1729 }
1730 /* 1730 /*
1731 * It's mmapped pagecache. Add buffers and journal it. There 1731 * It's mmapped pagecache. Add buffers and journal it. There
1732 * doesn't seem much point in redirtying the page here. 1732 * doesn't seem much point in redirtying the page here.
@@ -1749,17 +1749,18 @@ static int ext3_journalled_writepage(struct page *page,
1749 atomic_set(&EXT3_I(inode)->i_datasync_tid, 1749 atomic_set(&EXT3_I(inode)->i_datasync_tid,
1750 handle->h_transaction->t_tid); 1750 handle->h_transaction->t_tid);
1751 unlock_page(page); 1751 unlock_page(page);
1752 err = ext3_journal_stop(handle);
1753 if (!ret)
1754 ret = err;
1752 } else { 1755 } else {
1753 /* 1756 /*
1754 * It may be a page full of checkpoint-mode buffers. We don't 1757 * It is a page full of checkpoint-mode buffers. Go and write
1755 * really know unless we go poke around in the buffer_heads. 1758 * them. They should have been already mapped when they went
1756 * But block_write_full_page will do the right thing. 1759 * to the journal so provide NULL get_block function to catch
1760 * errors.
1757 */ 1761 */
1758 ret = block_write_full_page(page, ext3_get_block, wbc); 1762 ret = block_write_full_page(page, NULL, wbc);
1759 } 1763 }
1760 err = ext3_journal_stop(handle);
1761 if (!ret)
1762 ret = err;
1763out: 1764out:
1764 return ret; 1765 return ret;
1765 1766