aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2011-10-18 10:23:19 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-10-25 01:10:16 -0400
commitc7eead1e118fb7e34ee8f5063c3c090c054c3820 (patch)
tree67ea83476070ca516321645cc1b775b5ddd91c14 /fs/xfs
parente7bde7c73957cfda82963127421069d13a44e921 (diff)
xfs: revert to using a kthread for AIL pushing
commit 0030807c66f058230bcb20d2573bcaf28852e804 upstream 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> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/linux-2.6/xfs_linux.h2
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c13
-rw-r--r--fs/xfs/xfs_trans_ail.c73
-rw-r--r--fs/xfs/xfs_trans_priv.h8
4 files changed, 45 insertions, 51 deletions
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index 8633521b3b2..87315168538 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -70,6 +70,8 @@
70#include <linux/ctype.h> 70#include <linux/ctype.h>
71#include <linux/writeback.h> 71#include <linux/writeback.h>
72#include <linux/capability.h> 72#include <linux/capability.h>
73#include <linux/kthread.h>
74#include <linux/freezer.h>
73#include <linux/list_sort.h> 75#include <linux/list_sort.h>
74 76
75#include <asm/page.h> 77#include <asm/page.h>
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 3ebb4588e1b..347cae965e8 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1660,24 +1660,13 @@ xfs_init_workqueues(void)
1660 */ 1660 */
1661 xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_CPU_INTENSIVE, 8); 1661 xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_CPU_INTENSIVE, 8);
1662 if (!xfs_syncd_wq) 1662 if (!xfs_syncd_wq)
1663 goto out; 1663 return -ENOMEM;
1664
1665 xfs_ail_wq = alloc_workqueue("xfsail", WQ_CPU_INTENSIVE, 8);
1666 if (!xfs_ail_wq)
1667 goto out_destroy_syncd;
1668
1669 return 0; 1664 return 0;
1670
1671out_destroy_syncd:
1672 destroy_workqueue(xfs_syncd_wq);
1673out:
1674 return -ENOMEM;
1675} 1665}
1676 1666
1677STATIC void 1667STATIC void
1678xfs_destroy_workqueues(void) 1668xfs_destroy_workqueues(void)
1679{ 1669{
1680 destroy_workqueue(xfs_ail_wq);
1681 destroy_workqueue(xfs_syncd_wq); 1670 destroy_workqueue(xfs_syncd_wq);
1682} 1671}
1683 1672
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index afc4aa0bc66..a4c281bf7a9 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.
@@ -406,16 +404,10 @@ xfs_ail_delete(
406 xfs_trans_ail_cursor_clear(ailp, lip); 404 xfs_trans_ail_cursor_clear(ailp, lip);
407} 405}
408 406
409/* 407static long
410 * xfs_ail_worker does the work of pushing on the AIL. It will requeue itself 408xfsaild_push(
411 * to run at a later time if there is more work to do to complete the push. 409 struct xfs_ail *ailp)
412 */
413STATIC void
414xfs_ail_worker(
415 struct work_struct *work)
416{ 410{
417 struct xfs_ail *ailp = container_of(to_delayed_work(work),
418 struct xfs_ail, xa_work);
419 xfs_mount_t *mp = ailp->xa_mount; 411 xfs_mount_t *mp = ailp->xa_mount;
420 struct xfs_ail_cursor *cur = &ailp->xa_cursors; 412 struct xfs_ail_cursor *cur = &ailp->xa_cursors;
421 xfs_log_item_t *lip; 413 xfs_log_item_t *lip;
@@ -556,20 +548,6 @@ out_done:
556 /* We're past our target or empty, so idle */ 548 /* We're past our target or empty, so idle */
557 ailp->xa_last_pushed_lsn = 0; 549 ailp->xa_last_pushed_lsn = 0;
558 550
559 /*
560 * We clear the XFS_AIL_PUSHING_BIT first before checking
561 * whether the target has changed. If the target has changed,
562 * this pushes the requeue race directly onto the result of the
563 * atomic test/set bit, so we are guaranteed that either the
564 * the pusher that changed the target or ourselves will requeue
565 * the work (but not both).
566 */
567 clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags);
568 smp_rmb();
569 if (XFS_LSN_CMP(ailp->xa_target, target) == 0 ||
570 test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
571 return;
572
573 tout = 50; 551 tout = 50;
574 } else if (XFS_LSN_CMP(lsn, target) >= 0) { 552 } else if (XFS_LSN_CMP(lsn, target) >= 0) {
575 /* 553 /*
@@ -592,9 +570,30 @@ out_done:
592 tout = 20; 570 tout = 20;
593 } 571 }
594 572
595 /* There is more to do, requeue us. */ 573 return tout;
596 queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 574}
597 msecs_to_jiffies(tout)); 575
576static int
577xfsaild(
578 void *data)
579{
580 struct xfs_ail *ailp = data;
581 long tout = 0; /* milliseconds */
582
583 while (!kthread_should_stop()) {
584 if (tout && tout <= 20)
585 __set_current_state(TASK_KILLABLE);
586 else
587 __set_current_state(TASK_INTERRUPTIBLE);
588 schedule_timeout(tout ?
589 msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT);
590
591 try_to_freeze();
592
593 tout = xfsaild_push(ailp);
594 }
595
596 return 0;
598} 597}
599 598
600/* 599/*
@@ -629,8 +628,9 @@ xfs_ail_push(
629 */ 628 */
630 smp_wmb(); 629 smp_wmb();
631 xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn); 630 xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn);
632 if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags)) 631 smp_wmb();
633 queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0); 632
633 wake_up_process(ailp->xa_task);
634} 634}
635 635
636/* 636/*
@@ -865,9 +865,18 @@ xfs_trans_ail_init(
865 ailp->xa_mount = mp; 865 ailp->xa_mount = mp;
866 INIT_LIST_HEAD(&ailp->xa_ail); 866 INIT_LIST_HEAD(&ailp->xa_ail);
867 spin_lock_init(&ailp->xa_lock); 867 spin_lock_init(&ailp->xa_lock);
868 INIT_DELAYED_WORK(&ailp->xa_work, xfs_ail_worker); 868
869 ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
870 ailp->xa_mount->m_fsname);
871 if (IS_ERR(ailp->xa_task))
872 goto out_free_ailp;
873
869 mp->m_ail = ailp; 874 mp->m_ail = ailp;
870 return 0; 875 return 0;
876
877out_free_ailp:
878 kmem_free(ailp);
879 return ENOMEM;
871} 880}
872 881
873void 882void
@@ -876,6 +885,6 @@ xfs_trans_ail_destroy(
876{ 885{
877 struct xfs_ail *ailp = mp->m_ail; 886 struct xfs_ail *ailp = mp->m_ail;
878 887
879 cancel_delayed_work_sync(&ailp->xa_work); 888 kthread_stop(ailp->xa_task);
880 kmem_free(ailp); 889 kmem_free(ailp);
881} 890}
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index c0cb4089032..fe2e3cbc2f9 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -64,23 +64,17 @@ struct xfs_ail_cursor {
64 */ 64 */
65struct xfs_ail { 65struct xfs_ail {
66 struct xfs_mount *xa_mount; 66 struct xfs_mount *xa_mount;
67 struct task_struct *xa_task;
67 struct list_head xa_ail; 68 struct list_head xa_ail;
68 xfs_lsn_t xa_target; 69 xfs_lsn_t xa_target;
69 struct xfs_ail_cursor xa_cursors; 70 struct xfs_ail_cursor xa_cursors;
70 spinlock_t xa_lock; 71 spinlock_t xa_lock;
71 struct delayed_work xa_work;
72 xfs_lsn_t xa_last_pushed_lsn; 72 xfs_lsn_t xa_last_pushed_lsn;
73 unsigned long xa_flags;
74}; 73};
75 74
76#define XFS_AIL_PUSHING_BIT 0
77
78/* 75/*
79 * From xfs_trans_ail.c 76 * From xfs_trans_ail.c
80 */ 77 */
81
82extern struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */
83
84void xfs_trans_ail_update_bulk(struct xfs_ail *ailp, 78void xfs_trans_ail_update_bulk(struct xfs_ail *ailp,
85 struct xfs_ail_cursor *cur, 79 struct xfs_ail_cursor *cur,
86 struct xfs_log_item **log_items, int nr_items, 80 struct xfs_log_item **log_items, int nr_items,