]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
xfs: fix up quotacheck buffer list error handling
authorBrian Foster <bfoster@redhat.com>
Fri, 21 Apr 2017 19:40:44 +0000 (12:40 -0700)
committerThadeu Lima de Souza Cascardo <cascardo@canonical.com>
Tue, 27 Jun 2017 13:16:19 +0000 (10:16 -0300)
BugLink: http://bugs.launchpad.net/bugs/1697001
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 <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_qm.c

index f71d896d5bcc8c36f25e7e8f84182b4822945b8a..ed706d1e47ab82acff4a1101ea24a040d8463b09 100644 (file)
@@ -979,6 +979,8 @@ void
 xfs_buf_unlock(
        struct xfs_buf          *bp)
 {
+       ASSERT(xfs_buf_islocked(bp));
+
        XB_CLEAR_OWNER(bp);
        up(&bp->b_sema);
 
@@ -1711,6 +1713,28 @@ error:
        return NULL;
 }
 
+/*
+ * 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.
  *
index ed6f49738a826a7b115036eca2f19c4942a9e0f3..3ea1f6db759481ee1a2af66b5021f2ee061da5c7 100644 (file)
@@ -303,6 +303,7 @@ extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
 extern void *xfs_buf_offset(struct xfs_buf *, size_t);
 
 /* 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 *);
index 532ab79d38fe376c14a5463a97195b59a61d8f84..572b64a135b351e344631552ba413d714b296ea1 100644 (file)
@@ -1355,12 +1355,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,