4.9-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Brian Foster <[email protected]>

commit 20e8a063786050083fe05b4f45be338c60b49126 upstream.

The quotacheck error handling of the delwri buffer list assumes the
resident buffers are locked and doesn't clear the _XBF_DELWRI_Q flag
on the buffers that are dequeued. This can lead to assert failures
on buffer release and possibly other locking problems.

Move this code to a delwri queue cancel helper function to
encapsulate the logic required to properly release buffers from a
delwri queue. Update the helper to clear the delwri queue flag and
call it from quotacheck.

Signed-off-by: Brian Foster <[email protected]>
Reviewed-by: Darrick J. Wong <[email protected]>
Signed-off-by: Darrick J. Wong <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 fs/xfs/xfs_buf.c |   24 ++++++++++++++++++++++++
 fs/xfs/xfs_buf.h |    1 +
 fs/xfs/xfs_qm.c  |    7 +------
 3 files changed, 26 insertions(+), 6 deletions(-)

--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -1066,6 +1066,8 @@ void
 xfs_buf_unlock(
        struct xfs_buf          *bp)
 {
+       ASSERT(xfs_buf_islocked(bp));
+
        XB_CLEAR_OWNER(bp);
        up(&bp->b_sema);
 
@@ -1804,6 +1806,28 @@ error:
 }
 
 /*
+ * Cancel a delayed write list.
+ *
+ * Remove each buffer from the list, clear the delwri queue flag and drop the
+ * associated buffer reference.
+ */
+void
+xfs_buf_delwri_cancel(
+       struct list_head        *list)
+{
+       struct xfs_buf          *bp;
+
+       while (!list_empty(list)) {
+               bp = list_first_entry(list, struct xfs_buf, b_list);
+
+               xfs_buf_lock(bp);
+               bp->b_flags &= ~_XBF_DELWRI_Q;
+               list_del_init(&bp->b_list);
+               xfs_buf_relse(bp);
+       }
+}
+
+/*
  * Add a buffer to the delayed write list.
  *
  * This queues a buffer for writeout if it hasn't already been.  Note that
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -329,6 +329,7 @@ extern void *xfs_buf_offset(struct xfs_b
 extern void xfs_buf_stale(struct xfs_buf *bp);
 
 /* Delayed Write Buffer Routines */
+extern void xfs_buf_delwri_cancel(struct list_head *);
 extern bool xfs_buf_delwri_queue(struct xfs_buf *, struct list_head *);
 extern int xfs_buf_delwri_submit(struct list_head *);
 extern int xfs_buf_delwri_submit_nowait(struct list_head *);
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -1384,12 +1384,7 @@ xfs_qm_quotacheck(
        mp->m_qflags |= flags;
 
  error_return:
-       while (!list_empty(&buffer_list)) {
-               struct xfs_buf *bp =
-                       list_first_entry(&buffer_list, struct xfs_buf, b_list);
-               list_del_init(&bp->b_list);
-               xfs_buf_relse(bp);
-       }
+       xfs_buf_delwri_cancel(&buffer_list);
 
        if (error) {
                xfs_warn(mp,


Reply via email to