aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlos Maiolino <cmaiolino@redhat.com>2017-11-28 11:54:10 -0500
committerDarrick J. Wong <darrick.wong@oracle.com>2017-11-30 11:47:40 -0500
commit373b0589dc8d58bc09c9a28d03611ae4fb216057 (patch)
treeb5ed363a432290a113e2f59a05d24973a629d437
parent3b42d385753c22b29d259ccb9d4c3f419e583b30 (diff)
xfs: Properly retry failed dquot items in case of error during buffer writeback
Once the inode item writeback errors is already fixed, it's time to fix the same problem in dquot code. Although there were no reports of users hitting this bug in dquot code (at least none I've seen), the bug is there and I was already planning to fix it when the correct approach to fix the inodes part was decided. This patch aims to fix the same problem in dquot code, regarding failed buffers being unable to be resubmitted once they are flush locked. Tested with the recently test-case sent to fstests list by Hou Tao. Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r--fs/xfs/xfs_dquot.c14
-rw-r--r--fs/xfs/xfs_dquot_item.c40
2 files changed, 49 insertions, 5 deletions
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index d57c2db64e59..f248708c10ff 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -970,14 +970,22 @@ xfs_qm_dqflush_done(
970 * holding the lock before removing the dquot from the AIL. 970 * holding the lock before removing the dquot from the AIL.
971 */ 971 */
972 if ((lip->li_flags & XFS_LI_IN_AIL) && 972 if ((lip->li_flags & XFS_LI_IN_AIL) &&
973 lip->li_lsn == qip->qli_flush_lsn) { 973 ((lip->li_lsn == qip->qli_flush_lsn) ||
974 (lip->li_flags & XFS_LI_FAILED))) {
974 975
975 /* xfs_trans_ail_delete() drops the AIL lock. */ 976 /* xfs_trans_ail_delete() drops the AIL lock. */
976 spin_lock(&ailp->xa_lock); 977 spin_lock(&ailp->xa_lock);
977 if (lip->li_lsn == qip->qli_flush_lsn) 978 if (lip->li_lsn == qip->qli_flush_lsn) {
978 xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE); 979 xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE);
979 else 980 } else {
981 /*
982 * Clear the failed state since we are about to drop the
983 * flush lock
984 */
985 if (lip->li_flags & XFS_LI_FAILED)
986 xfs_clear_li_failed(lip);
980 spin_unlock(&ailp->xa_lock); 987 spin_unlock(&ailp->xa_lock);
988 }
981 } 989 }
982 990
983 /* 991 /*
diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
index 2c7a1629e064..664dea105e76 100644
--- a/fs/xfs/xfs_dquot_item.c
+++ b/fs/xfs/xfs_dquot_item.c
@@ -137,6 +137,26 @@ xfs_qm_dqunpin_wait(
137 wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); 137 wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0));
138} 138}
139 139
140/*
141 * Callback used to mark a buffer with XFS_LI_FAILED when items in the buffer
142 * have been failed during writeback
143 *
144 * this informs the AIL that the dquot is already flush locked on the next push,
145 * and acquires a hold on the buffer to ensure that it isn't reclaimed before
146 * dirty data makes it to disk.
147 */
148STATIC void
149xfs_dquot_item_error(
150 struct xfs_log_item *lip,
151 struct xfs_buf *bp)
152{
153 struct xfs_dquot *dqp;
154
155 dqp = DQUOT_ITEM(lip)->qli_dquot;
156 ASSERT(!completion_done(&dqp->q_flush));
157 xfs_set_li_failed(lip, bp);
158}
159
140STATIC uint 160STATIC uint
141xfs_qm_dquot_logitem_push( 161xfs_qm_dquot_logitem_push(
142 struct xfs_log_item *lip, 162 struct xfs_log_item *lip,
@@ -144,13 +164,28 @@ xfs_qm_dquot_logitem_push(
144 __acquires(&lip->li_ailp->xa_lock) 164 __acquires(&lip->li_ailp->xa_lock)
145{ 165{
146 struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; 166 struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
147 struct xfs_buf *bp = NULL; 167 struct xfs_buf *bp = lip->li_buf;
148 uint rval = XFS_ITEM_SUCCESS; 168 uint rval = XFS_ITEM_SUCCESS;
149 int error; 169 int error;
150 170
151 if (atomic_read(&dqp->q_pincount) > 0) 171 if (atomic_read(&dqp->q_pincount) > 0)
152 return XFS_ITEM_PINNED; 172 return XFS_ITEM_PINNED;
153 173
174 /*
175 * The buffer containing this item failed to be written back
176 * previously. Resubmit the buffer for IO
177 */
178 if (lip->li_flags & XFS_LI_FAILED) {
179 if (!xfs_buf_trylock(bp))
180 return XFS_ITEM_LOCKED;
181
182 if (!xfs_buf_resubmit_failed_buffers(bp, lip, buffer_list))
183 rval = XFS_ITEM_FLUSHING;
184
185 xfs_buf_unlock(bp);
186 return rval;
187 }
188
154 if (!xfs_dqlock_nowait(dqp)) 189 if (!xfs_dqlock_nowait(dqp))
155 return XFS_ITEM_LOCKED; 190 return XFS_ITEM_LOCKED;
156 191
@@ -242,7 +277,8 @@ static const struct xfs_item_ops xfs_dquot_item_ops = {
242 .iop_unlock = xfs_qm_dquot_logitem_unlock, 277 .iop_unlock = xfs_qm_dquot_logitem_unlock,
243 .iop_committed = xfs_qm_dquot_logitem_committed, 278 .iop_committed = xfs_qm_dquot_logitem_committed,
244 .iop_push = xfs_qm_dquot_logitem_push, 279 .iop_push = xfs_qm_dquot_logitem_push,
245 .iop_committing = xfs_qm_dquot_logitem_committing 280 .iop_committing = xfs_qm_dquot_logitem_committing,
281 .iop_error = xfs_dquot_item_error
246}; 282};
247 283
248/* 284/*