remove unnecessary iput checks
[ext4-patch-queue.git] / dont-let-dirty-time-inodes-get-more-than-a-day-stale
bloba3f8b4de0c6b35f1325e150832c02440750b204f
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                | 28 +++++++++++++++++++++++-----
10  include/linux/fs.h        |  1 +
11  include/trace/events/fs.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12  4 files changed, 81 insertions(+), 5 deletions(-)
14 diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
15 index ce7de22..eb04277 100644
16 --- a/fs/fs-writeback.c
17 +++ b/fs/fs-writeback.c
18 @@ -1141,6 +1141,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
19         if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
20                 trace_writeback_dirty_inode_start(inode, flags);
22 +               inode->i_ts_dirty_day = 0;
23                 if (sb->s_op->dirty_inode)
24                         sb->s_op->dirty_inode(inode, flags);
26 diff --git a/fs/inode.c b/fs/inode.c
27 index 2093a84..321c7d7 100644
28 --- a/fs/inode.c
29 +++ b/fs/inode.c
30 @@ -1511,6 +1511,8 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
31   */
32  static int update_time(struct inode *inode, struct timespec *time, int flags)
33  {
34 +       struct timespec uptime;
35 +       unsigned short days_since_boot;
36         int ret;
38         if (inode->i_op->update_time) {
39 @@ -1525,17 +1527,33 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
40                 if (flags & S_CTIME)
41                         inode->i_ctime = *time;
42                 if (flags & S_MTIME)
43 -                       inode->i_mtime = *time;
44 +               inode->i_mtime = *time;
45         }
46 +       /*
47 +        * If i_ts_dirty_day is zero, then either we have not deferred
48 +        * timestamp updates, or the system has been up for less than
49 +        * a day (so days_since_boot is zero), so we defer timestamp
50 +        * updates in that case and set the I_DIRTY_TIME flag.  If a
51 +        * day or more has passed, then i_ts_dirty_day will be
52 +        * different from days_since_boot, and then we should update
53 +        * the on-disk inode and then we can clear i_ts_dirty_day.
54 +        */
55         if ((inode->i_sb->s_flags & MS_LAZYTIME) &&
56             !(flags & S_VERSION)) {
57                 if (inode->i_state & I_DIRTY_TIME)
58                         return 0;
59 -               spin_lock(&inode->i_lock);
60 -               inode->i_state |= I_DIRTY_TIME;
61 -               spin_unlock(&inode->i_lock);
62 -               return 0;
63 +               get_monotonic_boottime(&uptime);
64 +               days_since_boot = div_u64(uptime.tv_sec, 86400);
65 +               if (!inode->i_ts_dirty_day ||
66 +                   inode->i_ts_dirty_day == days_since_boot) {
67 +                       spin_lock(&inode->i_lock);
68 +                       inode->i_state |= I_DIRTY_TIME;
69 +                       spin_unlock(&inode->i_lock);
70 +                       inode->i_ts_dirty_day = days_since_boot;
71 +                       return 0;
72 +               }
73         }
74 +       inode->i_ts_dirty_day = 0;
75         if (inode->i_op->write_time)
76                 return inode->i_op->write_time(inode);
77         mark_inode_dirty_sync(inode);
78 diff --git a/include/linux/fs.h b/include/linux/fs.h
79 index 489b2f2..e3574cd 100644
80 --- a/include/linux/fs.h
81 +++ b/include/linux/fs.h
82 @@ -575,6 +575,7 @@ struct inode {
83         struct timespec         i_ctime;
84         spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
85         unsigned short          i_bytes;
86 +       unsigned short          i_ts_dirty_day;
87         unsigned int            i_blkbits;
88         blkcnt_t                i_blocks;
90 diff --git a/include/trace/events/fs.h b/include/trace/events/fs.h
91 new file mode 100644
92 index 0000000..ca06d5c
93 --- /dev/null
94 +++ b/include/trace/events/fs.h
95 @@ -0,0 +1,56 @@
96 +#undef TRACE_SYSTEM
97 +#define TRACE_SYSTEM fs
99 +#if !defined(_TRACE_FS_H) || defined(TRACE_HEADER_MULTI_READ)
100 +#define _TRACE_FS_H
102 +#include <linux/tracepoint.h>
104 +DECLARE_EVENT_CLASS(fs__inode,
105 +       TP_PROTO(struct inode *inode),
107 +       TP_ARGS(inode),
109 +       TP_STRUCT__entry(
110 +               __field(        dev_t,  dev                     )
111 +               __field(        ino_t,  ino                     )
112 +               __field(        uid_t,  uid                     )
113 +               __field(        gid_t,  gid                     )
114 +               __field(        __u16, mode                     )
115 +       ),
117 +       TP_fast_assign(
118 +               __entry->dev    = inode->i_sb->s_dev;
119 +               __entry->ino    = inode->i_ino;
120 +               __entry->uid    = i_uid_read(inode);
121 +               __entry->gid    = i_gid_read(inode);
122 +               __entry->mode   = inode->i_mode;
123 +       ),
125 +       TP_printk("dev %d,%d ino %lu mode 0%o uid %u gid %u",
126 +                 MAJOR(__entry->dev), MINOR(__entry->dev),
127 +                 (unsigned long) __entry->ino, __entry->mode,
128 +                 __entry->uid, __entry->gid)
131 +DEFINE_EVENT(fs__inode, fs_lazytime_defer,
132 +       TP_PROTO(struct inode *inode),
134 +       TP_ARGS(inode)
137 +DEFINE_EVENT(fs__inode, fs_lazytime_evict,
138 +       TP_PROTO(struct inode *inode),
140 +       TP_ARGS(inode)
143 +DEFINE_EVENT(fs__inode, fs_lazytime_flush,
144 +       TP_PROTO(struct inode *inode),
146 +       TP_ARGS(inode)
148 +#endif /* _TRACE_FS_H */
150 +/* This part must be outside protection */
151 +#include <trace/define_trace.h>