This patch checks for and prevents the deadlock with a page in journalled writeback in __ext4_journalled_writepage(). It turns out that __ext4_journalled_writepage() may race with itself in another task (e.g., two tasks set the same mmap'ed page dirty and called msync(), one after the other), so we have to check/handle it. Signed-off-by: Mauricio Faria de Oliveira <mfo@xxxxxxxxxxxxx> --- fs/ext4/inode.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 574a062b8bcd..401313be8a5b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1910,6 +1910,7 @@ static noinline int __ext4_journalled_writepage(struct page *page, */ ejwp = kmem_cache_alloc(ext4_journalled_wb_page_cachep, GFP_KERNEL); +retry_journal: handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, ext4_writepage_trans_blocks(inode)); if (IS_ERR(handle)) { @@ -1948,7 +1949,20 @@ static noinline int __ext4_journalled_writepage(struct page *page, goto out; } - /* Data integrity writeback; have to wait and do it. */ + /* + * Data integrity writeback; have to wait and do it. + * + * Check for deadlock with page in journalled writeback + * (i.e. another task running/ran this function as well) + */ + if (ext4_check_journalled_writeback(handle, page)) { + get_page(page); + unlock_page(page); + ext4_journal_stop(handle); + ext4_start_commit_datasync(inode); + wait_on_page_writeback(page); + goto retry_journal; + } wait_on_page_writeback(page); } -- 2.20.1