add patch improve-code-readability-in-ext4_iget
[ext4-patch-queue.git] / extend-timestamps-to-40-bits
blob3df1b3d8cd3a677fc1d85f00bf11a2e1dae59d1c
1 ext4: super: extend timestamps to 40 bits
3 From: Arnd Bergmann <arnd@arndb.de>
5 The inode timestamps use 34 bits in ext4, but the various timestamps in
6 the superblock are limited to 32 bits. If every user accesses these as
7 'unsigned', then this is good until year 2106, but it seems better to
8 extend this a bit further in the process of removing the deprecated
9 get_seconds() function.
11 This adds another byte for each timestamp in the superblock, making
12 them long enough to store timestamps beyond what is in the inodes,
13 which seems good enough here (in ocfs2, they are already 64-bit wide,
14 which is appropriate for a new layout).
16 I did not modify e2fsprogs, which obviously needs the same change to
17 actually interpret future timestamps correctly.
19 Signed-off-by: Arnd Bergmann <arnd@arndb.de>
20 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
21 ---
22 v2: drop 'RFC' from subject
23     minor changes as suggested by Andreas Dilger
24 ---
25  fs/ext4/ext4.h  |  9 ++++++++-
26  fs/ext4/super.c | 39 ++++++++++++++++++++++++++++++---------
27  fs/ext4/sysfs.c | 19 +++++++++++++++++--
28  3 files changed, 55 insertions(+), 12 deletions(-)
30 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
31 index f71ccafe8f9f..3ee9f198c698 100644
32 --- a/fs/ext4/ext4.h
33 +++ b/fs/ext4/ext4.h
34 @@ -1295,7 +1295,14 @@ struct ext4_super_block {
35         __le32  s_lpf_ino;              /* Location of the lost+found inode */
36         __le32  s_prj_quota_inum;       /* inode for tracking project quota */
37         __le32  s_checksum_seed;        /* crc32c(uuid) if csum_seed set */
38 -       __le32  s_reserved[98];         /* Padding to the end of the block */
39 +       __u8    s_wtime_hi;
40 +       __u8    s_mtime_hi;
41 +       __u8    s_mkfs_time_hi;
42 +       __u8    s_lastcheck_hi;
43 +       __u8    s_first_error_time_hi;
44 +       __u8    s_last_error_time_hi;
45 +       __u8    s_pad[2];
46 +       __le32  s_reserved[96];         /* Padding to the end of the block */
47         __le32  s_checksum;             /* crc32c(superblock) */
48  };
50 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
51 index 86e3d13787e6..aaf29e3981db 100644
52 --- a/fs/ext4/super.c
53 +++ b/fs/ext4/super.c
54 @@ -313,6 +313,24 @@ void ext4_itable_unused_set(struct super_block *sb,
55                 bg->bg_itable_unused_hi = cpu_to_le16(count >> 16);
56  }
58 +static void __ext4_update_tstamp(__le32 *lo, __u8 *hi)
60 +       time64_t now = ktime_get_real_seconds();
62 +       now = clamp_val(now, 0, (1ull << 40) - 1);
64 +       *lo = cpu_to_le32(lower_32_bits(now));
65 +       *hi = upper_32_bits(now);
68 +static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi)
70 +       return ((time64_t)(*hi) << 32) + le32_to_cpu(*lo);
72 +#define ext4_update_tstamp(es, tstamp) \
73 +       __ext4_update_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi)
74 +#define ext4_get_tstamp(es, tstamp) \
75 +       __ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi)
77  static void __save_error_info(struct super_block *sb, const char *func,
78                             unsigned int line)
79 @@ -323,11 +341,12 @@ static void __save_error_info(struct super_block *sb, const char *func,
80         if (bdev_read_only(sb->s_bdev))
81                 return;
82         es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
83 -       es->s_last_error_time = cpu_to_le32(get_seconds());
84 +       ext4_update_tstamp(es, s_last_error_time);
85         strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func));
86         es->s_last_error_line = cpu_to_le32(line);
87         if (!es->s_first_error_time) {
88                 es->s_first_error_time = es->s_last_error_time;
89 +               es->s_first_error_time_hi = es->s_last_error_time_hi;
90                 strncpy(es->s_first_error_func, func,
91                         sizeof(es->s_first_error_func));
92                 es->s_first_error_line = cpu_to_le32(line);
93 @@ -2175,8 +2194,8 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
94                          "warning: maximal mount count reached, "
95                          "running e2fsck is recommended");
96         else if (le32_to_cpu(es->s_checkinterval) &&
97 -               (le32_to_cpu(es->s_lastcheck) +
98 -                       le32_to_cpu(es->s_checkinterval) <= get_seconds()))
99 +                (ext4_get_tstamp(es, s_lastcheck) +
100 +                 le32_to_cpu(es->s_checkinterval) <= ktime_get_real_seconds()))
101                 ext4_msg(sb, KERN_WARNING,
102                          "warning: checktime reached, "
103                          "running e2fsck is recommended");
104 @@ -2185,7 +2204,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
105         if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
106                 es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT);
107         le16_add_cpu(&es->s_mnt_count, 1);
108 -       es->s_mtime = cpu_to_le32(get_seconds());
109 +       ext4_update_tstamp(es, s_mtime);
110         ext4_update_dynamic_rev(sb);
111         if (sbi->s_journal)
112                 ext4_set_feature_journal_needs_recovery(sb);
113 @@ -2876,8 +2895,9 @@ static void print_daily_error_info(struct timer_list *t)
114                 ext4_msg(sb, KERN_NOTICE, "error count since last fsck: %u",
115                          le32_to_cpu(es->s_error_count));
116         if (es->s_first_error_time) {
117 -               printk(KERN_NOTICE "EXT4-fs (%s): initial error at time %u: %.*s:%d",
118 -                      sb->s_id, le32_to_cpu(es->s_first_error_time),
119 +               printk(KERN_NOTICE "EXT4-fs (%s): initial error at time %llu: %.*s:%d",
120 +                      sb->s_id,
121 +                      ext4_get_tstamp(es, s_first_error_time),
122                        (int) sizeof(es->s_first_error_func),
123                        es->s_first_error_func,
124                        le32_to_cpu(es->s_first_error_line));
125 @@ -2890,8 +2910,9 @@ static void print_daily_error_info(struct timer_list *t)
126                 printk(KERN_CONT "\n");
127         }
128         if (es->s_last_error_time) {
129 -               printk(KERN_NOTICE "EXT4-fs (%s): last error at time %u: %.*s:%d",
130 -                      sb->s_id, le32_to_cpu(es->s_last_error_time),
131 +               printk(KERN_NOTICE "EXT4-fs (%s): last error at time %llu: %.*s:%d",
132 +                      sb->s_id,
133 +                      ext4_get_tstamp(es, s_last_error_time),
134                        (int) sizeof(es->s_last_error_func),
135                        es->s_last_error_func,
136                        le32_to_cpu(es->s_last_error_line));
137 @@ -4822,7 +4843,7 @@ static int ext4_commit_super(struct super_block *sb, int sync)
138          * to complain and force a full file system check.
139          */
140         if (!(sb->s_flags & SB_RDONLY))
141 -               es->s_wtime = cpu_to_le32(get_seconds());
142 +               ext4_update_tstamp(es, s_wtime);
143         if (sb->s_bdev->bd_part)
144                 es->s_kbytes_written =
145                         cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
146 diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
147 index b970a200f20c..e60cc5e89023 100644
148 --- a/fs/ext4/sysfs.c
149 +++ b/fs/ext4/sysfs.c
150 @@ -25,6 +25,8 @@ typedef enum {
151         attr_reserved_clusters,
152         attr_inode_readahead,
153         attr_trigger_test_error,
154 +       attr_first_error_time,
155 +       attr_last_error_time,
156         attr_feature,
157         attr_pointer_ui,
158         attr_pointer_atomic,
159 @@ -182,8 +184,8 @@ EXT4_RW_ATTR_SBI_UI(warning_ratelimit_burst, s_warning_ratelimit_state.burst);
160  EXT4_RW_ATTR_SBI_UI(msg_ratelimit_interval_ms, s_msg_ratelimit_state.interval);
161  EXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst);
162  EXT4_RO_ATTR_ES_UI(errors_count, s_error_count);
163 -EXT4_RO_ATTR_ES_UI(first_error_time, s_first_error_time);
164 -EXT4_RO_ATTR_ES_UI(last_error_time, s_last_error_time);
165 +EXT4_ATTR(first_error_time, 0444, first_error_time);
166 +EXT4_ATTR(last_error_time, 0444, last_error_time);
168  static unsigned int old_bump_val = 128;
169  EXT4_ATTR_PTR(max_writeback_mb_bump, 0444, pointer_ui, &old_bump_val);
170 @@ -249,6 +251,15 @@ static void *calc_ptr(struct ext4_attr *a, struct ext4_sb_info *sbi)
171         return NULL;
174 +static ssize_t __print_tstamp(char *buf, __le32 lo, __u8 hi)
176 +       return snprintf(buf, PAGE_SIZE, "%lld",
177 +                       ((time64_t)hi << 32) + le32_to_cpu(lo));
180 +#define print_tstamp(buf, es, tstamp) \
181 +       __print_tstamp(buf, (es)->tstamp, (es)->tstamp ## _hi)
183  static ssize_t ext4_attr_show(struct kobject *kobj,
184                               struct attribute *attr, char *buf)
186 @@ -287,6 +298,10 @@ static ssize_t ext4_attr_show(struct kobject *kobj,
187                                 atomic_read((atomic_t *) ptr));
188         case attr_feature:
189                 return snprintf(buf, PAGE_SIZE, "supported\n");
190 +       case attr_first_error_time:
191 +               return print_tstamp(buf, sbi->s_es, s_first_error_time);
192 +       case attr_last_error_time:
193 +               return print_tstamp(buf, sbi->s_es, s_last_error_time);
194         }
196         return 0;
197 -- 
198 2.9.0