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
6 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
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
30 @@ -1511,6 +1511,8 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
32 static int update_time(struct inode *inode, struct timespec *time, int flags)
34 + struct timespec uptime;
35 + unsigned short days_since_boot;
38 if (inode->i_op->update_time) {
39 @@ -1525,17 +1527,33 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
41 inode->i_ctime = *time;
43 - inode->i_mtime = *time;
44 + inode->i_mtime = *time;
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.
55 if ((inode->i_sb->s_flags & MS_LAZYTIME) &&
56 !(flags & S_VERSION)) {
57 if (inode->i_state & I_DIRTY_TIME)
59 - spin_lock(&inode->i_lock);
60 - inode->i_state |= I_DIRTY_TIME;
61 - spin_unlock(&inode->i_lock);
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;
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;
90 diff --git a/include/trace/events/fs.h b/include/trace/events/fs.h
92 index 0000000..ca06d5c
94 +++ b/include/trace/events/fs.h
97 +#define TRACE_SYSTEM fs
99 +#if !defined(_TRACE_FS_H) || defined(TRACE_HEADER_MULTI_READ)
102 +#include <linux/tracepoint.h>
104 +DECLARE_EVENT_CLASS(fs__inode,
105 + TP_PROTO(struct inode *inode),
110 + __field( dev_t, dev )
111 + __field( ino_t, ino )
112 + __field( uid_t, uid )
113 + __field( gid_t, gid )
114 + __field( __u16, mode )
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;
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),
137 +DEFINE_EVENT(fs__inode, fs_lazytime_evict,
138 + TP_PROTO(struct inode *inode),
143 +DEFINE_EVENT(fs__inode, fs_lazytime_flush,
144 + TP_PROTO(struct inode *inode),
148 +#endif /* _TRACE_FS_H */
150 +/* This part must be outside protection */
151 +#include <trace/define_trace.h>