{
unmap_underlying_metadata(bdev, block);
}
+
+static inline int wbc_to_write_flags(struct writeback_control *wbc)
+{
+ if (wbc->sync_mode == WB_SYNC_ALL)
+ return WRITE_SYNC;
+
+ return 0;
+}
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
-static inline void __sdfat_submit_bio_write(struct bio *bio)
+static inline void __sdfat_submit_bio_write(struct bio *bio,
+ struct writeback_control *wbc)
{
- bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+ int write_flags = wbc_to_write_flags(wbc);
+
+ bio_set_op_attrs(bio, REQ_OP_WRITE, write_flags);
submit_bio(bio);
}
return init_name_hash(dentry);
}
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) */
-static inline void __sdfat_submit_bio_write(struct bio *bio)
+static inline void __sdfat_submit_bio_write(struct bio *bio,
+ struct writeback_control *wbc)
{
- submit_bio(WRITE, bio);
+ int write_flags = wbc_to_write_flags(wbc);
+
+ submit_bio(write_flags, bio);
}
static inline unsigned int __sdfat_full_name_hash(const struct dentry *unused, const char *name, unsigned int len)
}
#endif
-
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
static inline sector_t __sdfat_bio_sector(struct bio *bio)
{
/*************************************************************************
* MORE FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
*************************************************************************/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
-#define CURRENT_TIME_SEC timespec64_trunc(current_kernel_time64(), NSEC_PER_SEC)
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
-#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC)
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
- /* EMPTY */
-#endif
-
-
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
static void sdfat_writepage_end_io(struct bio *bio)
{
__lock_super(sb);
/* Check if FS_ERROR occurred */
- if (sb->s_flags & MS_RDONLY) {
+ if (sb_rdonly(sb)) {
dfr_err("RDONLY partition (err %d)", -EPERM);
__unlock_super(sb);
return -EPERM;
TMSG("%s entered\n", __func__);
- ts = CURRENT_TIME_SEC;
+ ts = current_time(dir);
err = fsapi_create(dir, (u8 *) dentry->d_name.name, FM_REGULAR, &fid);
if (err)
TMSG("%s entered\n", __func__);
- ts = CURRENT_TIME_SEC;
+ ts = current_time(dir);
SDFAT_I(inode)->fid.size = i_size_read(inode);
TMSG("%s entered\n", __func__);
- ts = CURRENT_TIME_SEC;
+ ts = current_time(dir);
err = fsapi_create(dir, (u8 *) dentry->d_name.name, FM_SYMLINK, &fid);
if (err)
TMSG("%s entered\n", __func__);
- ts = CURRENT_TIME_SEC;
+ ts = current_time(dir);
err = fsapi_mkdir(dir, (u8 *) dentry->d_name.name, &fid);
if (err)
TMSG("%s entered\n", __func__);
- ts = CURRENT_TIME_SEC;
+ ts = current_time(dir);
SDFAT_I(inode)->fid.size = i_size_read(inode);
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
- ts = CURRENT_TIME_SEC;
+ ts = current_time(old_inode);
SDFAT_I(old_inode)->fid.size = i_size_read(old_inode);
if (err)
return err;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
mark_inode_dirty(inode);
if (!IS_SYNC(inode))
if (err)
goto out;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
if (IS_DIRSYNC(inode))
(void) sdfat_sync_inode(inode);
else
}
static inline void sdfat_submit_fullpage_bio(struct block_device *bdev,
- sector_t sector, unsigned int length, struct page *page)
+ sector_t sector, unsigned int length,
+ struct page *page, struct writeback_control *wbc)
{
/* Single page bio submit */
struct bio *bio;
__sdfat_set_bio_iterate(bio, sector, length, 0, 0);
bio->bi_end_io = sdfat_writepage_end_io;
- __sdfat_submit_bio_write(bio);
+ __sdfat_submit_bio_write(bio, wbc);
}
static int sdfat_writepage(struct page *page, struct writeback_control *wbc)
sdfat_submit_fullpage_bio(head->b_bdev,
head->b_blocknr << (sb->s_blocksize_bits - SECTOR_SIZE_BITS),
nr_blocks_towrite << inode->i_blkbits,
- page);
+ page, wbc);
unlock_page(page);
if (fsapi_check_bdi_valid(sb))
return -EIO;
- if (sb->s_flags & MS_RDONLY)
+ if (sb_rdonly(sb))
return -EROFS;
return 0;
sdfat_write_failed(mapping, pos+len);
if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) {
- inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
fid->attr |= ATTR_ARCHIVE;
mark_inode_dirty(inode);
}
return &ei->vfs_inode;
}
-static void sdfat_destroy_inode(struct inode *inode)
+static void sdfat_free_inode(struct inode *inode)
{
if (SDFAT_I(inode)->target) {
kfree(SDFAT_I(inode)->target);
kmem_cache_free(sdfat_inode_cachep, SDFAT_I(inode));
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+/* Use free_inode instead of destroy_inode */
+#define sdfat_destroy_inode (NULL)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
+static void sdfat_i_callback(struct rcu_head *head)
+{
+ struct inode *inode = container_of(head, struct inode, i_rcu);
+
+ sdfat_free_inode(inode);
+}
+
+static void sdfat_destroy_inode(struct inode *inode)
+{
+ call_rcu(&inode->i_rcu, sdfat_i_callback);
+}
+#else
+static void sdfat_destroy_inode(struct inode *inode)
+{
+ sdfat_free_inode(inode);
+}
+#endif
+
static int __sdfat_write_inode(struct inode *inode, int sync)
{
struct super_block *sb = inode->i_sb;
static void sdfat_evict_inode(struct inode *inode)
{
- truncate_inode_pages(&inode->i_data, 0);
+ truncate_inode_pages_final(&inode->i_data);
if (!inode->i_nlink) {
loff_t old_size = i_size_read(inode);
/* remove_inode_hash(inode); */
}
-
-
-static void sdfat_put_super(struct super_block *sb)
+static void sdfat_free_sb_info(struct sdfat_sb_info *sbi)
{
- struct sdfat_sb_info *sbi = SDFAT_SB(sb);
- int err;
-
- sdfat_log_msg(sb, KERN_INFO, "trying to unmount...");
-
- __cancel_delayed_work_sync(sbi);
-
- if (__is_sb_dirty(sb))
- sdfat_write_super(sb);
-
- __free_dfr_mem_if_required(sb);
- err = fsapi_umount(sb);
-
if (sbi->nls_disk) {
unload_nls(sbi->nls_disk);
sbi->nls_disk = NULL;
sbi->options.iocharset = sdfat_default_iocharset;
}
+ if (sbi->use_vmalloc) {
+ vfree(sbi);
+ return;
+ }
+ kfree(sbi);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
+static void delayed_free(struct rcu_head *p)
+{
+ struct sdfat_sb_info *sbi = container_of(p, struct sdfat_sb_info, rcu);
+
+ sdfat_free_sb_info(sbi);
+}
+
+static void __sdfat_destroy_sb_info(struct super_block *sb)
+{
+ struct sdfat_sb_info *sbi = SDFAT_SB(sb);
+
+ call_rcu(&sbi->rcu, delayed_free);
+}
+#else
+static void __sdfat_destroy_sb_info(struct super_block *sb)
+{
+ struct sdfat_sb_info *sbi = SDFAT_SB(sb);
+
+ sdfat_free_sb_info(sbi);
sb->s_fs_info = NULL;
+}
+#endif
+
+static void sdfat_destroy_sb_info(struct super_block *sb)
+{
+ struct sdfat_sb_info *sbi = SDFAT_SB(sb);
kobject_del(&sbi->sb_kobj);
kobject_put(&sbi->sb_kobj);
- if (!sbi->use_vmalloc)
- kfree(sbi);
- else
- vfree(sbi);
+
+ __sdfat_destroy_sb_info(sb);
+}
+
+static void sdfat_put_super(struct super_block *sb)
+{
+ struct sdfat_sb_info *sbi = SDFAT_SB(sb);
+ int err;
+
+ sdfat_log_msg(sb, KERN_INFO, "trying to unmount...");
+
+ __cancel_delayed_work_sync(sbi);
+
+ if (__is_sb_dirty(sb))
+ sdfat_write_super(sb);
+
+ __free_dfr_mem_if_required(sb);
+ err = fsapi_umount(sb);
+
+ sdfat_destroy_sb_info(sb);
sdfat_log_msg(sb, KERN_INFO, "unmounted successfully! %s",
err ? "(with previous I/O errors)" : "");
/* flush delayed FAT/DIR dirty */
__flush_delayed_meta(sb, 0);
- if (!(sb->s_flags & MS_RDONLY))
+ if (!sb_rdonly(sb))
fsapi_sync_fs(sb, 0);
__unlock_super(sb);
buf->f_bavail = info.FreeClusters;
buf->f_fsid.val[0] = (u32)id;
buf->f_fsid.val[1] = (u32)(id >> 32);
- buf->f_namelen = 260;
+ /* Unicode utf8 255 characters */
+ buf->f_namelen = MAX_NAME_LENGTH * MAX_CHARSET_SIZE;
return 0;
}
struct sdfat_sb_info *sbi = SDFAT_SB(sb);
FS_INFO_T *fsi = &(sbi->fsi);
- *flags |= MS_NODIRATIME;
+ *flags |= SB_NODIRATIME;
prev_sb_flags = sb->s_flags;
fsapi_set_vol_flags(sb, VOL_CLEAN, 1);
sdfat_log_msg(sb, KERN_INFO, "re-mounted(%s->%s), eio=0x%x, Opts: %s",
- (prev_sb_flags & MS_RDONLY) ? "ro" : "rw",
- (*flags & MS_RDONLY) ? "ro" : "rw",
+ (prev_sb_flags & SB_RDONLY) ? "ro" : "rw",
+ (*flags & SB_RDONLY) ? "ro" : "rw",
fsi->prev_eio, orig_data);
kfree(orig_data);
return 0;
static const struct super_operations sdfat_sops = {
.alloc_inode = sdfat_alloc_inode,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+ .free_inode = sdfat_free_inode,
+#else
.destroy_inode = sdfat_destroy_inode,
+#endif
.write_inode = sdfat_write_inode,
.evict_inode = sdfat_evict_inode,
.put_super = sdfat_put_super,
FS_INFO_T *fsi = &(sbi->fsi);
DIR_ENTRY_T info;
- ts = CURRENT_TIME_SEC;
+ ts = current_time(inode);
SDFAT_I(inode)->fid.dir.dir = fsi->root_dir;
SDFAT_I(inode)->fid.dir.flags = 0x01;
mutex_init(&sbi->s_vlock);
sb->s_fs_info = sbi;
- sb->s_flags |= MS_NODIRATIME;
+ sb->s_flags |= SB_NODIRATIME;
sb->s_magic = SDFAT_SUPER_MAGIC;
sb->s_op = &sdfat_sops;
ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
+ sb->s_time_gran = NSEC_PER_SEC; /* the same with default */
+ sb->s_time_min = SDFAT_MIN_TIMESTAMP_SECS;
+ sb->s_time_max = SDFAT_MAX_TIMESTAMP_SECS;
+#endif
+
err = parse_options(sb, data, silent, &debug, &sbi->options);
if (err) {
sdfat_log_msg(sb, KERN_ERR, "failed to parse options");
static void sdfat_destroy_inodecache(void)
{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
+ /*
+ * Make sure all delayed rcu free inodes are flushed before we
+ * destroy cache.
+ */
+ rcu_barrier();
+#endif
kmem_cache_destroy(sdfat_inode_cachep);
}
static void __exit exit_sdfat_fs(void)
{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
+ /*
+ * Make sure all delayed rcu free inodes are flushed before we
+ * destroy cache.
+ */
+ rcu_barrier();
+#endif
sdfat_uevent_uninit();
sdfat_statistics_uninit();