aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/linux-2.6/xfs_sync.c
diff options
context:
space:
mode:
authorDavid Chinner <david@fromorbit.com>2008-10-30 02:06:18 -0400
committerLachlan McIlroy <lachlan@sgi.com>2008-10-30 02:06:18 -0400
commita167b17e899a930758506bbc18748078d6fd8c89 (patch)
tree698f8efbe5085ae75e0b46e1b71c7bfc7186d3b2 /fs/xfs/linux-2.6/xfs_sync.c
parentfe4fa4b8e463fa5848ef9e86ed75d27501d0da1e (diff)
[XFS] move xfssyncd code to xfs_sync.c
Move all the xfssyncd code to the new xfs_sync.c file. This places it closer to the actual code that it interacts with, rather than just being associated with high level VFS code. SGI-PV: 988139 SGI-Modid: xfs-linux-melb:xfs-kern:32283a Signed-off-by: David Chinner <david@fromorbit.com> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org>
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_sync.c')
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index c765eb2a8dca..a51534c71b36 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -44,6 +44,9 @@
44#include "xfs_inode_item.h" 44#include "xfs_inode_item.h"
45#include "xfs_rw.h" 45#include "xfs_rw.h"
46 46
47#include <linux/kthread.h>
48#include <linux/freezer.h>
49
47/* 50/*
48 * xfs_sync flushes any pending I/O to file system vfsp. 51 * xfs_sync flushes any pending I/O to file system vfsp.
49 * 52 *
@@ -603,3 +606,163 @@ xfs_syncsub(
603 606
604 return XFS_ERROR(last_error); 607 return XFS_ERROR(last_error);
605} 608}
609
610/*
611 * Enqueue a work item to be picked up by the vfs xfssyncd thread.
612 * Doing this has two advantages:
613 * - It saves on stack space, which is tight in certain situations
614 * - It can be used (with care) as a mechanism to avoid deadlocks.
615 * Flushing while allocating in a full filesystem requires both.
616 */
617STATIC void
618xfs_syncd_queue_work(
619 struct xfs_mount *mp,
620 void *data,
621 void (*syncer)(struct xfs_mount *, void *))
622{
623 struct bhv_vfs_sync_work *work;
624
625 work = kmem_alloc(sizeof(struct bhv_vfs_sync_work), KM_SLEEP);
626 INIT_LIST_HEAD(&work->w_list);
627 work->w_syncer = syncer;
628 work->w_data = data;
629 work->w_mount = mp;
630 spin_lock(&mp->m_sync_lock);
631 list_add_tail(&work->w_list, &mp->m_sync_list);
632 spin_unlock(&mp->m_sync_lock);
633 wake_up_process(mp->m_sync_task);
634}
635
636/*
637 * Flush delayed allocate data, attempting to free up reserved space
638 * from existing allocations. At this point a new allocation attempt
639 * has failed with ENOSPC and we are in the process of scratching our
640 * heads, looking about for more room...
641 */
642STATIC void
643xfs_flush_inode_work(
644 struct xfs_mount *mp,
645 void *arg)
646{
647 struct inode *inode = arg;
648 filemap_flush(inode->i_mapping);
649 iput(inode);
650}
651
652void
653xfs_flush_inode(
654 xfs_inode_t *ip)
655{
656 struct inode *inode = VFS_I(ip);
657
658 igrab(inode);
659 xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inode_work);
660 delay(msecs_to_jiffies(500));
661}
662
663/*
664 * This is the "bigger hammer" version of xfs_flush_inode_work...
665 * (IOW, "If at first you don't succeed, use a Bigger Hammer").
666 */
667STATIC void
668xfs_flush_device_work(
669 struct xfs_mount *mp,
670 void *arg)
671{
672 struct inode *inode = arg;
673 sync_blockdev(mp->m_super->s_bdev);
674 iput(inode);
675}
676
677void
678xfs_flush_device(
679 xfs_inode_t *ip)
680{
681 struct inode *inode = VFS_I(ip);
682
683 igrab(inode);
684 xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_device_work);
685 delay(msecs_to_jiffies(500));
686 xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC);
687}
688
689STATIC void
690xfs_sync_worker(
691 struct xfs_mount *mp,
692 void *unused)
693{
694 int error;
695
696 if (!(mp->m_flags & XFS_MOUNT_RDONLY))
697 error = xfs_sync(mp, SYNC_FSDATA | SYNC_BDFLUSH | SYNC_ATTR);
698 mp->m_sync_seq++;
699 wake_up(&mp->m_wait_single_sync_task);
700}
701
702STATIC int
703xfssyncd(
704 void *arg)
705{
706 struct xfs_mount *mp = arg;
707 long timeleft;
708 bhv_vfs_sync_work_t *work, *n;
709 LIST_HEAD (tmp);
710
711 set_freezable();
712 timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10);
713 for (;;) {
714 timeleft = schedule_timeout_interruptible(timeleft);
715 /* swsusp */
716 try_to_freeze();
717 if (kthread_should_stop() && list_empty(&mp->m_sync_list))
718 break;
719
720 spin_lock(&mp->m_sync_lock);
721 /*
722 * We can get woken by laptop mode, to do a sync -
723 * that's the (only!) case where the list would be
724 * empty with time remaining.
725 */
726 if (!timeleft || list_empty(&mp->m_sync_list)) {
727 if (!timeleft)
728 timeleft = xfs_syncd_centisecs *
729 msecs_to_jiffies(10);
730 INIT_LIST_HEAD(&mp->m_sync_work.w_list);
731 list_add_tail(&mp->m_sync_work.w_list,
732 &mp->m_sync_list);
733 }
734 list_for_each_entry_safe(work, n, &mp->m_sync_list, w_list)
735 list_move(&work->w_list, &tmp);
736 spin_unlock(&mp->m_sync_lock);
737
738 list_for_each_entry_safe(work, n, &tmp, w_list) {
739 (*work->w_syncer)(mp, work->w_data);
740 list_del(&work->w_list);
741 if (work == &mp->m_sync_work)
742 continue;
743 kmem_free(work);
744 }
745 }
746
747 return 0;
748}
749
750int
751xfs_syncd_init(
752 struct xfs_mount *mp)
753{
754 mp->m_sync_work.w_syncer = xfs_sync_worker;
755 mp->m_sync_work.w_mount = mp;
756 mp->m_sync_task = kthread_run(xfssyncd, mp, "xfssyncd");
757 if (IS_ERR(mp->m_sync_task))
758 return -PTR_ERR(mp->m_sync_task);
759 return 0;
760}
761
762void
763xfs_syncd_stop(
764 struct xfs_mount *mp)
765{
766 kthread_stop(mp->m_sync_task);
767}
768