xfs: convert flex-array declarations in struct xfs_attrlist*
[platform/kernel/linux-starfive.git] / fs / xfs / xfs_extent_busy.c
index f3d328e..7c2fdc7 100644 (file)
@@ -566,20 +566,45 @@ xfs_extent_busy_clear(
 
 /*
  * Flush out all busy extents for this AG.
+ *
+ * If the current transaction is holding busy extents, the caller may not want
+ * to wait for committed busy extents to resolve. If we are being told just to
+ * try a flush or progress has been made since we last skipped a busy extent,
+ * return immediately to allow the caller to try again.
+ *
+ * If we are freeing extents, we might actually be holding the only free extents
+ * in the transaction busy list and the log force won't resolve that situation.
+ * In this case, we must return -EAGAIN to avoid a deadlock by informing the
+ * caller it needs to commit the busy extents it holds before retrying the
+ * extent free operation.
  */
-void
+int
 xfs_extent_busy_flush(
-       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
        struct xfs_perag        *pag,
-       unsigned                busy_gen)
+       unsigned                busy_gen,
+       uint32_t                alloc_flags)
 {
        DEFINE_WAIT             (wait);
        int                     error;
 
-       error = xfs_log_force(mp, XFS_LOG_SYNC);
+       error = xfs_log_force(tp->t_mountp, XFS_LOG_SYNC);
        if (error)
-               return;
+               return error;
+
+       /* Avoid deadlocks on uncommitted busy extents. */
+       if (!list_empty(&tp->t_busy)) {
+               if (alloc_flags & XFS_ALLOC_FLAG_TRYFLUSH)
+                       return 0;
+
+               if (busy_gen != READ_ONCE(pag->pagb_gen))
+                       return 0;
+
+               if (alloc_flags & XFS_ALLOC_FLAG_FREEING)
+                       return -EAGAIN;
+       }
 
+       /* Wait for committed busy extents to resolve. */
        do {
                prepare_to_wait(&pag->pagb_wait, &wait, TASK_KILLABLE);
                if  (busy_gen != READ_ONCE(pag->pagb_gen))
@@ -588,6 +613,7 @@ xfs_extent_busy_flush(
        } while (1);
 
        finish_wait(&pag->pagb_wait, &wait);
+       return 0;
 }
 
 void