1 ext4: stop using VFS for dirty superblock management
3 From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
5 Do not use VFS for managing dirty superblock but do it inside
6 ext4. Remove the 'ext4_write_super()' VFS callback and instead,
7 schedule a delayed work when the superblock is marked as dirty. Use
8 the 'dio_unwritten_wq' which we already have for these purposes.
10 We add memory barriers to make sure the 's_dirt' flag changes are
11 visible to other CPUs as soon as possible to avoid queuing unnecessary
14 The big changes comparing to the previous behavior:
15 1. We use 'dio_unwritten' queue, so the superblock will be written by
16 per-filesystem 'ext4-dio-unwrit' thread, instead of 'sync_supers'
19 2. We allocate memory in 'ext4_mark_super_dirty()'.
21 Note: the final goal is to get rid of the 'sync_supers()' kernel
22 thread which wakes up every 5 seconds and even if there is nothing to
23 do. Thus, we are pushing superblock management from VFS down to
26 Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
27 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
29 fs/ext4/super.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++-------
30 1 files changed, 63 insertions(+), 10 deletions(-)
32 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
33 index d9543f3..7d453f7 100644
36 @@ -73,7 +73,6 @@ static const char *ext4_decode_error(struct super_block *sb, int errno,
37 static int ext4_remount(struct super_block *sb, int *flags, char *data);
38 static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf);
39 static int ext4_unfreeze(struct super_block *sb);
40 -static void ext4_write_super(struct super_block *sb);
41 static int ext4_freeze(struct super_block *sb);
42 static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags,
43 const char *dev_name, void *data);
44 @@ -1294,7 +1293,6 @@ static const struct super_operations ext4_nojournal_sops = {
45 .dirty_inode = ext4_dirty_inode,
46 .drop_inode = ext4_drop_inode,
47 .evict_inode = ext4_evict_inode,
48 - .write_super = ext4_write_super,
49 .put_super = ext4_put_super,
50 .statfs = ext4_statfs,
51 .remount_fs = ext4_remount,
52 @@ -4140,6 +4138,14 @@ static int ext4_commit_super(struct super_block *sb, int sync)
54 if (!sbh || block_device_ejected(sb))
59 + * Make sure we first mark the superblock as clean and then start
64 if (buffer_write_io_error(sbh)) {
66 * Oh, dear. A previous attempt to write the
67 @@ -4180,7 +4186,6 @@ static int ext4_commit_super(struct super_block *sb, int sync)
68 es->s_free_inodes_count =
69 cpu_to_le32(percpu_counter_sum_positive(
70 &EXT4_SB(sb)->s_freeinodes_counter));
72 BUFFER_TRACE(sbh, "marking dirty");
73 mark_buffer_dirty(sbh);
75 @@ -4199,9 +4204,64 @@ static int ext4_commit_super(struct super_block *sb, int sync)
79 +struct sb_delayed_work {
80 + struct delayed_work dwork;
81 + struct super_block *sb;
84 +static struct sb_delayed_work *work_to_sbwork(struct work_struct *work)
86 + struct delayed_work *dwork;
88 + dwork = container_of(work, struct delayed_work, work);
89 + return container_of(dwork, struct sb_delayed_work, dwork);
92 +static void write_super(struct work_struct *work)
94 + struct sb_delayed_work *sbwork = work_to_sbwork(work);
95 + struct super_block *sb = sbwork->sb;
104 + ext4_commit_super(sb, 1);
108 void __ext4_mark_super_dirty(struct super_block *sb)
110 + struct ext4_sb_info *sbi = EXT4_SB(sb);
111 + struct sb_delayed_work *sbwork;
112 + unsigned long delay;
114 + /* Make sure we see 's_dirt' changes ASAP */
116 + if (sb->s_dirt == 1)
119 + /* Make other CPUs see the 's_dirt' change as soon as possible */
122 + sbwork = kmalloc(sizeof(struct sb_delayed_work), GFP_NOFS);
125 + * Well, should not be a big deal - the system must be in
126 + * trouble anyway, and the SB will be written out on unmount or
127 + * we may be luckier next time it is marked as dirty.
133 + INIT_DELAYED_WORK(&sbwork->dwork, write_super);
135 + delay = msecs_to_jiffies(dirty_writeback_interval * 10);
136 + queue_delayed_work(sbi->dio_unwritten_wq, &sbwork->dwork, delay);
140 @@ -4291,13 +4351,6 @@ int ext4_force_commit(struct super_block *sb)
144 -static void ext4_write_super(struct super_block *sb)
147 - ext4_commit_super(sb, 1);
151 static int ext4_sync_fs(struct super_block *sb, int wait)