162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/fat/misc.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Written 1992,1993 by Werner Almesberger 662306a36Sopenharmony_ci * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 762306a36Sopenharmony_ci * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "fat.h" 1162306a36Sopenharmony_ci#include <linux/iversion.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * fat_fs_error reports a file system problem that might indicate fa data 1562306a36Sopenharmony_ci * corruption/inconsistency. Depending on 'errors' mount option the 1662306a36Sopenharmony_ci * panic() is called, or error message is printed FAT and nothing is done, 1762306a36Sopenharmony_ci * or filesystem is remounted read-only (default behavior). 1862306a36Sopenharmony_ci * In case the file system is remounted read-only, it can be made writable 1962306a36Sopenharmony_ci * again by remounting it. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_civoid __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct fat_mount_options *opts = &MSDOS_SB(sb)->options; 2462306a36Sopenharmony_ci va_list args; 2562306a36Sopenharmony_ci struct va_format vaf; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci if (report) { 2862306a36Sopenharmony_ci va_start(args, fmt); 2962306a36Sopenharmony_ci vaf.fmt = fmt; 3062306a36Sopenharmony_ci vaf.va = &args; 3162306a36Sopenharmony_ci fat_msg(sb, KERN_ERR, "error, %pV", &vaf); 3262306a36Sopenharmony_ci va_end(args); 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (opts->errors == FAT_ERRORS_PANIC) 3662306a36Sopenharmony_ci panic("FAT-fs (%s): fs panic from previous error\n", sb->s_id); 3762306a36Sopenharmony_ci else if (opts->errors == FAT_ERRORS_RO && !sb_rdonly(sb)) { 3862306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 3962306a36Sopenharmony_ci fat_msg(sb, KERN_ERR, "Filesystem has been set read-only"); 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__fat_fs_error); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/** 4562306a36Sopenharmony_ci * _fat_msg() - Print a preformatted FAT message based on a superblock. 4662306a36Sopenharmony_ci * @sb: A pointer to a &struct super_block 4762306a36Sopenharmony_ci * @level: A Kernel printk level constant 4862306a36Sopenharmony_ci * @fmt: The printf-style format string to print. 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * Everything that is not fat_fs_error() should be fat_msg(). 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * fat_msg() wraps _fat_msg() for printk indexing. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_civoid _fat_msg(struct super_block *sb, const char *level, const char *fmt, ...) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct va_format vaf; 5762306a36Sopenharmony_ci va_list args; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci va_start(args, fmt); 6062306a36Sopenharmony_ci vaf.fmt = fmt; 6162306a36Sopenharmony_ci vaf.va = &args; 6262306a36Sopenharmony_ci _printk(FAT_PRINTK_PREFIX "%pV\n", level, sb->s_id, &vaf); 6362306a36Sopenharmony_ci va_end(args); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* Flushes the number of free clusters on FAT32 */ 6762306a36Sopenharmony_ci/* XXX: Need to write one per FSINFO block. Currently only writes 1 */ 6862306a36Sopenharmony_ciint fat_clusters_flush(struct super_block *sb) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct msdos_sb_info *sbi = MSDOS_SB(sb); 7162306a36Sopenharmony_ci struct buffer_head *bh; 7262306a36Sopenharmony_ci struct fat_boot_fsinfo *fsinfo; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (!is_fat32(sbi)) 7562306a36Sopenharmony_ci return 0; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci bh = sb_bread(sb, sbi->fsinfo_sector); 7862306a36Sopenharmony_ci if (bh == NULL) { 7962306a36Sopenharmony_ci fat_msg(sb, KERN_ERR, "bread failed in fat_clusters_flush"); 8062306a36Sopenharmony_ci return -EIO; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci fsinfo = (struct fat_boot_fsinfo *)bh->b_data; 8462306a36Sopenharmony_ci /* Sanity check */ 8562306a36Sopenharmony_ci if (!IS_FSINFO(fsinfo)) { 8662306a36Sopenharmony_ci fat_msg(sb, KERN_ERR, "Invalid FSINFO signature: " 8762306a36Sopenharmony_ci "0x%08x, 0x%08x (sector = %lu)", 8862306a36Sopenharmony_ci le32_to_cpu(fsinfo->signature1), 8962306a36Sopenharmony_ci le32_to_cpu(fsinfo->signature2), 9062306a36Sopenharmony_ci sbi->fsinfo_sector); 9162306a36Sopenharmony_ci } else { 9262306a36Sopenharmony_ci if (sbi->free_clusters != -1) 9362306a36Sopenharmony_ci fsinfo->free_clusters = cpu_to_le32(sbi->free_clusters); 9462306a36Sopenharmony_ci if (sbi->prev_free != -1) 9562306a36Sopenharmony_ci fsinfo->next_cluster = cpu_to_le32(sbi->prev_free); 9662306a36Sopenharmony_ci mark_buffer_dirty(bh); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci brelse(bh); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * fat_chain_add() adds a new cluster to the chain of clusters represented 10562306a36Sopenharmony_ci * by inode. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ciint fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 11062306a36Sopenharmony_ci struct msdos_sb_info *sbi = MSDOS_SB(sb); 11162306a36Sopenharmony_ci int ret, new_fclus, last; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* 11462306a36Sopenharmony_ci * We must locate the last cluster of the file to add this new 11562306a36Sopenharmony_ci * one (new_dclus) to the end of the link list (the FAT). 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ci last = new_fclus = 0; 11862306a36Sopenharmony_ci if (MSDOS_I(inode)->i_start) { 11962306a36Sopenharmony_ci int fclus, dclus; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus); 12262306a36Sopenharmony_ci if (ret < 0) 12362306a36Sopenharmony_ci return ret; 12462306a36Sopenharmony_ci new_fclus = fclus + 1; 12562306a36Sopenharmony_ci last = dclus; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* add new one to the last of the cluster chain */ 12962306a36Sopenharmony_ci if (last) { 13062306a36Sopenharmony_ci struct fat_entry fatent; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci fatent_init(&fatent); 13362306a36Sopenharmony_ci ret = fat_ent_read(inode, &fatent, last); 13462306a36Sopenharmony_ci if (ret >= 0) { 13562306a36Sopenharmony_ci int wait = inode_needs_sync(inode); 13662306a36Sopenharmony_ci ret = fat_ent_write(inode, &fatent, new_dclus, wait); 13762306a36Sopenharmony_ci fatent_brelse(&fatent); 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci if (ret < 0) 14062306a36Sopenharmony_ci return ret; 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * FIXME:Although we can add this cache, fat_cache_add() is 14362306a36Sopenharmony_ci * assuming to be called after linear search with fat_cache_id. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci// fat_cache_add(inode, new_fclus, new_dclus); 14662306a36Sopenharmony_ci } else { 14762306a36Sopenharmony_ci MSDOS_I(inode)->i_start = new_dclus; 14862306a36Sopenharmony_ci MSDOS_I(inode)->i_logstart = new_dclus; 14962306a36Sopenharmony_ci /* 15062306a36Sopenharmony_ci * Since generic_write_sync() synchronizes regular files later, 15162306a36Sopenharmony_ci * we sync here only directories. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) { 15462306a36Sopenharmony_ci ret = fat_sync_inode(inode); 15562306a36Sopenharmony_ci if (ret) 15662306a36Sopenharmony_ci return ret; 15762306a36Sopenharmony_ci } else 15862306a36Sopenharmony_ci mark_inode_dirty(inode); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { 16162306a36Sopenharmony_ci fat_fs_error(sb, "clusters badly computed (%d != %llu)", 16262306a36Sopenharmony_ci new_fclus, 16362306a36Sopenharmony_ci (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); 16462306a36Sopenharmony_ci fat_cache_inval_inode(inode); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* 17262306a36Sopenharmony_ci * The epoch of FAT timestamp is 1980. 17362306a36Sopenharmony_ci * : bits : value 17462306a36Sopenharmony_ci * date: 0 - 4: day (1 - 31) 17562306a36Sopenharmony_ci * date: 5 - 8: month (1 - 12) 17662306a36Sopenharmony_ci * date: 9 - 15: year (0 - 127) from 1980 17762306a36Sopenharmony_ci * time: 0 - 4: sec (0 - 29) 2sec counts 17862306a36Sopenharmony_ci * time: 5 - 10: min (0 - 59) 17962306a36Sopenharmony_ci * time: 11 - 15: hour (0 - 23) 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci#define SECS_PER_MIN 60 18262306a36Sopenharmony_ci#define SECS_PER_HOUR (60 * 60) 18362306a36Sopenharmony_ci#define SECS_PER_DAY (SECS_PER_HOUR * 24) 18462306a36Sopenharmony_ci/* days between 1.1.70 and 1.1.80 (2 leap days) */ 18562306a36Sopenharmony_ci#define DAYS_DELTA (365 * 10 + 2) 18662306a36Sopenharmony_ci/* 120 (2100 - 1980) isn't leap year */ 18762306a36Sopenharmony_ci#define YEAR_2100 120 18862306a36Sopenharmony_ci#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100) 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* Linear day numbers of the respective 1sts in non-leap years. */ 19162306a36Sopenharmony_cistatic long days_in_year[] = { 19262306a36Sopenharmony_ci /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ 19362306a36Sopenharmony_ci 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic inline int fat_tz_offset(const struct msdos_sb_info *sbi) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci return (sbi->options.tz_set ? 19962306a36Sopenharmony_ci -sbi->options.time_offset : 20062306a36Sopenharmony_ci sys_tz.tz_minuteswest) * SECS_PER_MIN; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ 20462306a36Sopenharmony_civoid fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec64 *ts, 20562306a36Sopenharmony_ci __le16 __time, __le16 __date, u8 time_cs) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci u16 time = le16_to_cpu(__time), date = le16_to_cpu(__date); 20862306a36Sopenharmony_ci time64_t second; 20962306a36Sopenharmony_ci long day, leap_day, month, year; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci year = date >> 9; 21262306a36Sopenharmony_ci month = max(1, (date >> 5) & 0xf); 21362306a36Sopenharmony_ci day = max(1, date & 0x1f) - 1; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci leap_day = (year + 3) / 4; 21662306a36Sopenharmony_ci if (year > YEAR_2100) /* 2100 isn't leap year */ 21762306a36Sopenharmony_ci leap_day--; 21862306a36Sopenharmony_ci if (IS_LEAP_YEAR(year) && month > 2) 21962306a36Sopenharmony_ci leap_day++; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci second = (time & 0x1f) << 1; 22262306a36Sopenharmony_ci second += ((time >> 5) & 0x3f) * SECS_PER_MIN; 22362306a36Sopenharmony_ci second += (time >> 11) * SECS_PER_HOUR; 22462306a36Sopenharmony_ci second += (time64_t)(year * 365 + leap_day 22562306a36Sopenharmony_ci + days_in_year[month] + day 22662306a36Sopenharmony_ci + DAYS_DELTA) * SECS_PER_DAY; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci second += fat_tz_offset(sbi); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (time_cs) { 23162306a36Sopenharmony_ci ts->tv_sec = second + (time_cs / 100); 23262306a36Sopenharmony_ci ts->tv_nsec = (time_cs % 100) * 10000000; 23362306a36Sopenharmony_ci } else { 23462306a36Sopenharmony_ci ts->tv_sec = second; 23562306a36Sopenharmony_ci ts->tv_nsec = 0; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* Export fat_time_fat2unix() for the fat_test KUnit tests. */ 24062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fat_time_fat2unix); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* Convert linear UNIX date to a FAT time/date pair. */ 24362306a36Sopenharmony_civoid fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts, 24462306a36Sopenharmony_ci __le16 *time, __le16 *date, u8 *time_cs) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct tm tm; 24762306a36Sopenharmony_ci time64_to_tm(ts->tv_sec, -fat_tz_offset(sbi), &tm); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* FAT can only support year between 1980 to 2107 */ 25062306a36Sopenharmony_ci if (tm.tm_year < 1980 - 1900) { 25162306a36Sopenharmony_ci *time = 0; 25262306a36Sopenharmony_ci *date = cpu_to_le16((0 << 9) | (1 << 5) | 1); 25362306a36Sopenharmony_ci if (time_cs) 25462306a36Sopenharmony_ci *time_cs = 0; 25562306a36Sopenharmony_ci return; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci if (tm.tm_year > 2107 - 1900) { 25862306a36Sopenharmony_ci *time = cpu_to_le16((23 << 11) | (59 << 5) | 29); 25962306a36Sopenharmony_ci *date = cpu_to_le16((127 << 9) | (12 << 5) | 31); 26062306a36Sopenharmony_ci if (time_cs) 26162306a36Sopenharmony_ci *time_cs = 199; 26262306a36Sopenharmony_ci return; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* from 1900 -> from 1980 */ 26662306a36Sopenharmony_ci tm.tm_year -= 80; 26762306a36Sopenharmony_ci /* 0~11 -> 1~12 */ 26862306a36Sopenharmony_ci tm.tm_mon++; 26962306a36Sopenharmony_ci /* 0~59 -> 0~29(2sec counts) */ 27062306a36Sopenharmony_ci tm.tm_sec >>= 1; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci *time = cpu_to_le16(tm.tm_hour << 11 | tm.tm_min << 5 | tm.tm_sec); 27362306a36Sopenharmony_ci *date = cpu_to_le16(tm.tm_year << 9 | tm.tm_mon << 5 | tm.tm_mday); 27462306a36Sopenharmony_ci if (time_cs) 27562306a36Sopenharmony_ci *time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fat_time_unix2fat); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic inline struct timespec64 fat_timespec64_trunc_2secs(struct timespec64 ts) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci return (struct timespec64){ ts.tv_sec & ~1ULL, 0 }; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/* 28562306a36Sopenharmony_ci * truncate atime to 24 hour granularity (00:00:00 in local timezone) 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_cistruct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi, 28862306a36Sopenharmony_ci const struct timespec64 *ts) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci /* to localtime */ 29162306a36Sopenharmony_ci time64_t seconds = ts->tv_sec - fat_tz_offset(sbi); 29262306a36Sopenharmony_ci s32 remainder; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci div_s64_rem(seconds, SECS_PER_DAY, &remainder); 29562306a36Sopenharmony_ci /* to day boundary, and back to unix time */ 29662306a36Sopenharmony_ci seconds = seconds + fat_tz_offset(sbi) - remainder; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return (struct timespec64){ seconds, 0 }; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* 30262306a36Sopenharmony_ci * truncate mtime to 2 second granularity 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_cistruct timespec64 fat_truncate_mtime(const struct msdos_sb_info *sbi, 30562306a36Sopenharmony_ci const struct timespec64 *ts) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci return fat_timespec64_trunc_2secs(*ts); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/* 31162306a36Sopenharmony_ci * truncate the various times with appropriate granularity: 31262306a36Sopenharmony_ci * all times in root node are always 0 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ciint fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); 31762306a36Sopenharmony_ci struct timespec64 ts; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (inode->i_ino == MSDOS_ROOT_INO) 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (now == NULL) { 32362306a36Sopenharmony_ci now = &ts; 32462306a36Sopenharmony_ci ts = current_time(inode); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (flags & S_ATIME) 32862306a36Sopenharmony_ci inode->i_atime = fat_truncate_atime(sbi, now); 32962306a36Sopenharmony_ci /* 33062306a36Sopenharmony_ci * ctime and mtime share the same on-disk field, and should be 33162306a36Sopenharmony_ci * identical in memory. all mtime updates will be applied to ctime, 33262306a36Sopenharmony_ci * but ctime updates are ignored. 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ci if (flags & S_MTIME) 33562306a36Sopenharmony_ci inode->i_mtime = inode_set_ctime_to_ts(inode, 33662306a36Sopenharmony_ci fat_truncate_mtime(sbi, now)); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fat_truncate_time); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ciint fat_update_time(struct inode *inode, int flags) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci int dirty_flags = 0; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (inode->i_ino == MSDOS_ROOT_INO) 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (flags & (S_ATIME | S_CTIME | S_MTIME)) { 35062306a36Sopenharmony_ci fat_truncate_time(inode, NULL, flags); 35162306a36Sopenharmony_ci if (inode->i_sb->s_flags & SB_LAZYTIME) 35262306a36Sopenharmony_ci dirty_flags |= I_DIRTY_TIME; 35362306a36Sopenharmony_ci else 35462306a36Sopenharmony_ci dirty_flags |= I_DIRTY_SYNC; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci __mark_inode_dirty(inode, dirty_flags); 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fat_update_time); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ciint fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci int i, err = 0; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci for (i = 0; i < nr_bhs; i++) 36762306a36Sopenharmony_ci write_dirty_buffer(bhs[i], 0); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci for (i = 0; i < nr_bhs; i++) { 37062306a36Sopenharmony_ci wait_on_buffer(bhs[i]); 37162306a36Sopenharmony_ci if (!err && !buffer_uptodate(bhs[i])) 37262306a36Sopenharmony_ci err = -EIO; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci return err; 37562306a36Sopenharmony_ci} 376