|
@@ -28,8 +28,6 @@
|
|
|
#include "xfs_trans_priv.h"
|
|
|
#include "xfs_error.h"
|
|
|
|
|
|
-struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */
|
|
|
-
|
|
|
#ifdef DEBUG
|
|
|
/*
|
|
|
* Check that the list is sorted as it should be.
|
|
@@ -356,16 +354,10 @@ xfs_ail_delete(
|
|
|
xfs_trans_ail_cursor_clear(ailp, lip);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * xfs_ail_worker does the work of pushing on the AIL. It will requeue itself
|
|
|
- * to run at a later time if there is more work to do to complete the push.
|
|
|
- */
|
|
|
-STATIC void
|
|
|
-xfs_ail_worker(
|
|
|
- struct work_struct *work)
|
|
|
+static long
|
|
|
+xfsaild_push(
|
|
|
+ struct xfs_ail *ailp)
|
|
|
{
|
|
|
- struct xfs_ail *ailp = container_of(to_delayed_work(work),
|
|
|
- struct xfs_ail, xa_work);
|
|
|
xfs_mount_t *mp = ailp->xa_mount;
|
|
|
struct xfs_ail_cursor cur;
|
|
|
xfs_log_item_t *lip;
|
|
@@ -505,20 +497,6 @@ out_done:
|
|
|
/* We're past our target or empty, so idle */
|
|
|
ailp->xa_last_pushed_lsn = 0;
|
|
|
|
|
|
- /*
|
|
|
- * We clear the XFS_AIL_PUSHING_BIT first before checking
|
|
|
- * whether the target has changed. If the target has changed,
|
|
|
- * this pushes the requeue race directly onto the result of the
|
|
|
- * atomic test/set bit, so we are guaranteed that either the
|
|
|
- * the pusher that changed the target or ourselves will requeue
|
|
|
- * the work (but not both).
|
|
|
- */
|
|
|
- clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags);
|
|
|
- smp_rmb();
|
|
|
- if (XFS_LSN_CMP(ailp->xa_target, target) == 0 ||
|
|
|
- test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
|
|
|
- return;
|
|
|
-
|
|
|
tout = 50;
|
|
|
} else if (XFS_LSN_CMP(lsn, target) >= 0) {
|
|
|
/*
|
|
@@ -541,9 +519,30 @@ out_done:
|
|
|
tout = 20;
|
|
|
}
|
|
|
|
|
|
- /* There is more to do, requeue us. */
|
|
|
- queue_delayed_work(xfs_syncd_wq, &ailp->xa_work,
|
|
|
- msecs_to_jiffies(tout));
|
|
|
+ return tout;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+xfsaild(
|
|
|
+ void *data)
|
|
|
+{
|
|
|
+ struct xfs_ail *ailp = data;
|
|
|
+ long tout = 0; /* milliseconds */
|
|
|
+
|
|
|
+ while (!kthread_should_stop()) {
|
|
|
+ if (tout && tout <= 20)
|
|
|
+ __set_current_state(TASK_KILLABLE);
|
|
|
+ else
|
|
|
+ __set_current_state(TASK_INTERRUPTIBLE);
|
|
|
+ schedule_timeout(tout ?
|
|
|
+ msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT);
|
|
|
+
|
|
|
+ try_to_freeze();
|
|
|
+
|
|
|
+ tout = xfsaild_push(ailp);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -578,8 +577,9 @@ xfs_ail_push(
|
|
|
*/
|
|
|
smp_wmb();
|
|
|
xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn);
|
|
|
- if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
|
|
|
- queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0);
|
|
|
+ smp_wmb();
|
|
|
+
|
|
|
+ wake_up_process(ailp->xa_task);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -817,9 +817,18 @@ xfs_trans_ail_init(
|
|
|
INIT_LIST_HEAD(&ailp->xa_ail);
|
|
|
INIT_LIST_HEAD(&ailp->xa_cursors);
|
|
|
spin_lock_init(&ailp->xa_lock);
|
|
|
- INIT_DELAYED_WORK(&ailp->xa_work, xfs_ail_worker);
|
|
|
+
|
|
|
+ ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
|
|
|
+ ailp->xa_mount->m_fsname);
|
|
|
+ if (IS_ERR(ailp->xa_task))
|
|
|
+ goto out_free_ailp;
|
|
|
+
|
|
|
mp->m_ail = ailp;
|
|
|
return 0;
|
|
|
+
|
|
|
+out_free_ailp:
|
|
|
+ kmem_free(ailp);
|
|
|
+ return ENOMEM;
|
|
|
}
|
|
|
|
|
|
void
|
|
@@ -828,6 +837,6 @@ xfs_trans_ail_destroy(
|
|
|
{
|
|
|
struct xfs_ail *ailp = mp->m_ail;
|
|
|
|
|
|
- cancel_delayed_work_sync(&ailp->xa_work);
|
|
|
+ kthread_stop(ailp->xa_task);
|
|
|
kmem_free(ailp);
|
|
|
}
|