diff options
-rw-r--r-- | fs/xfs/linux-2.6/xfs_super.c | 30 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 88 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 4 |
4 files changed, 63 insertions, 61 deletions
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 1ba5c451da36..c71b6ed45e41 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
@@ -1191,22 +1191,12 @@ xfs_fs_sync_fs( | |||
1191 | return -error; | 1191 | return -error; |
1192 | 1192 | ||
1193 | if (laptop_mode) { | 1193 | if (laptop_mode) { |
1194 | int prev_sync_seq = mp->m_sync_seq; | ||
1195 | |||
1196 | /* | 1194 | /* |
1197 | * The disk must be active because we're syncing. | 1195 | * The disk must be active because we're syncing. |
1198 | * We schedule xfssyncd now (now that the disk is | 1196 | * We schedule xfssyncd now (now that the disk is |
1199 | * active) instead of later (when it might not be). | 1197 | * active) instead of later (when it might not be). |
1200 | */ | 1198 | */ |
1201 | wake_up_process(mp->m_sync_task); | 1199 | flush_delayed_work_sync(&mp->m_sync_work); |
1202 | /* | ||
1203 | * We have to wait for the sync iteration to complete. | ||
1204 | * If we don't, the disk activity caused by the sync | ||
1205 | * will come after the sync is completed, and that | ||
1206 | * triggers another sync from laptop mode. | ||
1207 | */ | ||
1208 | wait_event(mp->m_wait_single_sync_task, | ||
1209 | mp->m_sync_seq != prev_sync_seq); | ||
1210 | } | 1200 | } |
1211 | 1201 | ||
1212 | return 0; | 1202 | return 0; |
@@ -1492,7 +1482,6 @@ xfs_fs_fill_super( | |||
1492 | atomic_set(&mp->m_active_trans, 0); | 1482 | atomic_set(&mp->m_active_trans, 0); |
1493 | INIT_LIST_HEAD(&mp->m_sync_list); | 1483 | INIT_LIST_HEAD(&mp->m_sync_list); |
1494 | spin_lock_init(&mp->m_sync_lock); | 1484 | spin_lock_init(&mp->m_sync_lock); |
1495 | init_waitqueue_head(&mp->m_wait_single_sync_task); | ||
1496 | 1485 | ||
1497 | mp->m_super = sb; | 1486 | mp->m_super = sb; |
1498 | sb->s_fs_info = mp; | 1487 | sb->s_fs_info = mp; |
@@ -1833,13 +1822,27 @@ init_xfs_fs(void) | |||
1833 | if (error) | 1822 | if (error) |
1834 | goto out_cleanup_procfs; | 1823 | goto out_cleanup_procfs; |
1835 | 1824 | ||
1825 | /* | ||
1826 | * max_active is set to 8 to give enough concurency to allow | ||
1827 | * multiple work operations on each CPU to run. This allows multiple | ||
1828 | * filesystems to be running sync work concurrently, and scales with | ||
1829 | * the number of CPUs in the system. | ||
1830 | */ | ||
1831 | xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_CPU_INTENSIVE, 8); | ||
1832 | if (!xfs_syncd_wq) { | ||
1833 | error = -ENOMEM; | ||
1834 | goto out_sysctl_unregister; | ||
1835 | } | ||
1836 | |||
1836 | vfs_initquota(); | 1837 | vfs_initquota(); |
1837 | 1838 | ||
1838 | error = register_filesystem(&xfs_fs_type); | 1839 | error = register_filesystem(&xfs_fs_type); |
1839 | if (error) | 1840 | if (error) |
1840 | goto out_sysctl_unregister; | 1841 | goto out_destroy_xfs_syncd; |
1841 | return 0; | 1842 | return 0; |
1842 | 1843 | ||
1844 | out_destroy_xfs_syncd: | ||
1845 | destroy_workqueue(xfs_syncd_wq); | ||
1843 | out_sysctl_unregister: | 1846 | out_sysctl_unregister: |
1844 | xfs_sysctl_unregister(); | 1847 | xfs_sysctl_unregister(); |
1845 | out_cleanup_procfs: | 1848 | out_cleanup_procfs: |
@@ -1861,6 +1864,7 @@ exit_xfs_fs(void) | |||
1861 | { | 1864 | { |
1862 | vfs_exitquota(); | 1865 | vfs_exitquota(); |
1863 | unregister_filesystem(&xfs_fs_type); | 1866 | unregister_filesystem(&xfs_fs_type); |
1867 | destroy_workqueue(xfs_syncd_wq); | ||
1864 | xfs_sysctl_unregister(); | 1868 | xfs_sysctl_unregister(); |
1865 | xfs_cleanup_procfs(); | 1869 | xfs_cleanup_procfs(); |
1866 | xfs_buf_terminate(); | 1870 | xfs_buf_terminate(); |
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 594cd822d84d..4a582d8100e4 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <linux/kthread.h> | 39 | #include <linux/kthread.h> |
40 | #include <linux/freezer.h> | 40 | #include <linux/freezer.h> |
41 | 41 | ||
42 | struct workqueue_struct *xfs_syncd_wq; /* sync workqueue */ | ||
43 | |||
42 | /* | 44 | /* |
43 | * The inode lookup is done in batches to keep the amount of lock traffic and | 45 | * The inode lookup is done in batches to keep the amount of lock traffic and |
44 | * radix tree lookups to a minimum. The batch size is a trade off between | 46 | * radix tree lookups to a minimum. The batch size is a trade off between |
@@ -489,32 +491,6 @@ xfs_flush_inodes( | |||
489 | xfs_log_force(ip->i_mount, XFS_LOG_SYNC); | 491 | xfs_log_force(ip->i_mount, XFS_LOG_SYNC); |
490 | } | 492 | } |
491 | 493 | ||
492 | /* | ||
493 | * Every sync period we need to unpin all items, reclaim inodes and sync | ||
494 | * disk quotas. We might need to cover the log to indicate that the | ||
495 | * filesystem is idle and not frozen. | ||
496 | */ | ||
497 | STATIC void | ||
498 | xfs_sync_worker( | ||
499 | struct xfs_mount *mp, | ||
500 | void *unused) | ||
501 | { | ||
502 | int error; | ||
503 | |||
504 | if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { | ||
505 | /* dgc: errors ignored here */ | ||
506 | if (mp->m_super->s_frozen == SB_UNFROZEN && | ||
507 | xfs_log_need_covered(mp)) | ||
508 | error = xfs_fs_log_dummy(mp); | ||
509 | else | ||
510 | xfs_log_force(mp, 0); | ||
511 | xfs_reclaim_inodes(mp, 0); | ||
512 | error = xfs_qm_sync(mp, SYNC_TRYLOCK); | ||
513 | } | ||
514 | mp->m_sync_seq++; | ||
515 | wake_up(&mp->m_wait_single_sync_task); | ||
516 | } | ||
517 | |||
518 | STATIC int | 494 | STATIC int |
519 | xfssyncd( | 495 | xfssyncd( |
520 | void *arg) | 496 | void *arg) |
@@ -528,34 +504,19 @@ xfssyncd( | |||
528 | timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); | 504 | timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); |
529 | for (;;) { | 505 | for (;;) { |
530 | if (list_empty(&mp->m_sync_list)) | 506 | if (list_empty(&mp->m_sync_list)) |
531 | timeleft = schedule_timeout_interruptible(timeleft); | 507 | schedule_timeout_interruptible(timeleft); |
532 | /* swsusp */ | 508 | /* swsusp */ |
533 | try_to_freeze(); | 509 | try_to_freeze(); |
534 | if (kthread_should_stop() && list_empty(&mp->m_sync_list)) | 510 | if (kthread_should_stop() && list_empty(&mp->m_sync_list)) |
535 | break; | 511 | break; |
536 | 512 | ||
537 | spin_lock(&mp->m_sync_lock); | 513 | spin_lock(&mp->m_sync_lock); |
538 | /* | ||
539 | * We can get woken by laptop mode, to do a sync - | ||
540 | * that's the (only!) case where the list would be | ||
541 | * empty with time remaining. | ||
542 | */ | ||
543 | if (!timeleft || list_empty(&mp->m_sync_list)) { | ||
544 | if (!timeleft) | ||
545 | timeleft = xfs_syncd_centisecs * | ||
546 | msecs_to_jiffies(10); | ||
547 | INIT_LIST_HEAD(&mp->m_sync_work.w_list); | ||
548 | list_add_tail(&mp->m_sync_work.w_list, | ||
549 | &mp->m_sync_list); | ||
550 | } | ||
551 | list_splice_init(&mp->m_sync_list, &tmp); | 514 | list_splice_init(&mp->m_sync_list, &tmp); |
552 | spin_unlock(&mp->m_sync_lock); | 515 | spin_unlock(&mp->m_sync_lock); |
553 | 516 | ||
554 | list_for_each_entry_safe(work, n, &tmp, w_list) { | 517 | list_for_each_entry_safe(work, n, &tmp, w_list) { |
555 | (*work->w_syncer)(mp, work->w_data); | 518 | (*work->w_syncer)(mp, work->w_data); |
556 | list_del(&work->w_list); | 519 | list_del(&work->w_list); |
557 | if (work == &mp->m_sync_work) | ||
558 | continue; | ||
559 | if (work->w_completion) | 520 | if (work->w_completion) |
560 | complete(work->w_completion); | 521 | complete(work->w_completion); |
561 | kmem_free(work); | 522 | kmem_free(work); |
@@ -565,13 +526,49 @@ xfssyncd( | |||
565 | return 0; | 526 | return 0; |
566 | } | 527 | } |
567 | 528 | ||
529 | static void | ||
530 | xfs_syncd_queue_sync( | ||
531 | struct xfs_mount *mp) | ||
532 | { | ||
533 | queue_delayed_work(xfs_syncd_wq, &mp->m_sync_work, | ||
534 | msecs_to_jiffies(xfs_syncd_centisecs * 10)); | ||
535 | } | ||
536 | |||
537 | /* | ||
538 | * Every sync period we need to unpin all items, reclaim inodes and sync | ||
539 | * disk quotas. We might need to cover the log to indicate that the | ||
540 | * filesystem is idle and not frozen. | ||
541 | */ | ||
542 | STATIC void | ||
543 | xfs_sync_worker( | ||
544 | struct work_struct *work) | ||
545 | { | ||
546 | struct xfs_mount *mp = container_of(to_delayed_work(work), | ||
547 | struct xfs_mount, m_sync_work); | ||
548 | int error; | ||
549 | |||
550 | if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { | ||
551 | /* dgc: errors ignored here */ | ||
552 | if (mp->m_super->s_frozen == SB_UNFROZEN && | ||
553 | xfs_log_need_covered(mp)) | ||
554 | error = xfs_fs_log_dummy(mp); | ||
555 | else | ||
556 | xfs_log_force(mp, 0); | ||
557 | xfs_reclaim_inodes(mp, 0); | ||
558 | error = xfs_qm_sync(mp, SYNC_TRYLOCK); | ||
559 | } | ||
560 | |||
561 | /* queue us up again */ | ||
562 | xfs_syncd_queue_sync(mp); | ||
563 | } | ||
564 | |||
568 | int | 565 | int |
569 | xfs_syncd_init( | 566 | xfs_syncd_init( |
570 | struct xfs_mount *mp) | 567 | struct xfs_mount *mp) |
571 | { | 568 | { |
572 | mp->m_sync_work.w_syncer = xfs_sync_worker; | 569 | INIT_DELAYED_WORK(&mp->m_sync_work, xfs_sync_worker); |
573 | mp->m_sync_work.w_mount = mp; | 570 | xfs_syncd_queue_sync(mp); |
574 | mp->m_sync_work.w_completion = NULL; | 571 | |
575 | mp->m_sync_task = kthread_run(xfssyncd, mp, "xfssyncd/%s", mp->m_fsname); | 572 | mp->m_sync_task = kthread_run(xfssyncd, mp, "xfssyncd/%s", mp->m_fsname); |
576 | if (IS_ERR(mp->m_sync_task)) | 573 | if (IS_ERR(mp->m_sync_task)) |
577 | return -PTR_ERR(mp->m_sync_task); | 574 | return -PTR_ERR(mp->m_sync_task); |
@@ -582,6 +579,7 @@ void | |||
582 | xfs_syncd_stop( | 579 | xfs_syncd_stop( |
583 | struct xfs_mount *mp) | 580 | struct xfs_mount *mp) |
584 | { | 581 | { |
582 | cancel_delayed_work_sync(&mp->m_sync_work); | ||
585 | kthread_stop(mp->m_sync_task); | 583 | kthread_stop(mp->m_sync_task); |
586 | } | 584 | } |
587 | 585 | ||
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index 32ba6628290c..e3a6ad27415f 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h | |||
@@ -32,6 +32,8 @@ typedef struct xfs_sync_work { | |||
32 | #define SYNC_WAIT 0x0001 /* wait for i/o to complete */ | 32 | #define SYNC_WAIT 0x0001 /* wait for i/o to complete */ |
33 | #define SYNC_TRYLOCK 0x0002 /* only try to lock inodes */ | 33 | #define SYNC_TRYLOCK 0x0002 /* only try to lock inodes */ |
34 | 34 | ||
35 | extern struct workqueue_struct *xfs_syncd_wq; /* sync workqueue */ | ||
36 | |||
35 | int xfs_syncd_init(struct xfs_mount *mp); | 37 | int xfs_syncd_init(struct xfs_mount *mp); |
36 | void xfs_syncd_stop(struct xfs_mount *mp); | 38 | void xfs_syncd_stop(struct xfs_mount *mp); |
37 | 39 | ||
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index a62e8971539d..2c11e62be888 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -203,12 +203,10 @@ typedef struct xfs_mount { | |||
203 | struct mutex m_icsb_mutex; /* balancer sync lock */ | 203 | struct mutex m_icsb_mutex; /* balancer sync lock */ |
204 | #endif | 204 | #endif |
205 | struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ | 205 | struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ |
206 | struct delayed_work m_sync_work; /* background sync work */ | ||
206 | struct task_struct *m_sync_task; /* generalised sync thread */ | 207 | struct task_struct *m_sync_task; /* generalised sync thread */ |
207 | xfs_sync_work_t m_sync_work; /* work item for VFS_SYNC */ | ||
208 | struct list_head m_sync_list; /* sync thread work item list */ | 208 | struct list_head m_sync_list; /* sync thread work item list */ |
209 | spinlock_t m_sync_lock; /* work item list lock */ | 209 | spinlock_t m_sync_lock; /* work item list lock */ |
210 | int m_sync_seq; /* sync thread generation no. */ | ||
211 | wait_queue_head_t m_wait_single_sync_task; | ||
212 | __int64_t m_update_flags; /* sb flags we need to update | 210 | __int64_t m_update_flags; /* sb flags we need to update |
213 | on the next remount,rw */ | 211 | on the next remount,rw */ |
214 | struct shrinker m_inode_shrink; /* inode reclaim shrinker */ | 212 | struct shrinker m_inode_shrink; /* inode reclaim shrinker */ |