gfs2: Fix iomap write page reclaim deadlock
Since commit64bc06bb32
("gfs2: iomap buffered write support"), gfs2 is doing buffered writes by starting a transaction in iomap_begin, writing a range of pages, and ending that transaction in iomap_end. This approach suffers from two problems: (1) Any allocations necessary for the write are done in iomap_begin, so when the data aren't journaled, there is no need for keeping the transaction open until iomap_end. (2) Transactions keep the gfs2 log flush lock held. When iomap_file_buffered_write calls balance_dirty_pages, this can end up calling gfs2_write_inode, which will try to flush the log. This requires taking the log flush lock which is already held, resulting in a deadlock. Fix both of these issues by not keeping transactions open from iomap_begin to iomap_end. Instead, start a small transaction in page_prepare and end it in page_done when necessary. Reported-by: Edwin Török <edvin.torok@citrix.com> Fixes:64bc06bb32
("gfs2: iomap buffered write support") Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
This commit is contained in:
@@ -649,7 +649,7 @@ out_uninit:
|
||||
*/
|
||||
void adjust_fs_space(struct inode *inode)
|
||||
{
|
||||
struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
|
||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
|
||||
struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
|
||||
struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
|
||||
@@ -657,10 +657,13 @@ void adjust_fs_space(struct inode *inode)
|
||||
struct buffer_head *m_bh, *l_bh;
|
||||
u64 fs_total, new_free;
|
||||
|
||||
if (gfs2_trans_begin(sdp, 2 * RES_STATFS, 0) != 0)
|
||||
return;
|
||||
|
||||
/* Total up the file system space, according to the latest rindex. */
|
||||
fs_total = gfs2_ri_total(sdp);
|
||||
if (gfs2_meta_inode_buffer(m_ip, &m_bh) != 0)
|
||||
return;
|
||||
goto out;
|
||||
|
||||
spin_lock(&sdp->sd_statfs_spin);
|
||||
gfs2_statfs_change_in(m_sc, m_bh->b_data +
|
||||
@@ -675,11 +678,14 @@ void adjust_fs_space(struct inode *inode)
|
||||
gfs2_statfs_change(sdp, new_free, new_free, 0);
|
||||
|
||||
if (gfs2_meta_inode_buffer(l_ip, &l_bh) != 0)
|
||||
goto out;
|
||||
goto out2;
|
||||
update_statfs(sdp, m_bh, l_bh);
|
||||
brelse(l_bh);
|
||||
out:
|
||||
out2:
|
||||
brelse(m_bh);
|
||||
out:
|
||||
sdp->sd_rindex_uptodate = 0;
|
||||
gfs2_trans_end(sdp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user