Fix delalloc-debug
[ext4-patch-queue.git] / stop-using-VFS-for-dirty-superblock-management
blobf11e55b7b944c6a7c99f5dd472160e64e18291c9
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
12 works.
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'
17    thread.
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
24 file-systems.
26 Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
27 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
28 ---
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
34 --- a/fs/ext4/super.c
35 +++ b/fs/ext4/super.c
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))
55                 return error;
57 +       sb->s_dirt = 0;
58 +       /*
59 +        * Make sure we first mark the superblock as clean and then start
60 +        * writing it out.
61 +        */
62 +       smp_wmb();
64         if (buffer_write_io_error(sbh)) {
65                 /*
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));
71 -       sb->s_dirt = 0;
72         BUFFER_TRACE(sbh, "marking dirty");
73         mark_buffer_dirty(sbh);
74         if (sync) {
75 @@ -4199,9 +4204,64 @@ static int ext4_commit_super(struct super_block *sb, int sync)
76         return error;
77  }
79 +struct sb_delayed_work {
80 +       struct delayed_work dwork;
81 +       struct super_block *sb;
82 +};
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;
97 +       kfree(sbwork);
99 +       smp_rmb();
100 +       if (!sb->s_dirt)
101 +               return;
103 +       lock_super(sb);
104 +       ext4_commit_super(sb, 1);
105 +       unlock_super(sb);
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 */
115 +       smp_rmb();
116 +       if (sb->s_dirt == 1)
117 +               return;
118         sb->s_dirt = 1;
119 +       /* Make other CPUs see the 's_dirt' change as soon as possible */
120 +       smp_wmb();
122 +       sbwork = kmalloc(sizeof(struct sb_delayed_work), GFP_NOFS);
123 +       if (!sbwork) {
124 +               /*
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.
128 +                */
129 +               sb->s_dirt = 2;
130 +               return;
131 +       }
133 +       INIT_DELAYED_WORK(&sbwork->dwork, write_super);
134 +       sbwork->sb = sb;
135 +       delay = msecs_to_jiffies(dirty_writeback_interval * 10);
136 +       queue_delayed_work(sbi->dio_unwritten_wq, &sbwork->dwork, delay);
139  /*
140 @@ -4291,13 +4351,6 @@ int ext4_force_commit(struct super_block *sb)
141         return ret;
144 -static void ext4_write_super(struct super_block *sb)
146 -       lock_super(sb);
147 -       ext4_commit_super(sb, 1);
148 -       unlock_super(sb);
151  static int ext4_sync_fs(struct super_block *sb, int wait)
153         int ret = 0;
154 -- 
155 1.7.7.6