aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2019-07-27 17:12:54 +0200
committerAndreas Gruenbacher <agruenba@redhat.com>2019-07-31 18:51:50 +0200
commit706cb5492c8c459199fa0ab3b5fd2ba54ee53b0c (patch)
treef3d0e8df11ecdec00a54b6c96f5a433995a1ae02 /fs
parentLinux 5.3-rc2 (diff)
downloadlinux-dev-706cb5492c8c459199fa0ab3b5fd2ba54ee53b0c.tar.xz
linux-dev-706cb5492c8c459199fa0ab3b5fd2ba54ee53b0c.zip
gfs2: Inode dirtying fix
With the recent iomap write page reclaim deadlock fix, it turns out that the GLF_DIRTY flag isn't always set when it needs to be anymore: previously, this happened as a side effect of always adding the inode buffer head to the current transaction with gfs2_trans_add_meta, but this isn't happening consistently anymore. Fix by removing an additional unnecessary gfs2_trans_add_meta call and by setting the GLF_DIRTY flag in gfs2_iomap_end. (The GLF_DIRTY flag causes inode_go_sync to flush the transaction log when syncing out the glock of that inode. When the flag isn't set, inode_go_sync will skip inodes, including ones with an i_state of I_DIRTY_PAGES, which will lead to cluster incoherency.) In addition, in gfs2_iomap_page_done, if the metadata has changed, mark the inode as I_DIRTY_DATASYNC to have the inode added to the current transaction: we don't expect metadata to change here, but let's err on the safe side. Fixes: d0a22a4b03b8 ("gfs2: Fix iomap write page reclaim deadlock"); Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/bmap.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 79581b9bdebb..4df26ef2b2b1 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1002,11 +1002,16 @@ static void gfs2_iomap_page_done(struct inode *inode, loff_t pos,
unsigned copied, struct page *page,
struct iomap *iomap)
{
+ struct gfs2_trans *tr = current->journal_info;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
if (page && !gfs2_is_stuffed(ip))
gfs2_page_add_databufs(ip, page, offset_in_page(pos), copied);
+
+ if (tr->tr_num_buf_new)
+ __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+
gfs2_trans_end(sdp);
}
@@ -1099,8 +1104,6 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
tr = current->journal_info;
if (tr->tr_num_buf_new)
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
- else
- gfs2_trans_add_meta(ip->i_gl, mp->mp_bh[0]);
gfs2_trans_end(sdp);
}
@@ -1181,10 +1184,16 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
if (ip->i_qadata && ip->i_qadata->qa_qd_num)
gfs2_quota_unlock(ip);
+
+ if (unlikely(!written))
+ goto out_unlock;
+
if (iomap->flags & IOMAP_F_SIZE_CHANGED)
mark_inode_dirty(inode);
- gfs2_write_unlock(inode);
+ set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
+out_unlock:
+ gfs2_write_unlock(inode);
out:
return 0;
}