Blame view
fs/fat/misc.c
9.38 KB
457c89965 treewide: Add SPD... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 7 8 |
/* * linux/fs/fat/misc.c * * Written 1992,1993 by Werner Almesberger * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) */ |
9e975dae2 fat: split includ... |
9 |
#include "fat.h" |
6bb885ecd fat: add function... |
10 |
#include <linux/iversion.h> |
1da177e4c Linux-2.6.12-rc2 |
11 12 |
/* |
85c785919 FAT: add 'errors'... |
13 14 15 16 17 18 |
* fat_fs_error reports a file system problem that might indicate fa data * corruption/inconsistency. Depending on 'errors' mount option the * panic() is called, or error message is printed FAT and nothing is done, * or filesystem is remounted read-only (default behavior). * In case the file system is remounted read-only, it can be made writable * again by remounting it. |
1da177e4c Linux-2.6.12-rc2 |
19 |
*/ |
2c8a5ffb9 fat: Convert fat_... |
20 |
void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...) |
1da177e4c Linux-2.6.12-rc2 |
21 |
{ |
2c8a5ffb9 fat: Convert fat_... |
22 |
struct fat_mount_options *opts = &MSDOS_SB(sb)->options; |
1da177e4c Linux-2.6.12-rc2 |
23 |
va_list args; |
2c8a5ffb9 fat: Convert fat_... |
24 |
struct va_format vaf; |
1da177e4c Linux-2.6.12-rc2 |
25 |
|
aaa04b487 fatfs: ratelimit ... |
26 |
if (report) { |
aaa04b487 fatfs: ratelimit ... |
27 |
va_start(args, fmt); |
2c8a5ffb9 fat: Convert fat_... |
28 29 |
vaf.fmt = fmt; vaf.va = &args; |
e68e96d2a fs/fat: use fat_m... |
30 |
fat_msg(sb, KERN_ERR, "error, %pV", &vaf); |
aaa04b487 fatfs: ratelimit ... |
31 |
va_end(args); |
aaa04b487 fatfs: ratelimit ... |
32 |
} |
1da177e4c Linux-2.6.12-rc2 |
33 |
|
85c785919 FAT: add 'errors'... |
34 |
if (opts->errors == FAT_ERRORS_PANIC) |
2c8a5ffb9 fat: Convert fat_... |
35 36 |
panic("FAT-fs (%s): fs panic from previous error ", sb->s_id); |
bc98a42c1 VFS: Convert sb->... |
37 |
else if (opts->errors == FAT_ERRORS_RO && !sb_rdonly(sb)) { |
1751e8a6c Rename superblock... |
38 |
sb->s_flags |= SB_RDONLY; |
e68e96d2a fs/fat: use fat_m... |
39 |
fat_msg(sb, KERN_ERR, "Filesystem has been set read-only"); |
1da177e4c Linux-2.6.12-rc2 |
40 41 |
} } |
aaa04b487 fatfs: ratelimit ... |
42 |
EXPORT_SYMBOL_GPL(__fat_fs_error); |
1da177e4c Linux-2.6.12-rc2 |
43 |
|
81ac21d34 fat: Add fat_msg(... |
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
/** * fat_msg() - print preformated FAT specific messages. Every thing what is * not fat_fs_error() should be fat_msg(). */ void fat_msg(struct super_block *sb, const char *level, const char *fmt, ...) { struct va_format vaf; va_list args; va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; printk("%sFAT-fs (%s): %pV ", level, sb->s_id, &vaf); va_end(args); } |
1da177e4c Linux-2.6.12-rc2 |
60 61 |
/* Flushes the number of free clusters on FAT32 */ /* XXX: Need to write one per FSINFO block. Currently only writes 1 */ |
ed248b290 fat: Check s_dirt... |
62 |
int fat_clusters_flush(struct super_block *sb) |
1da177e4c Linux-2.6.12-rc2 |
63 64 65 66 |
{ struct msdos_sb_info *sbi = MSDOS_SB(sb); struct buffer_head *bh; struct fat_boot_fsinfo *fsinfo; |
306790f75 fat: new inline f... |
67 |
if (!is_fat32(sbi)) |
ed248b290 fat: Check s_dirt... |
68 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
69 70 71 |
bh = sb_bread(sb, sbi->fsinfo_sector); if (bh == NULL) { |
869f58c0c fat: Replace all ... |
72 |
fat_msg(sb, KERN_ERR, "bread failed in fat_clusters_flush"); |
ed248b290 fat: Check s_dirt... |
73 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
74 75 76 77 78 |
} fsinfo = (struct fat_boot_fsinfo *)bh->b_data; /* Sanity check */ if (!IS_FSINFO(fsinfo)) { |
869f58c0c fat: Replace all ... |
79 80 |
fat_msg(sb, KERN_ERR, "Invalid FSINFO signature: " "0x%08x, 0x%08x (sector = %lu)", |
1da177e4c Linux-2.6.12-rc2 |
81 82 83 84 85 86 87 88 89 |
le32_to_cpu(fsinfo->signature1), le32_to_cpu(fsinfo->signature2), sbi->fsinfo_sector); } else { if (sbi->free_clusters != -1) fsinfo->free_clusters = cpu_to_le32(sbi->free_clusters); if (sbi->prev_free != -1) fsinfo->next_cluster = cpu_to_le32(sbi->prev_free); mark_buffer_dirty(bh); |
1da177e4c Linux-2.6.12-rc2 |
90 91 |
} brelse(bh); |
ed248b290 fat: Check s_dirt... |
92 93 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
} /* * fat_chain_add() adds a new cluster to the chain of clusters represented * by inode. */ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) { struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); int ret, new_fclus, last; /* * We must locate the last cluster of the file to add this new * one (new_dclus) to the end of the link list (the FAT). */ last = new_fclus = 0; if (MSDOS_I(inode)->i_start) { int fclus, dclus; ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus); if (ret < 0) return ret; new_fclus = fclus + 1; last = dclus; } /* add new one to the last of the cluster chain */ if (last) { struct fat_entry fatent; fatent_init(&fatent); ret = fat_ent_read(inode, &fatent, last); if (ret >= 0) { int wait = inode_needs_sync(inode); ret = fat_ent_write(inode, &fatent, new_dclus, wait); fatent_brelse(&fatent); } if (ret < 0) return ret; |
c39540c6d fat: fix incorrec... |
134 135 136 137 |
/* * FIXME:Although we can add this cache, fat_cache_add() is * assuming to be called after linear search with fat_cache_id. */ |
1da177e4c Linux-2.6.12-rc2 |
138 139 140 141 142 |
// fat_cache_add(inode, new_fclus, new_dclus); } else { MSDOS_I(inode)->i_start = new_dclus; MSDOS_I(inode)->i_logstart = new_dclus; /* |
2f3d675bc fat: Opencode syn... |
143 144 |
* Since generic_write_sync() synchronizes regular files later, * we sync here only directories. |
1da177e4c Linux-2.6.12-rc2 |
145 146 147 148 149 150 151 152 153 |
*/ if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) { ret = fat_sync_inode(inode); if (ret) return ret; } else mark_inode_dirty(inode); } if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { |
85c785919 FAT: add 'errors'... |
154 |
fat_fs_error(sb, "clusters badly computed (%d != %llu)", |
c3302931d fat: i_blocks war... |
155 156 |
new_fclus, (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); |
1da177e4c Linux-2.6.12-rc2 |
157 158 159 160 161 162 |
fat_cache_inval_inode(inode); } inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9); return 0; } |
7decd1cb0 fat: Fix and clea... |
163 164 165 166 167 168 169 170 171 172 173 174 175 |
/* * The epoch of FAT timestamp is 1980. * : bits : value * date: 0 - 4: day (1 - 31) * date: 5 - 8: month (1 - 12) * date: 9 - 15: year (0 - 127) from 1980 * time: 0 - 4: sec (0 - 29) 2sec counts * time: 5 - 10: min (0 - 59) * time: 11 - 15: hour (0 - 23) */ #define SECS_PER_MIN 60 #define SECS_PER_HOUR (60 * 60) #define SECS_PER_DAY (SECS_PER_HOUR * 24) |
7decd1cb0 fat: Fix and clea... |
176 177 178 179 180 |
/* days between 1.1.70 and 1.1.80 (2 leap days) */ #define DAYS_DELTA (365 * 10 + 2) /* 120 (2100 - 1980) isn't leap year */ #define YEAR_2100 120 #define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100) |
1da177e4c Linux-2.6.12-rc2 |
181 |
/* Linear day numbers of the respective 1sts in non-leap years. */ |
f423420c2 fat: propagate 64... |
182 |
static long days_in_year[] = { |
7decd1cb0 fat: Fix and clea... |
183 184 |
/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, |
1da177e4c Linux-2.6.12-rc2 |
185 |
}; |
d9f4d9426 fat: create a fun... |
186 187 188 189 190 191 |
static inline int fat_tz_offset(struct msdos_sb_info *sbi) { return (sbi->options.tz_set ? -sbi->options.time_offset : sys_tz.tz_minuteswest) * SECS_PER_MIN; } |
7decd1cb0 fat: Fix and clea... |
192 |
/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ |
f423420c2 fat: propagate 64... |
193 |
void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec64 *ts, |
7decd1cb0 fat: Fix and clea... |
194 |
__le16 __time, __le16 __date, u8 time_cs) |
1da177e4c Linux-2.6.12-rc2 |
195 |
{ |
7decd1cb0 fat: Fix and clea... |
196 |
u16 time = le16_to_cpu(__time), date = le16_to_cpu(__date); |
f423420c2 fat: propagate 64... |
197 198 |
time64_t second; long day, leap_day, month, year; |
1da177e4c Linux-2.6.12-rc2 |
199 |
|
7decd1cb0 fat: Fix and clea... |
200 201 202 203 204 205 206 207 208 209 210 211 212 |
year = date >> 9; month = max(1, (date >> 5) & 0xf); day = max(1, date & 0x1f) - 1; leap_day = (year + 3) / 4; if (year > YEAR_2100) /* 2100 isn't leap year */ leap_day--; if (IS_LEAP_YEAR(year) && month > 2) leap_day++; second = (time & 0x1f) << 1; second += ((time >> 5) & 0x3f) * SECS_PER_MIN; second += (time >> 11) * SECS_PER_HOUR; |
f423420c2 fat: propagate 64... |
213 |
second += (time64_t)(year * 365 + leap_day |
7decd1cb0 fat: Fix and clea... |
214 215 |
+ days_in_year[month] + day + DAYS_DELTA) * SECS_PER_DAY; |
d9f4d9426 fat: create a fun... |
216 |
second += fat_tz_offset(sbi); |
7decd1cb0 fat: Fix and clea... |
217 218 219 220 221 222 223 224 |
if (time_cs) { ts->tv_sec = second + (time_cs / 100); ts->tv_nsec = (time_cs % 100) * 10000000; } else { ts->tv_sec = second; ts->tv_nsec = 0; } |
1da177e4c Linux-2.6.12-rc2 |
225 |
} |
7decd1cb0 fat: Fix and clea... |
226 |
/* Convert linear UNIX date to a FAT time/date pair. */ |
f423420c2 fat: propagate 64... |
227 |
void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts, |
7decd1cb0 fat: Fix and clea... |
228 |
__le16 *time, __le16 *date, u8 *time_cs) |
1da177e4c Linux-2.6.12-rc2 |
229 |
{ |
1d81a181e fatfs: use common... |
230 |
struct tm tm; |
d9f4d9426 fat: create a fun... |
231 |
time64_to_tm(ts->tv_sec, -fat_tz_offset(sbi), &tm); |
1da177e4c Linux-2.6.12-rc2 |
232 |
|
1d81a181e fatfs: use common... |
233 234 |
/* FAT can only support year between 1980 to 2107 */ if (tm.tm_year < 1980 - 1900) { |
7decd1cb0 fat: Fix and clea... |
235 236 237 238 239 240 |
*time = 0; *date = cpu_to_le16((0 << 9) | (1 << 5) | 1); if (time_cs) *time_cs = 0; return; } |
1d81a181e fatfs: use common... |
241 |
if (tm.tm_year > 2107 - 1900) { |
7decd1cb0 fat: Fix and clea... |
242 243 244 245 246 247 |
*time = cpu_to_le16((23 << 11) | (59 << 5) | 29); *date = cpu_to_le16((127 << 9) | (12 << 5) | 31); if (time_cs) *time_cs = 199; return; } |
7decd1cb0 fat: Fix and clea... |
248 |
|
1d81a181e fatfs: use common... |
249 250 251 252 253 254 |
/* from 1900 -> from 1980 */ tm.tm_year -= 80; /* 0~11 -> 1~12 */ tm.tm_mon++; /* 0~59 -> 0~29(2sec counts) */ tm.tm_sec >>= 1; |
1da177e4c Linux-2.6.12-rc2 |
255 |
|
1d81a181e fatfs: use common... |
256 257 |
*time = cpu_to_le16(tm.tm_hour << 11 | tm.tm_min << 5 | tm.tm_sec); *date = cpu_to_le16(tm.tm_year << 9 | tm.tm_mon << 5 | tm.tm_mday); |
7decd1cb0 fat: Fix and clea... |
258 259 260 261 |
if (time_cs) *time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000; } EXPORT_SYMBOL_GPL(fat_time_unix2fat); |
1da177e4c Linux-2.6.12-rc2 |
262 |
|
6bb885ecd fat: add function... |
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
static inline struct timespec64 fat_timespec64_trunc_2secs(struct timespec64 ts) { return (struct timespec64){ ts.tv_sec & ~1ULL, 0 }; } /* * truncate the various times with appropriate granularity: * root inode: * all times always 0 * all other inodes: * mtime - 2 seconds * ctime * msdos - 2 seconds * vfat - 10 milliseconds * atime - 24 hours (00:00:00 in local timezone) */ int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); struct timespec64 ts; if (inode->i_ino == MSDOS_ROOT_INO) return 0; if (now == NULL) { now = &ts; ts = current_time(inode); } if (flags & S_ATIME) { /* to localtime */ time64_t seconds = now->tv_sec - fat_tz_offset(sbi); s32 remainder; div_s64_rem(seconds, SECS_PER_DAY, &remainder); /* to day boundary, and back to unix time */ seconds = seconds + fat_tz_offset(sbi) - remainder; inode->i_atime = (struct timespec64){ seconds, 0 }; } if (flags & S_CTIME) { if (sbi->options.isvfat) inode->i_ctime = timespec64_trunc(*now, 10000000); else inode->i_ctime = fat_timespec64_trunc_2secs(*now); } if (flags & S_MTIME) inode->i_mtime = fat_timespec64_trunc_2secs(*now); return 0; } EXPORT_SYMBOL_GPL(fat_truncate_time); int fat_update_time(struct inode *inode, struct timespec64 *now, int flags) { int iflags = I_DIRTY_TIME; bool dirty = false; if (inode->i_ino == MSDOS_ROOT_INO) return 0; fat_truncate_time(inode, now, flags); if (flags & S_VERSION) dirty = inode_maybe_inc_iversion(inode, false); if ((flags & (S_ATIME | S_CTIME | S_MTIME)) && !(inode->i_sb->s_flags & SB_LAZYTIME)) dirty = true; if (dirty) iflags |= I_DIRTY_SYNC; __mark_inode_dirty(inode, iflags); return 0; } EXPORT_SYMBOL_GPL(fat_update_time); |
1da177e4c Linux-2.6.12-rc2 |
336 337 |
int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) { |
5b00226d4 [PATCH] fat: Repl... |
338 |
int i, err = 0; |
1da177e4c Linux-2.6.12-rc2 |
339 |
|
9cb569d60 remove SWRITE* I/... |
340 |
for (i = 0; i < nr_bhs; i++) |
2a222ca99 fs: have submit_b... |
341 |
write_dirty_buffer(bhs[i], 0); |
9cb569d60 remove SWRITE* I/... |
342 |
|
1da177e4c Linux-2.6.12-rc2 |
343 344 |
for (i = 0; i < nr_bhs; i++) { wait_on_buffer(bhs[i]); |
0edd55fae block: remove the... |
345 |
if (!err && !buffer_uptodate(bhs[i])) |
1da177e4c Linux-2.6.12-rc2 |
346 347 348 349 |
err = -EIO; } return err; } |