Add lazytime patches
[ext4-patch-queue.git] / make-sure-dirtytime-inodes-eventually-get-written
blob54d36160a2b6dc3c532d67f5a00b4f60082b4fd3
1 fs: make sure the timestamps for lazytime inodes eventually get written
3 Jan Kara pointed out that if there is an inode which is constantly
4 getting dirtied with I_DIRTY_PAGES, an inode with an updated timestamp
5 will never be written since inode->dirtied_when is constantly getting
6 updated.  We fix this by adding an extra field to the inode,
7 dirtied_time_when, so inodes with a stale dirtytime can get detected
8 and handled.
10 In addition, if we have a dirtytime inode caused by an atime update,
11 and there is no write activity on the file system, we need to have a
12 secondary system to make sure these inodes get written out.  We do
13 this by setting up a second delayed work structure which wakes up the
14 CPU much more rarely compared to writeback_expire_centisecs.
16 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
17 ---
18  fs/fs-writeback.c         | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
19  include/linux/fs.h        |  1 +
20  include/linux/writeback.h |  2 ++
21  kernel/sysctl.c           |  2 +-
22  4 files changed, 85 insertions(+), 12 deletions(-)
24 diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
25 index 705f036..0489712 100644
26 --- a/fs/fs-writeback.c
27 +++ b/fs/fs-writeback.c
28 @@ -53,8 +53,17 @@ struct wb_writeback_work {
29         struct completion *done;        /* set if the caller waits */
30  };
32 -/* 24 hours in seconds */
33 -unsigned int dirtytime_expire_interval = 24 * 60 * 60;
34 +/*
35 + * If an inode is constantly having its pages dirtied, but then the
36 + * updates stop dirtytime_expire_interval seconds in the past, it's
37 + * possible for the worst case time between when an inode has its
38 + * timestamps updated and when they finally get written out to be two
39 + * dirtytime_expire_intervals.  We set the default to 12 hours (in
40 + * seconds), which means most of the time inodes will have their
41 + * timestamps written to disk after 12 hours, but in the worst case a
42 + * few inodes might not their timestamps updated for 24 hours.
43 + */
44 +unsigned int dirtytime_expire_interval = 12 * 60 * 60;
46  /**
47   * writeback_in_progress - determine whether there is writeback in progress
48 @@ -278,7 +287,7 @@ static int move_expired_inodes(struct list_head *delaying_queue,
50         if ((flags & EXPIRE_DIRTY_ATIME) == 0)
51                 older_than_this = work->older_than_this;
52 -       else if ((work->reason == WB_REASON_SYNC) == 0) {
53 +       else if (!work->for_sync) {
54                 expire_time = jiffies - (dirtytime_expire_interval * HZ);
55                 older_than_this = &expire_time;
56         }
57 @@ -461,6 +470,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
58                  */
59                 redirty_tail(inode, wb);
60         } else if (inode->i_state & I_DIRTY_TIME) {
61 +               inode->dirtied_when = jiffies;
62                 list_move(&inode->i_wb_list, &wb->b_dirty_time);
63         } else {
64                 /* The inode is clean. Remove from writeback lists. */
65 @@ -508,12 +518,16 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
66         spin_lock(&inode->i_lock);
68         dirty = inode->i_state & I_DIRTY;
69 -       if (((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) &&
70 -            (inode->i_state & I_DIRTY_TIME)) ||
71 -           (inode->i_state & I_DIRTY_TIME_EXPIRED)) {
72 -               dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED;
73 -               trace_writeback_lazytime(inode);
74 -       }
75 +       if (inode->i_state & I_DIRTY_TIME) {
76 +               if ((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) ||
77 +                   unlikely(inode->i_state & I_DIRTY_TIME_EXPIRED) ||
78 +                   unlikely(time_after(inode->dirtied_time_when,
79 +                               (jiffies + dirtytime_expire_interval * HZ)))) {
80 +                       dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED;
81 +                       trace_writeback_lazytime(inode);
82 +               }
83 +       } else
84 +               inode->i_state &= ~I_DIRTY_TIME_EXPIRED;
85         inode->i_state &= ~dirty;
87         /*
88 @@ -1134,6 +1148,57 @@ void wakeup_flusher_threads(long nr_pages, enum wb_reason reason)
89         rcu_read_unlock();
90  }
92 +/*
93 + * Wake up bdi's periodically to make sure dirtytime inodes gets
94 + * written back periodically.  We deliberately do *not* check the
95 + * b_dirtytime list in wb_has_dirty_io(), since this would cause the
96 + * kernel to be constantly waking up once there are any dirtytime
97 + * inodes on the system.  So instead we define a separate delayed work
98 + * function which gets called much more rarely.  (By default, only
99 + * once every 12 hours.)
100 + *
101 + * If there is any other write activity going on in the file system,
102 + * this function won't be necessary.  But if the only thing that has
103 + * happened on the file system is a dirtytime inode caused by an atime
104 + * update, we need this infrastructure below to make sure that inode
105 + * eventually gets pushed out to disk.
106 + */
107 +static void wakeup_dirtytime_writeback(struct work_struct *w);
108 +static DECLARE_DELAYED_WORK(dirtytime_work, wakeup_dirtytime_writeback);
110 +static void wakeup_dirtytime_writeback(struct work_struct *w)
112 +       struct backing_dev_info *bdi;
114 +       rcu_read_lock();
115 +       list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
116 +               if (list_empty(&bdi->wb.b_dirty_time))
117 +                       continue;
118 +               bdi_wakeup_thread(bdi);
119 +       }
120 +       rcu_read_unlock();
121 +       schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
124 +static int __init start_dirtytime_writeback(void)
126 +       schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
127 +       return 0;
129 +__initcall(start_dirtytime_writeback);
131 +int dirtytime_interval_handler(struct ctl_table *table, int write,
132 +                              void __user *buffer, size_t *lenp, loff_t *ppos)
134 +       int ret;
136 +       ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
137 +       if (ret == 0 && write)
138 +               mod_delayed_work(system_wq, &dirtytime_work, 0);
139 +       return ret;
143  static noinline void block_dump___mark_inode_dirty(struct inode *inode)
145         if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) {
146 @@ -1272,8 +1337,13 @@ void __mark_inode_dirty(struct inode *inode, int flags)
147                         }
149                         inode->dirtied_when = jiffies;
150 -                       list_move(&inode->i_wb_list, dirtytime ?
151 -                                 &bdi->wb.b_dirty_time : &bdi->wb.b_dirty);
152 +                       if (dirtytime)
153 +                               inode->dirtied_time_when = jiffies;
154 +                       if (inode->i_state & (I_DIRTY_INODE | I_DIRTY_PAGES))
155 +                               list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
156 +                       else
157 +                               list_move(&inode->i_wb_list,
158 +                                         &bdi->wb.b_dirty_time);
159                         spin_unlock(&bdi->wb.list_lock);
160                         trace_writeback_dirty_inode_enqueue(inode);
162 diff --git a/include/linux/fs.h b/include/linux/fs.h
163 index b4d71b5..f4131e8 100644
164 --- a/include/linux/fs.h
165 +++ b/include/linux/fs.h
166 @@ -604,6 +604,7 @@ struct inode {
167         struct mutex            i_mutex;
169         unsigned long           dirtied_when;   /* jiffies of first dirtying */
170 +       unsigned long           dirtied_time_when;
172         struct hlist_node       i_hash;
173         struct list_head        i_wb_list;      /* backing dev IO list */
174 diff --git a/include/linux/writeback.h b/include/linux/writeback.h
175 index ba65fd0..b2dd371e 100644
176 --- a/include/linux/writeback.h
177 +++ b/include/linux/writeback.h
178 @@ -147,6 +147,8 @@ extern int dirty_ratio_handler(struct ctl_table *table, int write,
179  extern int dirty_bytes_handler(struct ctl_table *table, int write,
180                 void __user *buffer, size_t *lenp,
181                 loff_t *ppos);
182 +int dirtytime_interval_handler(struct ctl_table *table, int write,
183 +                              void __user *buffer, size_t *lenp, loff_t *ppos);
185  struct ctl_table;
186  int dirty_writeback_centisecs_handler(struct ctl_table *, int,
187 diff --git a/kernel/sysctl.c b/kernel/sysctl.c
188 index 44e6a25..ce410bb 100644
189 --- a/kernel/sysctl.c
190 +++ b/kernel/sysctl.c
191 @@ -1232,7 +1232,7 @@ static struct ctl_table vm_table[] = {
192                 .data           = &dirtytime_expire_interval,
193                 .maxlen         = sizeof(dirty_expire_interval),
194                 .mode           = 0644,
195 -               .proc_handler   = proc_dointvec_minmax,
196 +               .proc_handler   = dirtytime_interval_handler,
197                 .extra1         = &zero,
198         },
199         {