diff options
author | Artem Bityutskiy <artem.bityutskiy@linux.intel.com> | 2012-07-12 09:28:08 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-22 15:58:16 -0400 |
commit | 9e9ad5f408889db6038a59b38ede29ff1ba9ef2f (patch) | |
tree | 1ceddb870378c5cd272959a54c18ed5909291d44 /fs/ufs | |
parent | 7bd54ef722e9938768f524677be0ac4985d8473a (diff) |
fs/ufs: get rid of write_super
This patch makes UFS stop using the VFS '->write_super()' method along with
the 's_dirt' superblock flag, because they are on their way out.
The way we implement this is that we schedule a delay job instead relying on
's_dirt' and '->write_super()'.
The whole "superblock write-out" VFS infrastructure is served by the
'sync_supers()' kernel thread, which wakes up every 5 (by default) seconds and
writes out all dirty superblocks using the '->write_super()' call-back. But the
problem with this thread is that it wastes power by waking up the system every
5 seconds, even if there are no diry superblocks, or there are no client
file-systems which would need this (e.g., btrfs does not use
'->write_super()'). So we want to kill it completely and thus, we need to make
file-systems to stop using the '->write_super()' VFS service, and then remove
it together with the kernel thread.
Tested using fsstress from the LTP project.
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ufs')
-rw-r--r-- | fs/ufs/balloc.c | 8 | ||||
-rw-r--r-- | fs/ufs/ialloc.c | 4 | ||||
-rw-r--r-- | fs/ufs/super.c | 40 | ||||
-rw-r--r-- | fs/ufs/ufs.h | 5 | ||||
-rw-r--r-- | fs/ufs/ufs_fs.h | 1 |
5 files changed, 42 insertions, 16 deletions
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 42694e11c23d..1b3e410bf334 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c | |||
@@ -116,7 +116,7 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) | |||
116 | ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); | 116 | ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); |
117 | if (sb->s_flags & MS_SYNCHRONOUS) | 117 | if (sb->s_flags & MS_SYNCHRONOUS) |
118 | ubh_sync_block(UCPI_UBH(ucpi)); | 118 | ubh_sync_block(UCPI_UBH(ucpi)); |
119 | sb->s_dirt = 1; | 119 | ufs_mark_sb_dirty(sb); |
120 | 120 | ||
121 | unlock_super (sb); | 121 | unlock_super (sb); |
122 | UFSD("EXIT\n"); | 122 | UFSD("EXIT\n"); |
@@ -214,7 +214,7 @@ do_more: | |||
214 | goto do_more; | 214 | goto do_more; |
215 | } | 215 | } |
216 | 216 | ||
217 | sb->s_dirt = 1; | 217 | ufs_mark_sb_dirty(sb); |
218 | unlock_super (sb); | 218 | unlock_super (sb); |
219 | UFSD("EXIT\n"); | 219 | UFSD("EXIT\n"); |
220 | return; | 220 | return; |
@@ -557,7 +557,7 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment, | |||
557 | ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); | 557 | ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); |
558 | if (sb->s_flags & MS_SYNCHRONOUS) | 558 | if (sb->s_flags & MS_SYNCHRONOUS) |
559 | ubh_sync_block(UCPI_UBH(ucpi)); | 559 | ubh_sync_block(UCPI_UBH(ucpi)); |
560 | sb->s_dirt = 1; | 560 | ufs_mark_sb_dirty(sb); |
561 | 561 | ||
562 | UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment); | 562 | UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment); |
563 | 563 | ||
@@ -677,7 +677,7 @@ succed: | |||
677 | ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); | 677 | ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); |
678 | if (sb->s_flags & MS_SYNCHRONOUS) | 678 | if (sb->s_flags & MS_SYNCHRONOUS) |
679 | ubh_sync_block(UCPI_UBH(ucpi)); | 679 | ubh_sync_block(UCPI_UBH(ucpi)); |
680 | sb->s_dirt = 1; | 680 | ufs_mark_sb_dirty(sb); |
681 | 681 | ||
682 | result += cgno * uspi->s_fpg; | 682 | result += cgno * uspi->s_fpg; |
683 | UFSD("EXIT3, result %llu\n", (unsigned long long)result); | 683 | UFSD("EXIT3, result %llu\n", (unsigned long long)result); |
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index 4ec5c1085a87..e84cbe21b986 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c | |||
@@ -116,7 +116,7 @@ void ufs_free_inode (struct inode * inode) | |||
116 | if (sb->s_flags & MS_SYNCHRONOUS) | 116 | if (sb->s_flags & MS_SYNCHRONOUS) |
117 | ubh_sync_block(UCPI_UBH(ucpi)); | 117 | ubh_sync_block(UCPI_UBH(ucpi)); |
118 | 118 | ||
119 | sb->s_dirt = 1; | 119 | ufs_mark_sb_dirty(sb); |
120 | unlock_super (sb); | 120 | unlock_super (sb); |
121 | UFSD("EXIT\n"); | 121 | UFSD("EXIT\n"); |
122 | } | 122 | } |
@@ -288,7 +288,7 @@ cg_found: | |||
288 | ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); | 288 | ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); |
289 | if (sb->s_flags & MS_SYNCHRONOUS) | 289 | if (sb->s_flags & MS_SYNCHRONOUS) |
290 | ubh_sync_block(UCPI_UBH(ucpi)); | 290 | ubh_sync_block(UCPI_UBH(ucpi)); |
291 | sb->s_dirt = 1; | 291 | ufs_mark_sb_dirty(sb); |
292 | 292 | ||
293 | inode->i_ino = cg * uspi->s_ipg + bit; | 293 | inode->i_ino = cg * uspi->s_ipg + bit; |
294 | inode_init_owner(inode, dir, mode); | 294 | inode_init_owner(inode, dir, mode); |
diff --git a/fs/ufs/super.c b/fs/ufs/super.c index ad56c6dffc64..444927e5706b 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c | |||
@@ -302,7 +302,7 @@ void ufs_error (struct super_block * sb, const char * function, | |||
302 | if (!(sb->s_flags & MS_RDONLY)) { | 302 | if (!(sb->s_flags & MS_RDONLY)) { |
303 | usb1->fs_clean = UFS_FSBAD; | 303 | usb1->fs_clean = UFS_FSBAD; |
304 | ubh_mark_buffer_dirty(USPI_UBH(uspi)); | 304 | ubh_mark_buffer_dirty(USPI_UBH(uspi)); |
305 | sb->s_dirt = 1; | 305 | ufs_mark_sb_dirty(sb); |
306 | sb->s_flags |= MS_RDONLY; | 306 | sb->s_flags |= MS_RDONLY; |
307 | } | 307 | } |
308 | va_start (args, fmt); | 308 | va_start (args, fmt); |
@@ -334,7 +334,7 @@ void ufs_panic (struct super_block * sb, const char * function, | |||
334 | if (!(sb->s_flags & MS_RDONLY)) { | 334 | if (!(sb->s_flags & MS_RDONLY)) { |
335 | usb1->fs_clean = UFS_FSBAD; | 335 | usb1->fs_clean = UFS_FSBAD; |
336 | ubh_mark_buffer_dirty(USPI_UBH(uspi)); | 336 | ubh_mark_buffer_dirty(USPI_UBH(uspi)); |
337 | sb->s_dirt = 1; | 337 | ufs_mark_sb_dirty(sb); |
338 | } | 338 | } |
339 | va_start (args, fmt); | 339 | va_start (args, fmt); |
340 | vsnprintf (error_buf, sizeof(error_buf), fmt, args); | 340 | vsnprintf (error_buf, sizeof(error_buf), fmt, args); |
@@ -715,7 +715,6 @@ static int ufs_sync_fs(struct super_block *sb, int wait) | |||
715 | ufs_set_fs_state(sb, usb1, usb3, | 715 | ufs_set_fs_state(sb, usb1, usb3, |
716 | UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); | 716 | UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); |
717 | ufs_put_cstotal(sb); | 717 | ufs_put_cstotal(sb); |
718 | sb->s_dirt = 0; | ||
719 | 718 | ||
720 | UFSD("EXIT\n"); | 719 | UFSD("EXIT\n"); |
721 | unlock_super(sb); | 720 | unlock_super(sb); |
@@ -724,12 +723,31 @@ static int ufs_sync_fs(struct super_block *sb, int wait) | |||
724 | return 0; | 723 | return 0; |
725 | } | 724 | } |
726 | 725 | ||
727 | static void ufs_write_super(struct super_block *sb) | 726 | static void delayed_sync_fs(struct work_struct *work) |
728 | { | 727 | { |
729 | if (!(sb->s_flags & MS_RDONLY)) | 728 | struct ufs_sb_info *sbi; |
730 | ufs_sync_fs(sb, 1); | 729 | |
731 | else | 730 | sbi = container_of(work, struct ufs_sb_info, sync_work.work); |
732 | sb->s_dirt = 0; | 731 | |
732 | spin_lock(&sbi->work_lock); | ||
733 | sbi->work_queued = 0; | ||
734 | spin_unlock(&sbi->work_lock); | ||
735 | |||
736 | ufs_sync_fs(sbi->sb, 1); | ||
737 | } | ||
738 | |||
739 | void ufs_mark_sb_dirty(struct super_block *sb) | ||
740 | { | ||
741 | struct ufs_sb_info *sbi = UFS_SB(sb); | ||
742 | unsigned long delay; | ||
743 | |||
744 | spin_lock(&sbi->work_lock); | ||
745 | if (!sbi->work_queued) { | ||
746 | delay = msecs_to_jiffies(dirty_writeback_interval * 10); | ||
747 | queue_delayed_work(system_long_wq, &sbi->sync_work, delay); | ||
748 | sbi->work_queued = 1; | ||
749 | } | ||
750 | spin_unlock(&sbi->work_lock); | ||
733 | } | 751 | } |
734 | 752 | ||
735 | static void ufs_put_super(struct super_block *sb) | 753 | static void ufs_put_super(struct super_block *sb) |
@@ -740,6 +758,7 @@ static void ufs_put_super(struct super_block *sb) | |||
740 | 758 | ||
741 | if (!(sb->s_flags & MS_RDONLY)) | 759 | if (!(sb->s_flags & MS_RDONLY)) |
742 | ufs_put_super_internal(sb); | 760 | ufs_put_super_internal(sb); |
761 | cancel_delayed_work_sync(&sbi->sync_work); | ||
743 | 762 | ||
744 | ubh_brelse_uspi (sbi->s_uspi); | 763 | ubh_brelse_uspi (sbi->s_uspi); |
745 | kfree (sbi->s_uspi); | 764 | kfree (sbi->s_uspi); |
@@ -774,6 +793,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) | |||
774 | if (!sbi) | 793 | if (!sbi) |
775 | goto failed_nomem; | 794 | goto failed_nomem; |
776 | sb->s_fs_info = sbi; | 795 | sb->s_fs_info = sbi; |
796 | sbi->sb = sb; | ||
777 | 797 | ||
778 | UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY)); | 798 | UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY)); |
779 | 799 | ||
@@ -785,6 +805,8 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) | |||
785 | } | 805 | } |
786 | #endif | 806 | #endif |
787 | mutex_init(&sbi->mutex); | 807 | mutex_init(&sbi->mutex); |
808 | spin_lock_init(&sbi->work_lock); | ||
809 | INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs); | ||
788 | /* | 810 | /* |
789 | * Set default mount options | 811 | * Set default mount options |
790 | * Parse mount options | 812 | * Parse mount options |
@@ -1304,7 +1326,6 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
1304 | ufs_set_fs_state(sb, usb1, usb3, | 1326 | ufs_set_fs_state(sb, usb1, usb3, |
1305 | UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); | 1327 | UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); |
1306 | ubh_mark_buffer_dirty (USPI_UBH(uspi)); | 1328 | ubh_mark_buffer_dirty (USPI_UBH(uspi)); |
1307 | sb->s_dirt = 0; | ||
1308 | sb->s_flags |= MS_RDONLY; | 1329 | sb->s_flags |= MS_RDONLY; |
1309 | } else { | 1330 | } else { |
1310 | /* | 1331 | /* |
@@ -1454,7 +1475,6 @@ static const struct super_operations ufs_super_ops = { | |||
1454 | .write_inode = ufs_write_inode, | 1475 | .write_inode = ufs_write_inode, |
1455 | .evict_inode = ufs_evict_inode, | 1476 | .evict_inode = ufs_evict_inode, |
1456 | .put_super = ufs_put_super, | 1477 | .put_super = ufs_put_super, |
1457 | .write_super = ufs_write_super, | ||
1458 | .sync_fs = ufs_sync_fs, | 1478 | .sync_fs = ufs_sync_fs, |
1459 | .statfs = ufs_statfs, | 1479 | .statfs = ufs_statfs, |
1460 | .remount_fs = ufs_remount, | 1480 | .remount_fs = ufs_remount, |
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 528750b7e701..343e6fc571e5 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h | |||
@@ -20,6 +20,10 @@ struct ufs_sb_info { | |||
20 | unsigned s_mount_opt; | 20 | unsigned s_mount_opt; |
21 | struct mutex mutex; | 21 | struct mutex mutex; |
22 | struct task_struct *mutex_owner; | 22 | struct task_struct *mutex_owner; |
23 | struct super_block *sb; | ||
24 | int work_queued; /* non-zero if the delayed work is queued */ | ||
25 | struct delayed_work sync_work; /* FS sync delayed work */ | ||
26 | spinlock_t work_lock; /* protects sync_work and work_queued */ | ||
23 | }; | 27 | }; |
24 | 28 | ||
25 | struct ufs_inode_info { | 29 | struct ufs_inode_info { |
@@ -123,6 +127,7 @@ extern __printf(3, 4) | |||
123 | void ufs_error(struct super_block *, const char *, const char *, ...); | 127 | void ufs_error(struct super_block *, const char *, const char *, ...); |
124 | extern __printf(3, 4) | 128 | extern __printf(3, 4) |
125 | void ufs_panic(struct super_block *, const char *, const char *, ...); | 129 | void ufs_panic(struct super_block *, const char *, const char *, ...); |
130 | void ufs_mark_sb_dirty(struct super_block *sb); | ||
126 | 131 | ||
127 | /* symlink.c */ | 132 | /* symlink.c */ |
128 | extern const struct inode_operations ufs_fast_symlink_inode_operations; | 133 | extern const struct inode_operations ufs_fast_symlink_inode_operations; |
diff --git a/fs/ufs/ufs_fs.h b/fs/ufs/ufs_fs.h index 8aba544f9fad..0cbd5d340b67 100644 --- a/fs/ufs/ufs_fs.h +++ b/fs/ufs/ufs_fs.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/kernel.h> | 34 | #include <linux/kernel.h> |
35 | #include <linux/stat.h> | 35 | #include <linux/stat.h> |
36 | #include <linux/fs.h> | 36 | #include <linux/fs.h> |
37 | #include <linux/workqueue.h> | ||
37 | 38 | ||
38 | #include <asm/div64.h> | 39 | #include <asm/div64.h> |
39 | typedef __u64 __bitwise __fs64; | 40 | typedef __u64 __bitwise __fs64; |