xfs: don't use BMBT btree split workers for IO completion
[platform/kernel/linux-starfive.git] / fs / xfs / libxfs / xfs_btree.c
index 35f5744..da8c769 100644 (file)
@@ -2913,9 +2913,22 @@ xfs_btree_split_worker(
 }
 
 /*
- * BMBT split requests often come in with little stack to work on. Push
+ * BMBT split requests often come in with little stack to work on so we push
  * them off to a worker thread so there is lots of stack to use. For the other
  * btree types, just call directly to avoid the context switch overhead here.
+ *
+ * Care must be taken here - the work queue rescuer thread introduces potential
+ * AGF <> worker queue deadlocks if the BMBT block allocation has to lock new
+ * AGFs to allocate blocks. A task being run by the rescuer could attempt to
+ * lock an AGF that is already locked by a task queued to run by the rescuer,
+ * resulting in an ABBA deadlock as the rescuer cannot run the lock holder to
+ * release it until the current thread it is running gains the lock.
+ *
+ * To avoid this issue, we only ever queue BMBT splits that don't have an AGF
+ * already locked to allocate from. The only place that doesn't hold an AGF
+ * locked is unwritten extent conversion at IO completion, but that has already
+ * been offloaded to a worker thread and hence has no stack consumption issues
+ * we have to worry about.
  */
 STATIC int                                     /* error */
 xfs_btree_split(
@@ -2929,7 +2942,8 @@ xfs_btree_split(
        struct xfs_btree_split_args     args;
        DECLARE_COMPLETION_ONSTACK(done);
 
-       if (cur->bc_btnum != XFS_BTNUM_BMAP)
+       if (cur->bc_btnum != XFS_BTNUM_BMAP ||
+           cur->bc_tp->t_firstblock == NULLFSBLOCK)
                return __xfs_btree_split(cur, level, ptrp, key, curp, stat);
 
        args.cur = cur;