[PATCH] vfs: Avoid unnecessary WB_SYNC_NONE writeback during sync(1)

From: Jan Kara
Date: Thu Jul 14 2011 - 17:42:19 EST


wakeup_flusher_thread(0) will queue work doing complete writeback for
each flusher thread. Thus there is not much point in submitting another
work doing full inode WB_SYNC_NONE writeback by sync_filesystems(). So change
sync to do:
wakeup_flusher_threads(0);
for each filesystem
async quota_sync()
synchronous inode writeback
async sync_fs()
submit dirty buffers from all block devices
for each filesystem
synchronous quota_sync()
synchronous sync_fs()
synchronous writeout of all block devices

Note that we do synchronous inode writeback before calling sync_fs().
Otherwise sync_fs() would be called in the middle of inode writeback done
by flusher thread and thus couldn't do very meaningful work.

Signed-off-by: Jan Kara <jack@xxxxxxx>
---
fs/sync.c | 38 ++++++++++++++++++++++++++++++++------
1 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/fs/sync.c b/fs/sync.c
index f8f21d9..fb6b8b2 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -21,6 +21,11 @@
#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
SYNC_FILE_RANGE_WAIT_AFTER)

+/* Wait flags for __sync_filesystem */
+#define WAIT_QUOTA 0x01
+#define WAIT_INODES 0x02
+#define WAIT_FS 0x04
+
/*
* Do the filesystem syncing work. For simple filesystems
* writeback_inodes_sb(sb) just dirties buffers with inodes so the caller has
@@ -31,15 +36,15 @@
static void __sync_filesystem(struct super_block *sb, int wait)
{
if (sb->s_qcop && sb->s_qcop->quota_sync)
- sb->s_qcop->quota_sync(sb, -1, wait);
+ sb->s_qcop->quota_sync(sb, -1, !!(wait & WAIT_QUOTA));

- if (wait)
+ if (wait & WAIT_INODES)
sync_inodes_sb(sb);
else
writeback_inodes_sb(sb);

if (sb->s_op->sync_fs)
- sb->s_op->sync_fs(sb, wait);
+ sb->s_op->sync_fs(sb, !!(wait & WAIT_FS));
}

/*
@@ -74,7 +79,7 @@ int sync_filesystem(struct super_block *sb)
ret = __sync_blockdev(sb->s_bdev, 0);
if (ret < 0)
return ret;
- __sync_filesystem(sb, 1);
+ __sync_filesystem(sb, WAIT_QUOTA | WAIT_INODES | WAIT_FS);
return __sync_blockdev(sb->s_bdev, 1);
}
EXPORT_SYMBOL_GPL(sync_filesystem);
@@ -130,16 +135,37 @@ static void sync_all_bdevs(int wait)
iput(old_inode);
}

+static void sync_one_fs_metadata(struct super_block *sb, void *arg)
+{
+ /* Avoid read-only filesystems and filesystems without backing device */
+ if (sb->s_flags & MS_RDONLY)
+ return;
+ if (sb->s_bdi == &noop_backing_dev_info)
+ return;
+ if (sb->s_qcop && sb->s_qcop->quota_sync)
+ sb->s_qcop->quota_sync(sb, -1, 1);
+ if (sb->s_op->sync_fs)
+ sb->s_op->sync_fs(sb, 1);
+}
+
/*
* sync everything. Start out by waking pdflush, because that writes back
* all queues in parallel.
*/
SYSCALL_DEFINE0(sync)
{
+ /* Start flushing on all devices */
wakeup_flusher_threads(0);
- sync_filesystems(0);
- sync_filesystems(1);
+ /*
+ * Above call queued work doing complete writeout on each filesystem.
+ * So now we only have to queue work which guarantees data integrity
+ * - not much should be left for it to write. The WB_SYNC_ALL inode
+ * writeback also guarantees that sync_fs() is called after inodes
+ * are written out and thus it can do meaningful work.
+ */
+ sync_filesystems(WAIT_INODES);
sync_all_bdevs(0);
+ iterate_supers(sync_one_fs_metadata, NULL);
sync_all_bdevs(1);
if (unlikely(laptop_mode))
laptop_sync_completion();
--
1.7.1


--4Ckj6UjgE2iN1+kY--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/