diff --git a/fs/sdfat/amap_smart.c b/fs/sdfat/amap_smart.c index b556f868d76..c9e6f37feb5 100644 --- a/fs/sdfat/amap_smart.c +++ b/fs/sdfat/amap_smart.c @@ -1311,4 +1311,3 @@ u32 amap_get_au_stat(struct super_block *sb, s32 mode) return 0; } - diff --git a/fs/sdfat/api.c b/fs/sdfat/api.c index 02e0939efee..45b0c4106bd 100644 --- a/fs/sdfat/api.c +++ b/fs/sdfat/api.c @@ -478,6 +478,13 @@ void fsapi_invalidate_extent(struct inode *inode) } EXPORT_SYMBOL(fsapi_invalidate_extent); +/* check device is ejected */ +s32 fsapi_check_bdi_valid(struct super_block *sb) +{ + return fscore_check_bdi_valid(sb); +} +EXPORT_SYMBOL(fsapi_check_bdi_valid); + #ifdef CONFIG_SDFAT_DFR diff --git a/fs/sdfat/api.h b/fs/sdfat/api.h index 0bd05d700c8..df6a32fb8b3 100644 --- a/fs/sdfat/api.h +++ b/fs/sdfat/api.h @@ -355,6 +355,9 @@ u32 fsapi_get_au_stat(struct super_block *sb, s32 mode); /* extent cache functions */ void fsapi_invalidate_extent(struct inode *inode); +/* bdev management */ +s32 fsapi_check_bdi_valid(struct super_block *sb); + #ifdef CONFIG_SDFAT_DFR /*----------------------------------------------------------------------*/ /* Defragmentation related */ diff --git a/fs/sdfat/cache.c b/fs/sdfat/cache.c index f0170c56020..8286953fc24 100644 --- a/fs/sdfat/cache.c +++ b/fs/sdfat/cache.c @@ -838,5 +838,4 @@ static void __dcache_remove_hash(cache_ent_t *bp) __remove_from_hash(bp); } - /* end of cache.c */ diff --git a/fs/sdfat/core.c b/fs/sdfat/core.c index 357eb0d54f1..618c9e7f72d 100644 --- a/fs/sdfat/core.c +++ b/fs/sdfat/core.c @@ -1621,6 +1621,12 @@ s32 fscore_shutdown(void) return 0; } +/* check device is ejected */ +s32 fscore_check_bdi_valid(struct super_block *sb) +{ + return bdev_check_bdi_valid(sb); +} + static bool is_exfat(pbr_t *pbr) { int i = 53; @@ -1703,6 +1709,7 @@ s32 fscore_mount(struct super_block *sb) pbr_t *p_pbr; struct buffer_head *tmp_bh = NULL; struct gendisk *disk = sb->s_bdev->bd_disk; + struct hd_struct *part = sb->s_bdev->bd_part; struct sdfat_mount_options *opts = &(SDFAT_SB(sb)->options); FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); @@ -1802,9 +1809,11 @@ free_bh: "misaligned" : "aligned"); sdfat_log_msg(sb, KERN_INFO, - "detected volume size : %llu MB (disk_size : %llu MB)", - fsi->num_sectors >> 11, - disk ? (u64)((disk->part0.nr_sects) >> 11) : 0); + "detected volume size : %llu KB (disk : %llu KB, " + "part : %llu KB)", + (fsi->num_sectors * (sb->s_blocksize >> SECTOR_SIZE_BITS)) >> 1, + disk ? (u64)((disk->part0.nr_sects) >> 1) : 0, + part ? (u64)((part->nr_sects) >> 1) : 0); ret = load_upcase_table(sb); if (ret) { diff --git a/fs/sdfat/core.h b/fs/sdfat/core.h index 00ea2c5e260..1f8ed5a28ef 100644 --- a/fs/sdfat/core.h +++ b/fs/sdfat/core.h @@ -70,6 +70,9 @@ typedef struct { s32 fscore_init(void); s32 fscore_shutdown(void); +/* bdev management */ +s32 fscore_check_bdi_valid(struct super_block *sb); + /* chain management */ s32 chain_cont_cluster(struct super_block *sb, u32 chain, u32 len); diff --git a/fs/sdfat/core_exfat.c b/fs/sdfat/core_exfat.c index 08c45b09bb7..219acf0e251 100644 --- a/fs/sdfat/core_exfat.c +++ b/fs/sdfat/core_exfat.c @@ -733,8 +733,8 @@ static s32 __extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s static s32 exfat_find_dir_entry(struct super_block *sb, FILE_ID_T *fid, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *unused, u32 type) { - s32 i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len; - s32 order, step, name_len; + s32 i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len = 0; + s32 order, step, name_len = 0; s32 dentries_per_clu, num_empty = 0; u32 entry_type; u16 entry_uniname[16], *uniname = NULL, unichar; diff --git a/fs/sdfat/core_fat.c b/fs/sdfat/core_fat.c index 493e5cb7e71..d25ec32d3b3 100644 --- a/fs/sdfat/core_fat.c +++ b/fs/sdfat/core_fat.c @@ -1323,8 +1323,9 @@ static sector_t __calc_hidden_sect(struct super_block *sb) hidden = bdev->bd_part->start_sect; /* a disk device, not a partition */ if (!hidden) { - ASSERT(bdev == bdev->bd_contains); - ASSERT(!bdev->bd_part->partno); + if (bdev != bdev->bd_contains) + sdfat_log_msg(sb, KERN_WARNING, + "hidden(0), but disk has a partition table"); goto out; } @@ -1334,8 +1335,8 @@ static sector_t __calc_hidden_sect(struct super_block *sb) } out: - sdfat_log_msg(sb, KERN_INFO, "start_sect of partition : %lld", - (s64)hidden); + sdfat_log_msg(sb, KERN_INFO, "start_sect of part(%d) : %lld", + bdev ? bdev->bd_part->partno : -1, (s64)hidden); return hidden; } diff --git a/fs/sdfat/dfr.c b/fs/sdfat/dfr.c index 2853fe42519..6805e977771 100644 --- a/fs/sdfat/dfr.c +++ b/fs/sdfat/dfr.c @@ -1368,5 +1368,4 @@ defrag_spo_test( } #endif /* CONFIG_SDFAT_DFR_DEBUG */ - #endif /* CONFIG_SDFAT_DFR */ diff --git a/fs/sdfat/dfr.h b/fs/sdfat/dfr.h index da98605020d..f33d1cef655 100644 --- a/fs/sdfat/dfr.h +++ b/fs/sdfat/dfr.h @@ -258,4 +258,3 @@ void defrag_spo_test(struct super_block *sb, int flag, const char *caller); #endif /* CONFIG_SDFAT_DFR */ #endif /* _SDFAT_DEFRAG_H */ - diff --git a/fs/sdfat/misc.c b/fs/sdfat/misc.c index b9592ef4ca9..55b175d95f7 100644 --- a/fs/sdfat/misc.c +++ b/fs/sdfat/misc.c @@ -43,11 +43,23 @@ #include "version.h" #ifdef CONFIG_SDFAT_SUPPORT_STLOG +#ifdef CONFIG_PROC_FSLOG +#include +#else #include +#endif #else #define ST_LOG(fmt, ...) #endif +/************************************************************************* + * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY + *************************************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) +#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC) +#endif + + /* * sdfat_fs_error reports a file system problem that might indicate fa data * corruption/inconsistency. Depending on 'errors' mount option the @@ -84,6 +96,7 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); } else if (opts->errors == SDFAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) { sb->s_flags |= MS_RDONLY; + sdfat_statistics_set_mnt_ro(); pr_err("[SDFAT](%s[%d:%d]): Filesystem has been set " "read-only\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); #ifdef CONFIG_SDFAT_SUPPORT_STLOG @@ -253,15 +266,9 @@ void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, struct timespec *ts, TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tp) { - struct timespec ts; + struct timespec ts = CURRENT_TIME_SEC; DATE_TIME_T dt; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) - ts = CURRENT_TIME_SEC; -#else - ktime_get_real_ts(&ts); -#endif - sdfat_time_unix2fat(sbi, &ts, &dt); tp->year = dt.Year; diff --git a/fs/sdfat/mpage.c b/fs/sdfat/mpage.c index b3985825815..b57b798cf08 100644 --- a/fs/sdfat/mpage.c +++ b/fs/sdfat/mpage.c @@ -78,6 +78,27 @@ static void __mpage_write_end_io(struct bio *bio, int err); /************************************************************************* * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + /* EMPTY */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) */ +static inline void bio_set_dev(struct bio *bio, struct block_device *bdev) +{ + bio->bi_bdev = bdev; +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) +static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_t block) +{ + clean_bdev_aliases(bdev, block, 1); +} +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) */ +static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_t block) +{ + unmap_underlying_metadata(bdev, block); +} +#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) static inline void __sdfat_submit_bio_write2(int flags, struct bio *bio) { @@ -91,24 +112,6 @@ static inline void __sdfat_submit_bio_write2(int flags, struct bio *bio) } #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) -static void mpage_write_end_io(struct bio *bio) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - __mpage_write_end_io(bio, bio->bi_status); -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */ - __mpage_write_end_io(bio, bio->bi_error); -#endif -} -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) */ -static void mpage_write_end_io(struct bio *bio, int err) -{ - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) - err = 0; - __mpage_write_end_io(bio, err); -} -#endif - #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) static inline int bio_get_nr_vecs(struct block_device *bdev) { @@ -160,6 +163,28 @@ static inline void __sdfat_set_bio_size(struct bio *bio, unsigned int size) } #endif +/************************************************************************* + * MORE FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY + *************************************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) +static void mpage_write_end_io(struct bio *bio) +{ + __mpage_write_end_io(bio, blk_status_to_errno(bio->bi_status)); +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) +static void mpage_write_end_io(struct bio *bio) +{ + __mpage_write_end_io(bio, bio->bi_error); +} +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) */ +static void mpage_write_end_io(struct bio *bio, int err) +{ + if (test_bit(BIO_UPTODATE, &bio->bi_flags)) + err = 0; + __mpage_write_end_io(bio, err); +} +#endif + /* __check_dfr_on() and __dfr_writepage_end_io() functions * are copied from sdfat.c * Each function should be same perfectly @@ -281,11 +306,7 @@ mpage_alloc(struct block_device *bdev, } if (bio) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) bio_set_dev(bio, bdev); -#else - bio->bi_bdev = bdev; -#endif __sdfat_set_bio_sector(bio, first_sector); } return bio; @@ -369,11 +390,7 @@ static int sdfat_mpage_writepage(struct page *page, if (buffer_new(bh)) { clear_buffer_new(bh); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) - clean_bdev_bh_alias(bh); -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) */ - unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); -#endif + __sdfat_clean_bdev_aliases(bh->b_bdev, bh->b_blocknr); } } @@ -423,12 +440,7 @@ static int sdfat_mpage_writepage(struct page *page, goto confused; if (buffer_new(&map_bh)) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) - clean_bdev_bh_alias(&map_bh); -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) */ - unmap_underlying_metadata(map_bh.b_bdev, - map_bh.b_blocknr); -#endif + __sdfat_clean_bdev_aliases(map_bh.b_bdev, map_bh.b_blocknr); if (buffer_boundary(&map_bh)) { boundary_block = map_bh.b_blocknr; boundary_bdev = map_bh.b_bdev; diff --git a/fs/sdfat/sdfat.c b/fs/sdfat/sdfat.c index d83bf369b4d..e6c162a9f74 100644 --- a/fs/sdfat/sdfat.c +++ b/fs/sdfat/sdfat.c @@ -68,9 +68,6 @@ /* skip iterating emit_dots when dir is empty */ #define ITER_POS_FILLED_DOTS (2) -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) -#define current_time(x) (CURRENT_TIME_SEC) -#endif /* type index declare at sdfat.h */ const char *FS_TYPE_STR[] = { "auto", @@ -112,6 +109,7 @@ static void sdfat_free_namebuf(DENTRY_NAMEBUF_T *nb); /************************************************************************* * INNER FUNCTIONS FOR FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ +static int __sdfat_getattr(struct inode *inode, struct kstat *stat); static void __sdfat_writepage_end_io(struct bio *bio, int err); static inline void __lock_super(struct super_block *sb); static inline void __unlock_super(struct super_block *sb); @@ -140,6 +138,51 @@ static int __sdfat_cmpi(const struct dentry *dentry, unsigned int len, /************************************************************************* * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + /* EMPTY */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) */ +static inline void bio_set_dev(struct bio *bio, struct block_device *bdev) +{ + bio->bi_bdev = bdev; +} +#endif + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) +#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +static int sdfat_getattr(const struct path *path, struct kstat *stat, + u32 request_mask, unsigned int query_flags) +{ + struct inode *inode = d_backing_inode(path->dentry); + + return __sdfat_getattr(inode, stat); +} +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) */ +static int sdfat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + + return __sdfat_getattr(inode, stat); +} +#endif + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) +static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_t block) +{ + clean_bdev_aliases(bdev, block, 1); +} +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) */ +static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_t block) +{ + unmap_underlying_metadata(bdev, block); +} +#endif + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) static int sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, @@ -219,25 +262,6 @@ static inline void inode_unlock(struct inode *inode) #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) -static void sdfat_writepage_end_io(struct bio *bio) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - __sdfat_writepage_end_io(bio, bio->bi_status); -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */ - __sdfat_writepage_end_io(bio, bio->bi_error); -#endif -} -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) */ -static void sdfat_writepage_end_io(struct bio *bio, int err) -{ - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) - err = 0; - __sdfat_writepage_end_io(bio, err); -} -#endif - - #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) static inline int sdfat_remount_syncfs(struct super_block *sb) { @@ -870,6 +894,26 @@ static int sdfat_file_fsync(struct file *filp, int datasync) /************************************************************************* * MORE FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY *************************************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) +static void sdfat_writepage_end_io(struct bio *bio) +{ + __sdfat_writepage_end_io(bio, blk_status_to_errno(bio->bi_status)); +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) +static void sdfat_writepage_end_io(struct bio *bio) +{ + __sdfat_writepage_end_io(bio, bio->bi_error); +} +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) */ +static void sdfat_writepage_end_io(struct bio *bio, int err) +{ + if (test_bit(BIO_UPTODATE, &bio->bi_flags)) + err = 0; + __sdfat_writepage_end_io(bio, err); +} +#endif + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) static int sdfat_cmp(const struct dentry *dentry, unsigned int len, const char *str, const struct qstr *name) @@ -910,30 +954,6 @@ static int sdfat_cmpi(const struct dentry *parent, const struct inode *pinode, } #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) -static const char *sdfat_follow_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) -{ - struct sdfat_inode_info *ei = SDFAT_I(inode); - - return (char *)(ei->target); -} -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) -static const char *sdfat_follow_link(struct dentry *dentry, void **cookie) -{ - struct sdfat_inode_info *ei = SDFAT_I(dentry->d_inode); - - return *cookie = (char *)(ei->target); -} -#else -static void *sdfat_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - struct sdfat_inode_info *ei = SDFAT_I(dentry->d_inode); - - nd_set_link(nd, (char *)(ei->target)); - return NULL; -} -#endif - #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) static ssize_t sdfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) @@ -1041,6 +1061,31 @@ static inline ssize_t __sdfat_blkdev_direct_IO(int rw, struct kiocb *iocb, #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) +static const char *sdfat_follow_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) +{ + struct sdfat_inode_info *ei = SDFAT_I(inode); + + return (char *)(ei->target); +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) +static const char *sdfat_follow_link(struct dentry *dentry, void **cookie) +{ + struct sdfat_inode_info *ei = SDFAT_I(dentry->d_inode); + + return *cookie = (char *)(ei->target); +} +#else +static void *sdfat_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct sdfat_inode_info *ei = SDFAT_I(dentry->d_inode); + + nd_set_link(nd, (char *)(ei->target)); + return NULL; +} +#endif + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) static int sdfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) @@ -2221,6 +2266,16 @@ static long sdfat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned lo return sdfat_dbg_ioctl(inode, filp, cmd, arg); } +static int __sdfat_getattr(struct inode *inode, struct kstat *stat) +{ + TMSG("%s entered\n", __func__); + + generic_fillattr(inode, stat); + stat->blksize = SDFAT_SB(inode->i_sb)->fsi.cluster_size; + + TMSG("%s exited\n", __func__); + return 0; +} static void __sdfat_writepage_end_io(struct bio *bio, int err) { @@ -2313,6 +2368,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; struct inode *inode; + struct timespec ts; FILE_ID_T fid; loff_t i_pos; int err; @@ -2321,6 +2377,8 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry) TMSG("%s entered\n", __func__); + ts = CURRENT_TIME_SEC; + err = fsapi_create(dir, (u8 *) dentry->d_name.name, FM_REGULAR, &fid); if (err) goto out; @@ -2328,7 +2386,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry) __lock_d_revalidate(dentry); dir->i_version++; - dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + dir->i_ctime = dir->i_mtime = dir->i_atime = ts; if (IS_DIRSYNC(dir)) (void) sdfat_sync_inode(dir); else @@ -2341,7 +2399,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry) goto out; } inode->i_version++; - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = ts; /* timestamp is already written, so mark_inode_dirty() is unneeded. */ d_instantiate(dentry, inode); @@ -2475,12 +2533,15 @@ static int sdfat_unlink(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct super_block *sb = dir->i_sb; + struct timespec ts; int err; __lock_super(sb); TMSG("%s entered\n", __func__); + ts = CURRENT_TIME_SEC; + SDFAT_I(inode)->fid.size = i_size_read(inode); __cancel_dfr_work(inode, 0, SDFAT_I(inode)->fid.size, __func__); @@ -2492,14 +2553,14 @@ static int sdfat_unlink(struct inode *dir, struct dentry *dentry) __lock_d_revalidate(dentry); dir->i_version++; - dir->i_mtime = dir->i_atime = current_time(dir); + dir->i_mtime = dir->i_atime = ts; if (IS_DIRSYNC(dir)) (void) sdfat_sync_inode(dir); else mark_inode_dirty(dir); clear_nlink(inode); - inode->i_mtime = inode->i_atime = current_time(inode); + inode->i_mtime = inode->i_atime = ts; sdfat_detach(inode); dentry->d_time = dir->i_version; out: @@ -2513,6 +2574,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t { struct super_block *sb = dir->i_sb; struct inode *inode; + struct timespec ts; FILE_ID_T fid; loff_t i_pos; int err; @@ -2527,6 +2589,8 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t TMSG("%s entered\n", __func__); + ts = CURRENT_TIME_SEC; + err = fsapi_create(dir, (u8 *) dentry->d_name.name, FM_SYMLINK, &fid); if (err) goto out; @@ -2541,7 +2605,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t __lock_d_revalidate(dentry); dir->i_version++; - dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + dir->i_ctime = dir->i_mtime = dir->i_atime = ts; if (IS_DIRSYNC(dir)) (void) sdfat_sync_inode(dir); else @@ -2554,7 +2618,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t goto out; } inode->i_version++; - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = ts; /* timestamp is already written, so mark_inode_dirty() is unneeded. */ SDFAT_I(inode)->target = kmalloc((len+1), GFP_KERNEL); @@ -2577,6 +2641,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; struct inode *inode; + struct timespec ts; FILE_ID_T fid; loff_t i_pos; int err; @@ -2585,6 +2650,8 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry) TMSG("%s entered\n", __func__); + ts = CURRENT_TIME_SEC; + err = fsapi_mkdir(dir, (u8 *) dentry->d_name.name, &fid); if (err) goto out; @@ -2592,7 +2659,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry) __lock_d_revalidate(dentry); dir->i_version++; - dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + dir->i_ctime = dir->i_mtime = dir->i_atime = ts; if (IS_DIRSYNC(dir)) (void) sdfat_sync_inode(dir); else @@ -2606,7 +2673,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry) goto out; } inode->i_version++; - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = ts; /* timestamp is already written, so mark_inode_dirty() is unneeded. */ d_instantiate(dentry, inode); @@ -2625,12 +2692,15 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct super_block *sb = dir->i_sb; + struct timespec ts; int err; __lock_super(sb); TMSG("%s entered\n", __func__); + ts = CURRENT_TIME_SEC; + SDFAT_I(inode)->fid.size = i_size_read(inode); err = fsapi_rmdir(dir, &(SDFAT_I(inode)->fid)); @@ -2640,7 +2710,7 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry) __lock_d_revalidate(dentry); dir->i_version++; - dir->i_mtime = dir->i_atime = current_time(dir); + dir->i_mtime = dir->i_atime = ts; if (IS_DIRSYNC(dir)) (void) sdfat_sync_inode(dir); else @@ -2648,7 +2718,7 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry) drop_nlink(dir); clear_nlink(inode); - inode->i_mtime = inode->i_atime = current_time(inode); + inode->i_mtime = inode->i_atime = ts; sdfat_detach(inode); dentry->d_time = dir->i_version; out: @@ -2663,6 +2733,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, { struct inode *old_inode, *new_inode; struct super_block *sb = old_dir->i_sb; + struct timespec ts; loff_t i_pos; int err; @@ -2673,6 +2744,8 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, old_inode = old_dentry->d_inode; new_inode = new_dentry->d_inode; + ts = CURRENT_TIME_SEC; + SDFAT_I(old_inode)->fid.size = i_size_read(old_inode); __cancel_dfr_work(old_inode, 0, 1, __func__); @@ -2685,7 +2758,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, __lock_d_revalidate(new_dentry); new_dir->i_version++; - new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = current_time(new_dir); + new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = ts; if (IS_DIRSYNC(new_dir)) (void) sdfat_sync_inode(new_dir); else @@ -2706,7 +2779,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, } old_dir->i_version++; - old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); + old_dir->i_ctime = old_dir->i_mtime = ts; if (IS_DIRSYNC(old_dir)) (void) sdfat_sync_inode(old_dir); else @@ -2725,7 +2798,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry, __func__); WARN_ON(new_inode->i_nlink == 0); } - new_inode->i_ctime = current_time(new_inode); + new_inode->i_ctime = ts; #if 0 (void) sdfat_sync_inode(new_inode); #endif @@ -2749,7 +2822,7 @@ static int sdfat_cont_expand(struct inode *inode, loff_t size) if (err) return err; - inode->i_ctime = inode->i_mtime = current_time(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(inode); if (!IS_SYNC(inode)) @@ -2882,25 +2955,6 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr) return error; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) -static int sdfat_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int flags) -{ - struct inode *inode = path->dentry->d_inode; -#else -static int sdfat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) -{ - struct inode *inode = dentry->d_inode; -#endif - - TMSG("%s entered\n", __func__); - - generic_fillattr(inode, stat); - stat->blksize = SDFAT_SB(inode->i_sb)->fsi.cluster_size; - - TMSG("%s exited\n", __func__); - return 0; -} - static const struct inode_operations sdfat_dir_inode_operations = { .create = sdfat_create, .lookup = sdfat_lookup, @@ -3010,7 +3064,7 @@ static void sdfat_truncate(struct inode *inode, loff_t old_size) if (err) goto out; - inode->i_ctime = inode->i_mtime = current_time(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; if (IS_DIRSYNC(inode)) (void) sdfat_sync_inode(inode); else @@ -3107,7 +3161,7 @@ static int sdfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, if (((fsi->vol_type == FAT12) || (fsi->vol_type == FAT16)) && (inode->i_ino == SDFAT_ROOT_INO)) { if (sector < (fsi->dentries_in_root >> - (sb->s_blocksize_bits-DENTRY_SIZE_BITS))) { + (sb->s_blocksize_bits - DENTRY_SIZE_BITS))) { *phys = sector + fsi->root_start_sector; *mapped_blocks = 1; } @@ -3216,7 +3270,17 @@ static int sdfat_da_prep_block(struct inode *inode, sector_t iblock, } else if (create == 1) { /* Not exist: new cluster needed */ - BUG_ON(!BLOCK_ADDED(bmap_create)); + if (!BLOCK_ADDED(bmap_create)) { + sector_t last_block; + last_block = (i_size_read(inode) + (sb->s_blocksize - 1)) + >> sb->s_blocksize_bits; + sdfat_fs_error(sb, "%s: new cluster need, but " + "bmap_create == BMAP_NOT_CREATE(iblock:%lld, " + "last_block:%lld)", __func__, + (s64)iblock, (s64)last_block); + err = -EIO; + goto unlock_ret; + } // Reserved Cluster (only if iblock is the first sector in a clu) if (sec_offset == 0) { @@ -3444,11 +3508,7 @@ static inline void sdfat_submit_fullpage_bio(struct block_device *bdev, */ bio = bio_alloc(GFP_NOIO, 1); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) bio_set_dev(bio, bdev); -#else - bio->bi_bdev = bdev; -#endif bio->bi_vcnt = 1; bio->bi_io_vec[0].bv_page = page; /* Inline vec */ bio->bi_io_vec[0].bv_len = length; /* PAGE_SIZE */ @@ -3539,11 +3599,7 @@ static int sdfat_writepage(struct page *page, struct writeback_control *wbc) if (buffer_new(bh)) { clear_buffer_new(bh); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) - clean_bdev_bh_alias(bh); -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) */ - unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); -#endif + __sdfat_clean_bdev_aliases(bh->b_bdev, bh->b_blocknr); } } @@ -3593,7 +3649,7 @@ static int sdfat_writepage(struct page *page, struct writeback_control *wbc) atomic_inc(&SDFAT_SB(sb)->stat_n_pages_queued); sdfat_submit_fullpage_bio(head->b_bdev, - head->b_blocknr << (inode->i_blkbits - sb->s_blocksize_bits), + head->b_blocknr << (sb->s_blocksize_bits - SECTOR_SIZE_BITS), nr_blocks_towrite << inode->i_blkbits, page); @@ -3655,16 +3711,32 @@ static void sdfat_write_failed(struct address_space *mapping, loff_t to) } } +static int sdfat_check_writable(struct super_block *sb) +{ + if (fsapi_check_bdi_valid(sb)) + return -EIO; + + if (sb->s_flags & MS_RDONLY) + return -EROFS; + + return 0; +} + static int __sdfat_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned int len, unsigned int flags, struct page **pagep, void **fsdata, get_block_t *get_block, loff_t *bytes, const char *fname) { + struct super_block *sb = mapping->host->i_sb; int ret; __cancel_dfr_work(mapping->host, pos, (loff_t)(pos + len), fname); + ret = sdfat_check_writable(sb); + if (unlikely(ret < 0)) + return ret; + *pagep = NULL; ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, get_block, bytes); @@ -3719,7 +3791,7 @@ static int sdfat_write_end(struct file *file, struct address_space *mapping, sdfat_write_failed(mapping, pos+len); if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { - inode->i_mtime = inode->i_ctime = current_time(inode); + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; fid->attr |= ATTR_ARCHIVE; mark_inode_dirty(inode); } @@ -4725,9 +4797,12 @@ static int sdfat_read_root(struct inode *inode) { struct super_block *sb = inode->i_sb; struct sdfat_sb_info *sbi = SDFAT_SB(sb); + struct timespec ts; FS_INFO_T *fsi = &(sbi->fsi); DIR_ENTRY_T info; + ts = CURRENT_TIME_SEC; + SDFAT_I(inode)->fid.dir.dir = fsi->root_dir; SDFAT_I(inode)->fid.dir.flags = 0x01; SDFAT_I(inode)->fid.entry = -1; @@ -4763,7 +4838,7 @@ static int sdfat_read_root(struct inode *inode) SDFAT_I(inode)->i_size_ondisk = i_size_read(inode); sdfat_save_attr(inode, ATTR_SUBDIR); - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = ts; set_nlink(inode, info.NumSubdirs + 2); return 0; } @@ -5004,6 +5079,7 @@ static struct file_system_type sdfat_fs_type = { #endif /* CONFIG_SDFAT_DBG_IOCTL */ .fs_flags = FS_REQUIRES_DEV, }; +MODULE_ALIAS_FS("sdfat"); #ifdef CONFIG_SDFAT_USE_FOR_EXFAT static struct file_system_type exfat_fs_type = { @@ -5017,6 +5093,7 @@ static struct file_system_type exfat_fs_type = { #endif /* CONFIG_SDFAT_DBG_IOCTL */ .fs_flags = FS_REQUIRES_DEV, }; +MODULE_ALIAS_FS("exfat"); #endif /* CONFIG_SDFAT_USE_FOR_EXFAT */ #ifdef CONFIG_SDFAT_USE_FOR_VFAT @@ -5031,6 +5108,7 @@ static struct file_system_type vfat_fs_type = { #endif /* CONFIG_SDFAT_DBG_IOCTL */ .fs_flags = FS_REQUIRES_DEV, }; +MODULE_ALIAS_FS("vfat"); #endif /* CONFIG_SDFAT_USE_FOR_VFAT */ static int __init init_sdfat_fs(void) @@ -5116,6 +5194,7 @@ static void __exit exit_sdfat_fs(void) sdfat_destroy_inodecache(); unregister_filesystem(&sdfat_fs_type); + #ifdef CONFIG_SDFAT_USE_FOR_EXFAT unregister_filesystem(&exfat_fs_type); #endif /* CONFIG_SDFAT_USE_FOR_EXFAT */ diff --git a/fs/sdfat/sdfat.h b/fs/sdfat/sdfat.h index 6f764210fe4..922e861d722 100644 --- a/fs/sdfat/sdfat.h +++ b/fs/sdfat/sdfat.h @@ -127,7 +127,7 @@ struct sdfat_mount_options { unsigned char errors; /* on error: continue, panic, remount-ro */ unsigned char discard; /* flag on if -o dicard specified and device support discard() */ unsigned char fs_type; /* fs_type that user specified */ - unsigned short adj_req; /* support aligned mpage write */ + unsigned short adj_req; /* support aligned mpage write */ }; #define SDFAT_HASH_BITS 8 @@ -301,6 +301,7 @@ static inline void sdfat_save_attr(struct inode *inode, u32 attr) extern int sdfat_statistics_init(struct kset *sdfat_kset); extern void sdfat_statistics_uninit(void); extern void sdfat_statistics_set_mnt(FS_INFO_T *fsi); +extern void sdfat_statistics_set_mnt_ro(void); extern void sdfat_statistics_set_mkdir(u8 flags); extern void sdfat_statistics_set_create(u8 flags); extern void sdfat_statistics_set_rw(u8 flags, u32 clu_offset, s32 create); @@ -313,6 +314,7 @@ static inline int sdfat_statistics_init(struct kset *sdfat_kset) } static inline void sdfat_statistics_uninit(void) {}; static inline void sdfat_statistics_set_mnt(FS_INFO_T *fsi) {}; +static inline void sdfat_statistics_set_mnt_ro(void) {}; static inline void sdfat_statistics_set_mkdir(u8 flags) {}; static inline void sdfat_statistics_set_create(u8 flags) {}; static inline void sdfat_statistics_set_rw(u8 flags, u32 clu_offset, s32 create) {}; @@ -505,4 +507,3 @@ extern void __sdfat_dmsg(int level, const char *fmt, ...) __printf(2, 3) __cold; } #endif /* !_SDFAT_H */ - diff --git a/fs/sdfat/sdfat_fs.h b/fs/sdfat/sdfat_fs.h index 998ca84c9a6..487ac3f8af3 100644 --- a/fs/sdfat/sdfat_fs.h +++ b/fs/sdfat/sdfat_fs.h @@ -68,6 +68,8 @@ #define MAX_NAME_LENGTH 255 // max len of file name excluding NULL #define DOS_NAME_LENGTH 11 // DOS file name length excluding NULL +#define SECTOR_SIZE_BITS 9 /* VFS sector size is 512 bytes */ + #define DENTRY_SIZE 32 /* directory entry size */ #define DENTRY_SIZE_BITS 5 diff --git a/fs/sdfat/statistics.c b/fs/sdfat/statistics.c index 2ae1a93fb33..099d9a358a7 100644 --- a/fs/sdfat/statistics.c +++ b/fs/sdfat/statistics.c @@ -8,6 +8,7 @@ enum { SDFAT_MNT_FAT16, SDFAT_MNT_FAT32, SDFAT_MNT_EXFAT, + SDFAT_MNT_RO, SDFAT_MNT_MAX }; @@ -85,11 +86,12 @@ static ssize_t mount_show(struct kobject *kobj, { return snprintf(buff, PAGE_SIZE, "\"FAT12_MNT_I\":\"%u\"," "\"FAT16_MNT_I\":\"%u\",\"FAT32_MNT_I\":\"%u\"," - "\"EXFAT_MNT_I\":\"%u\"\n", + "\"EXFAT_MNT_I\":\"%u\",\"RO_MNT_I\":\"%u\"\n", statistics.mnt_cnt[SDFAT_MNT_FAT12], statistics.mnt_cnt[SDFAT_MNT_FAT16], statistics.mnt_cnt[SDFAT_MNT_FAT32], - statistics.mnt_cnt[SDFAT_MNT_EXFAT]); + statistics.mnt_cnt[SDFAT_MNT_EXFAT], + statistics.mnt_cnt[SDFAT_MNT_RO]); } static ssize_t nofat_op_show(struct kobject *kobj, @@ -201,6 +203,11 @@ void sdfat_statistics_set_mnt(FS_INFO_T *fsi) statistics.clus_vfat[SDFAT_VF_CLUS_MAX - 1]++; } +void sdfat_statistics_set_mnt_ro(void) +{ + statistics.mnt_cnt[SDFAT_MNT_RO]++; +} + void sdfat_statistics_set_mkdir(u8 flags) { if (flags != 0x03) diff --git a/fs/sdfat/version.h b/fs/sdfat/version.h index 999f052a7e9..6689b996a81 100644 --- a/fs/sdfat/version.h +++ b/fs/sdfat/version.h @@ -22,4 +22,5 @@ /* PURPOSE : sdFAT File Manager */ /* */ /************************************************************************/ -#define SDFAT_VERSION "2.0.8-lineage" + +#define SDFAT_VERSION "2.1.8-lineage"