Hi Greg,
This 5.4.y backport series contains patches which fix XFS bugs introduced by patches which were recently backported from v5.7. The patchset has been acked by Darrick.
Brian Foster (1): xfs: finish dfops on every insert range shift iteration
Darrick J. Wong (2): xfs: clear XFS_DQ_FREEING if we can't lock the dquot buffer to flush xfs: force the log after remapping a synchronous-writes file
fs/xfs/xfs_bmap_util.c | 2 +- fs/xfs/xfs_file.c | 17 ++++++++++++++++- fs/xfs/xfs_qm.c | 1 + 3 files changed, 18 insertions(+), 2 deletions(-)
From: Brian Foster bfoster@redhat.com
commit 9c516e0e4554e8f26ab73d46cbc789d7d8db664d upstream.
The recent change to make insert range an atomic operation used the incorrect transaction rolling mechanism. The explicit transaction roll does not finish deferred operations. This means that intents for rmapbt updates caused by extent shifts are not logged until the final transaction commits. Thus if a crash occurs during an insert range, log recovery might leave the rmapbt in an inconsistent state. This was discovered by repeated runs of generic/455.
Update insert range to finish dfops on every shift iteration. This is similar to collapse range and ensures that intents are logged with the transactions that make associated changes.
Fixes: dd87f87d87fa ("xfs: rework insert range into an atomic operation") Signed-off-by: Brian Foster bfoster@redhat.com Reviewed-by: Darrick J. Wong darrick.wong@oracle.com Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Acked-by: Darrick J. Wong djwong@kernel.org Signed-off-by: Chandan Babu R chandan.babu@oracle.com --- fs/xfs/xfs_bmap_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 5b211cb8b579..12c12c2ef241 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -1340,7 +1340,7 @@ xfs_insert_file_space( goto out_trans_cancel;
do { - error = xfs_trans_roll_inode(&tp, ip); + error = xfs_defer_finish(&tp); if (error) goto out_trans_cancel;
From: "Darrick J. Wong" darrick.wong@oracle.com
commit c97738a960a86081a147e7d436138e6481757445 upstream.
In commit 8d3d7e2b35ea, we changed xfs_qm_dqpurge to bail out if we can't lock the dquot buf to flush the dquot. This prevents the AIL from blocking on the dquot, but it also forgets to clear the FREEING flag on its way out. A subsequent purge attempt will see the FREEING flag is set and bail out, which leads to dqpurge_all failing to purge all the dquots.
(copy-pasting from Dave Chinner's identical patch)
This was found by inspection after having xfs/305 hang 1 in ~50 iterations in a quotaoff operation:
[ 8872.301115] xfs_quota D13888 92262 91813 0x00004002 [ 8872.302538] Call Trace: [ 8872.303193] __schedule+0x2d2/0x780 [ 8872.304108] ? do_raw_spin_unlock+0x57/0xd0 [ 8872.305198] schedule+0x6e/0xe0 [ 8872.306021] schedule_timeout+0x14d/0x300 [ 8872.307060] ? __next_timer_interrupt+0xe0/0xe0 [ 8872.308231] ? xfs_qm_dqusage_adjust+0x200/0x200 [ 8872.309422] schedule_timeout_uninterruptible+0x2a/0x30 [ 8872.310759] xfs_qm_dquot_walk.isra.0+0x15a/0x1b0 [ 8872.311971] xfs_qm_dqpurge_all+0x7f/0x90 [ 8872.313022] xfs_qm_scall_quotaoff+0x18d/0x2b0 [ 8872.314163] xfs_quota_disable+0x3a/0x60 [ 8872.315179] kernel_quotactl+0x7e2/0x8d0 [ 8872.316196] ? __do_sys_newstat+0x51/0x80 [ 8872.317238] __x64_sys_quotactl+0x1e/0x30 [ 8872.318266] do_syscall_64+0x46/0x90 [ 8872.319193] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 8872.320490] RIP: 0033:0x7f46b5490f2a [ 8872.321414] Code: Bad RIP value.
Returning -EAGAIN from xfs_qm_dqpurge() without clearing the XFS_DQ_FREEING flag means the xfs_qm_dqpurge_all() code can never free the dquot, and we loop forever waiting for the XFS_DQ_FREEING flag to go away on the dquot that leaked it via -EAGAIN.
Fixes: 8d3d7e2b35ea ("xfs: trylock underlying buffer on dquot flush") Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Reviewed-by: Allison Collins allison.henderson@oracle.com Reviewed-by: Chandan Babu R chandanrlinux@gmail.com Reviewed-by: Christoph Hellwig hch@lst.de Reviewed-by: Brian Foster bfoster@redhat.com Signed-off-by: Dave Chinner dchinner@redhat.com Reviewed-by: Dave Chinner dchinner@redhat.com Acked-by: Darrick J. Wong djwong@kernel.org Signed-off-by: Chandan Babu R chandan.babu@oracle.com --- fs/xfs/xfs_qm.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index ef2faee96909..6b23ebd3f54f 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -148,6 +148,7 @@ xfs_qm_dqpurge( error = xfs_bwrite(bp); xfs_buf_relse(bp); } else if (error == -EAGAIN) { + dqp->dq_flags &= ~XFS_DQ_FREEING; goto out_unlock; } xfs_dqflock(dqp);
From: "Darrick J. Wong" darrick.wong@oracle.com
commit 5ffce3cc22a0e89813ed0c7162a68b639aef9ab6 upstream.
Commit 5833112df7e9 tried to make it so that a remap operation would force the log out to disk if the filesystem is mounted with mandatory synchronous writes. Unfortunately, that commit failed to handle the case where the inode or the file descriptor require mandatory synchronous writes.
Refactor the check into into a helper that will look for all three conditions, and now we can treat reflink just like any other synchronous write.
Fixes: 5833112df7e9 ("xfs: reflink should force the log out if mounted with wsync") Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Reviewed-by: Brian Foster bfoster@redhat.com Reviewed-by: Christoph Hellwig hch@lst.de Acked-by: Darrick J. Wong djwong@kernel.org Signed-off-by: Chandan Babu R chandan.babu@oracle.com --- fs/xfs/xfs_file.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index cbca91b4b5b8..c67fab2c37c5 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -990,6 +990,21 @@ xfs_file_fadvise( return ret; }
+/* Does this file, inode, or mount want synchronous writes? */ +static inline bool xfs_file_sync_writes(struct file *filp) +{ + struct xfs_inode *ip = XFS_I(file_inode(filp)); + + if (ip->i_mount->m_flags & XFS_MOUNT_WSYNC) + return true; + if (filp->f_flags & (__O_SYNC | O_DSYNC)) + return true; + if (IS_SYNC(file_inode(filp))) + return true; + + return false; +} + STATIC loff_t xfs_file_remap_range( struct file *file_in, @@ -1047,7 +1062,7 @@ xfs_file_remap_range( if (ret) goto out_unlock;
- if (mp->m_flags & XFS_MOUNT_WSYNC) + if (xfs_file_sync_writes(file_in) || xfs_file_sync_writes(file_out)) xfs_log_force_inode(dest); out_unlock: xfs_reflink_remap_unlock(file_in, file_out);
linux-stable-mirror@lists.linaro.org