Commit ebd3610b authored by Jan Kara's avatar Jan Kara Committed by Theodore Ts'o

ext4: Fix deadlock in ext4_write_begin() and ext4_da_write_begin()

Functions ext4_write_begin() and ext4_da_write_begin() call
grab_cache_page_write_begin() without AOP_FLAG_NOFS. Thus it
can happen that page reclaim is triggered in that function
and it recurses back into the filesystem (or some other filesystem).
But this can lead to various problems as a transaction is already
started at that point. Add the necessary flag.

http://bugzilla.kernel.org/show_bug.cgi?id=11688Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 05bf9e83
...@@ -1368,6 +1368,10 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping, ...@@ -1368,6 +1368,10 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
goto out; goto out;
} }
/* We cannot recurse into the filesystem as the transaction is already
* started */
flags |= AOP_FLAG_NOFS;
page = grab_cache_page_write_begin(mapping, index, flags); page = grab_cache_page_write_begin(mapping, index, flags);
if (!page) { if (!page) {
ext4_journal_stop(handle); ext4_journal_stop(handle);
...@@ -1377,7 +1381,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping, ...@@ -1377,7 +1381,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
*pagep = page; *pagep = page;
ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ext4_get_block); ext4_get_block);
if (!ret && ext4_should_journal_data(inode)) { if (!ret && ext4_should_journal_data(inode)) {
ret = walk_page_buffers(handle, page_buffers(page), ret = walk_page_buffers(handle, page_buffers(page),
...@@ -2667,6 +2671,9 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, ...@@ -2667,6 +2671,9 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
ret = PTR_ERR(handle); ret = PTR_ERR(handle);
goto out; goto out;
} }
/* We cannot recurse into the filesystem as the transaction is already
* started */
flags |= AOP_FLAG_NOFS;
page = grab_cache_page_write_begin(mapping, index, flags); page = grab_cache_page_write_begin(mapping, index, flags);
if (!page) { if (!page) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment