aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_trans_ail.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2011-10-11 11:14:10 -0400
committerAlex Elder <aelder@sgi.com>2011-10-11 12:02:49 -0400
commit0030807c66f058230bcb20d2573bcaf28852e804 (patch)
tree40c98d94085b6556cbbb33a7f5fca5a2cce153a2 /fs/xfs/xfs_trans_ail.c
parent17b38471c3c07a49f0bbc2ecc2e92050c164e226 (diff)
xfs: revert to using a kthread for AIL pushing
Currently we have a few issues with the way the workqueue code is used to implement AIL pushing: - it accidentally uses the same workqueue as the syncer action, and thus can be prevented from running if there are enough sync actions active in the system. - it doesn't use the HIGHPRI flag to queue at the head of the queue of work items At this point I'm not confident enough in getting all the workqueue flags and tweaks right to provide a perfectly reliable execution context for AIL pushing, which is the most important piece in XFS to make forward progress when the log fills. Revert back to use a kthread per filesystem which fixes all the above issues at the cost of having a task struct and stack around for each mounted filesystem. In addition this also gives us much better ways to diagnose any issues involving hung AIL pushing and removes a small amount of code. Signed-off-by: Christoph Hellwig <hch@lst.de> Reported-by: Stefan Priebe <s.priebe@profihost.ag> Tested-by: Stefan Priebe <s.priebe@profihost.ag> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_trans_ail.c')
-rw-r--r--fs/xfs/xfs_trans_ail.c73
1 files changed, 41 insertions, 32 deletions
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index e4cd9180d33a..3a1e7ca54c2d 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -28,8 +28,6 @@
28#include "xfs_trans_priv.h" 28#include "xfs_trans_priv.h"
29#include "xfs_error.h" 29#include "xfs_error.h"
30 30
31struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */
32
33#ifdef DEBUG 31#ifdef DEBUG
34/* 32/*
35 * Check that the list is sorted as it should be. 33 * Check that the list is sorted as it should be.
@@ -356,16 +354,10 @@ xfs_ail_delete(
356 xfs_trans_ail_cursor_clear(ailp, lip); 354 xfs_trans_ail_cursor_clear(ailp, lip);
357} 355}
358 356
359/* 357static long
360 * xfs_ail_worker does the work of pushing on the AIL. It will requeue itself 358xfsaild_push(
361 * to run at a later time if there is more work to do to complete the push. 359 struct xfs_ail *ailp)
362 */
363STATIC void
364xfs_ail_worker(
365 struct work_struct *work)
366{ 360{
367 struct xfs_ail *ailp = container_of(to_delayed_work(work),
368 struct xfs_ail, xa_work);
369 xfs_mount_t *mp = ailp->xa_mount; 361 xfs_mount_t *mp = ailp->xa_mount;
370 struct xfs_ail_cursor cur; 362 struct xfs_ail_cursor cur;
371 xfs_log_item_t *lip; 363 xfs_log_item_t *lip;
@@ -505,20 +497,6 @@ out_done:
505 /* We're past our target or empty, so idle */ 497 /* We're past our target or empty, so idle */
506 ailp->xa_last_pushed_lsn = 0; 498 ailp->xa_last_pushed_lsn = 0;
507 499
508 /*
509 * We clear the XFS_AIL_PUSHING_BIT first before checking
510 * whether the target has changed. If the target has changed,
511 * this pushes the requeue race directly onto the result of the
512 * atomic test/set bit, so we are guaranteed that either the
513 * the pusher that changed the target or ourselves will requeue
514 * the work (but not both).
515 */
516 clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags);
517 smp_rmb();
518 if (XFS_LSN_CMP(ailp->xa_target, target) == 0 ||
519 test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
520 return;
521
522 tout = 50; 500 tout = 50;
523 } else if (XFS_LSN_CMP(lsn, target) >= 0) { 501 } else if (XFS_LSN_CMP(lsn, target) >= 0) {
524 /* 502 /*
@@ -541,9 +519,30 @@ out_done:
541 tout = 20; 519 tout = 20;
542 } 520 }
543 521
544 /* There is more to do, requeue us. */ 522 return tout;
545 queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 523}
546 msecs_to_jiffies(tout)); 524
525static int
526xfsaild(
527 void *data)
528{
529 struct xfs_ail *ailp = data;
530 long tout = 0; /* milliseconds */
531
532 while (!kthread_should_stop()) {
533 if (tout && tout <= 20)
534 __set_current_state(TASK_KILLABLE);
535 else
536 __set_current_state(TASK_INTERRUPTIBLE);
537 schedule_timeout(tout ?
538 msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT);
539
540 try_to_freeze();
541
542 tout = xfsaild_push(ailp);
543 }
544
545 return 0;
547} 546}
548 547
549/* 548/*
@@ -578,8 +577,9 @@ xfs_ail_push(
578 */ 577 */
579 smp_wmb(); 578 smp_wmb();
580 xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn); 579 xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn);
581 if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags)) 580 smp_wmb();
582 queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0); 581
582 wake_up_process(ailp->xa_task);
583} 583}
584 584
585/* 585/*
@@ -817,9 +817,18 @@ xfs_trans_ail_init(
817 INIT_LIST_HEAD(&ailp->xa_ail); 817 INIT_LIST_HEAD(&ailp->xa_ail);
818 INIT_LIST_HEAD(&ailp->xa_cursors); 818 INIT_LIST_HEAD(&ailp->xa_cursors);
819 spin_lock_init(&ailp->xa_lock); 819 spin_lock_init(&ailp->xa_lock);
820 INIT_DELAYED_WORK(&ailp->xa_work, xfs_ail_worker); 820
821 ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
822 ailp->xa_mount->m_fsname);
823 if (IS_ERR(ailp->xa_task))
824 goto out_free_ailp;
825
821 mp->m_ail = ailp; 826 mp->m_ail = ailp;
822 return 0; 827 return 0;
828
829out_free_ailp:
830 kmem_free(ailp);
831 return ENOMEM;
823} 832}
824 833
825void 834void
@@ -828,6 +837,6 @@ xfs_trans_ail_destroy(
828{ 837{
829 struct xfs_ail *ailp = mp->m_ail; 838 struct xfs_ail *ailp = mp->m_ail;
830 839
831 cancel_delayed_work_sync(&ailp->xa_work); 840 kthread_stop(ailp->xa_task);
832 kmem_free(ailp); 841 kmem_free(ailp);
833} 842}