hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/fs/fat/misc.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * linux/fs/fat/misc.c
34 *
....@@ -7,6 +8,7 @@
78 */
89
910 #include "fat.h"
11
+#include <linux/iversion.h>
1012
1113 /*
1214 * fat_fs_error reports a file system problem that might indicate fa data
....@@ -63,7 +65,7 @@
6365 struct buffer_head *bh;
6466 struct fat_boot_fsinfo *fsinfo;
6567
66
- if (sbi->fat_bits != 32)
68
+ if (!is_fat32(sbi))
6769 return 0;
6870
6971 bh = sb_bread(sb, sbi->fsinfo_sector);
....@@ -185,6 +187,13 @@
185187 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
186188 };
187189
190
+static inline int fat_tz_offset(struct msdos_sb_info *sbi)
191
+{
192
+ return (sbi->options.tz_set ?
193
+ -sbi->options.time_offset :
194
+ sys_tz.tz_minuteswest) * SECS_PER_MIN;
195
+}
196
+
188197 /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
189198 void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec64 *ts,
190199 __le16 __time, __le16 __date, u8 time_cs)
....@@ -210,10 +219,7 @@
210219 + days_in_year[month] + day
211220 + DAYS_DELTA) * SECS_PER_DAY;
212221
213
- if (!sbi->options.tz_set)
214
- second += sys_tz.tz_minuteswest * SECS_PER_MIN;
215
- else
216
- second -= sbi->options.time_offset * SECS_PER_MIN;
222
+ second += fat_tz_offset(sbi);
217223
218224 if (time_cs) {
219225 ts->tv_sec = second + (time_cs / 100);
....@@ -229,9 +235,7 @@
229235 __le16 *time, __le16 *date, u8 *time_cs)
230236 {
231237 struct tm tm;
232
- time64_to_tm(ts->tv_sec,
233
- (sbi->options.tz_set ? sbi->options.time_offset :
234
- -sys_tz.tz_minuteswest) * SECS_PER_MIN, &tm);
238
+ time64_to_tm(ts->tv_sec, -fat_tz_offset(sbi), &tm);
235239
236240 /* FAT can only support year between 1980 to 2107 */
237241 if (tm.tm_year < 1980 - 1900) {
....@@ -263,6 +267,88 @@
263267 }
264268 EXPORT_SYMBOL_GPL(fat_time_unix2fat);
265269
270
+static inline struct timespec64 fat_timespec64_trunc_2secs(struct timespec64 ts)
271
+{
272
+ return (struct timespec64){ ts.tv_sec & ~1ULL, 0 };
273
+}
274
+
275
+static inline struct timespec64 fat_timespec64_trunc_10ms(struct timespec64 ts)
276
+{
277
+ if (ts.tv_nsec)
278
+ ts.tv_nsec -= ts.tv_nsec % 10000000UL;
279
+ return ts;
280
+}
281
+
282
+/*
283
+ * truncate the various times with appropriate granularity:
284
+ * root inode:
285
+ * all times always 0
286
+ * all other inodes:
287
+ * mtime - 2 seconds
288
+ * ctime
289
+ * msdos - 2 seconds
290
+ * vfat - 10 milliseconds
291
+ * atime - 24 hours (00:00:00 in local timezone)
292
+ */
293
+int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags)
294
+{
295
+ struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
296
+ struct timespec64 ts;
297
+
298
+ if (inode->i_ino == MSDOS_ROOT_INO)
299
+ return 0;
300
+
301
+ if (now == NULL) {
302
+ now = &ts;
303
+ ts = current_time(inode);
304
+ }
305
+
306
+ if (flags & S_ATIME) {
307
+ /* to localtime */
308
+ time64_t seconds = now->tv_sec - fat_tz_offset(sbi);
309
+ s32 remainder;
310
+
311
+ div_s64_rem(seconds, SECS_PER_DAY, &remainder);
312
+ /* to day boundary, and back to unix time */
313
+ seconds = seconds + fat_tz_offset(sbi) - remainder;
314
+
315
+ inode->i_atime = (struct timespec64){ seconds, 0 };
316
+ }
317
+ if (flags & S_CTIME) {
318
+ if (sbi->options.isvfat)
319
+ inode->i_ctime = fat_timespec64_trunc_10ms(*now);
320
+ else
321
+ inode->i_ctime = fat_timespec64_trunc_2secs(*now);
322
+ }
323
+ if (flags & S_MTIME)
324
+ inode->i_mtime = fat_timespec64_trunc_2secs(*now);
325
+
326
+ return 0;
327
+}
328
+EXPORT_SYMBOL_GPL(fat_truncate_time);
329
+
330
+int fat_update_time(struct inode *inode, struct timespec64 *now, int flags)
331
+{
332
+ int iflags = I_DIRTY_TIME;
333
+ bool dirty = false;
334
+
335
+ if (inode->i_ino == MSDOS_ROOT_INO)
336
+ return 0;
337
+
338
+ fat_truncate_time(inode, now, flags);
339
+ if (flags & S_VERSION)
340
+ dirty = inode_maybe_inc_iversion(inode, false);
341
+ if ((flags & (S_ATIME | S_CTIME | S_MTIME)) &&
342
+ !(inode->i_sb->s_flags & SB_LAZYTIME))
343
+ dirty = true;
344
+
345
+ if (dirty)
346
+ iflags |= I_DIRTY_SYNC;
347
+ __mark_inode_dirty(inode, iflags);
348
+ return 0;
349
+}
350
+EXPORT_SYMBOL_GPL(fat_update_time);
351
+
266352 int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
267353 {
268354 int i, err = 0;