Additional changes to the patch series
[ext4-patch-queue.git] / dont-let-dirty-time-inodes-get-more-than-a-day-stale
blob31e8d2cb1ce279983d861eed3a3a913aa3f66163
1 vfs: don't let the dirty time inodes get more than a day stale
3 Guarantee that the on-disk timestamps will be no more than 24 hours
4 stale.
6 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
7 ---
8  fs/fs-writeback.c  |  1 +
9  fs/inode.c         | 19 +++++++++++++++++++
10  include/linux/fs.h |  1 +
11  3 files changed, 21 insertions(+)
13 diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
14 index ef8c5d8..529480a 100644
15 --- a/fs/fs-writeback.c
16 +++ b/fs/fs-writeback.c
17 @@ -1143,6 +1143,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
18         if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
19                 trace_writeback_dirty_inode_start(inode, flags);
21 +               inode->i_ts_dirty_day = 0;
22                 if (sb->s_op->dirty_inode)
23                         sb->s_op->dirty_inode(inode, flags);
25 diff --git a/fs/inode.c b/fs/inode.c
26 index 009d9c5..c8ad78b 100644
27 --- a/fs/inode.c
28 +++ b/fs/inode.c
29 @@ -1510,6 +1510,8 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
30   */
31  static int update_time(struct inode *inode, struct timespec *time, int flags)
32  {
33 +       struct timespec uptime;
34 +       unsigned short days_since_boot;
35         int ret;
37         if (inode->i_op->is_readonly) {
38 @@ -1532,6 +1534,22 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
39             !(inode->i_state & (I_DIRTY_SYNC | I_DIRTY_DATASYNC))) {
40                 if (inode->i_state & I_DIRTY_TIME)
41                         return 0;
42 +               get_monotonic_boottime(&uptime);
43 +               days_since_boot = div_u64(uptime.tv_sec, 86400);
44 +               /*
45 +                * If i_ts_dirty_day is zero, then either we have not
46 +                * deferred timestamp updates, or the system has been
47 +                * up for less than a day (so days_since_boot is
48 +                * zero), so we can defer timestamp updates in that
49 +                * case.  If a day or more has passed, then
50 +                * i_ts_dirty_day will be different from
51 +                * days_since_boot, and then we should update the
52 +                * on-disk inode and then we can clear i_ts_dirty_day.
53 +                */
54 +               if (inode->i_ts_dirty_day &&
55 +                   (inode->i_ts_dirty_day != days_since_boot))
56 +                       goto force_dirty;
58                 spin_lock(&inode->i_lock);
59                 if (inode->i_state & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
60                         spin_unlock(&inode->i_lock);
61 @@ -1542,6 +1560,7 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
62                         return 0;
63                 }
64                 inode->i_state |= I_DIRTY_TIME;
65 +               inode->i_ts_dirty_day = days_since_boot;
66                 spin_unlock(&inode->i_lock);
67                 inode_requeue_dirtytime(inode);
68                 return 0;
69 diff --git a/include/linux/fs.h b/include/linux/fs.h
70 index 6a6f56b..070f6c6 100644
71 --- a/include/linux/fs.h
72 +++ b/include/linux/fs.h
73 @@ -575,6 +575,7 @@ struct inode {
74         struct timespec         i_ctime;
75         spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
76         unsigned short          i_bytes;
77 +       unsigned short          i_ts_dirty_day;
78         unsigned int            i_blkbits;
79         blkcnt_t                i_blocks;