fs: sdfat: Update to version 2.4.5
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] / fs / sdfat / sdfat.c
index 65fcbf7e5ad82f754cfd90f1dea3ee63e79b5c96..72014f7f46abffde92c647652b25868c79a95065 100644 (file)
@@ -190,6 +190,14 @@ static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_
 {
        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
 
 
@@ -224,9 +232,12 @@ static int setattr_prepare(struct dentry *dentry, struct iattr *attr)
 
 
 #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);
 }
 
@@ -240,9 +251,12 @@ static inline unsigned long __sdfat_init_name_hash(const struct dentry *dentry)
        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)
@@ -289,7 +303,6 @@ static inline int sdfat_remount_syncfs(struct super_block *sb)
 }
 #endif
 
-
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
 static inline sector_t __sdfat_bio_sector(struct bio *bio)
 {
@@ -904,15 +917,6 @@ static int sdfat_file_fsync(struct file *filp, int datasync)
 /*************************************************************************
  * 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)
 {
@@ -2186,7 +2190,7 @@ static int sdfat_dfr_ioctl(struct inode *inode, struct file *filp,
                __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;
@@ -2397,7 +2401,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry)
 
        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)
@@ -2560,7 +2564,7 @@ static int sdfat_unlink(struct inode *dir, struct dentry *dentry)
 
        TMSG("%s entered\n", __func__);
 
-       ts = CURRENT_TIME_SEC;
+       ts = current_time(dir);
 
        SDFAT_I(inode)->fid.size = i_size_read(inode);
 
@@ -2609,7 +2613,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t
 
        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)
@@ -2670,7 +2674,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry)
 
        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)
@@ -2719,7 +2723,7 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry)
 
        TMSG("%s entered\n", __func__);
 
-       ts = CURRENT_TIME_SEC;
+       ts = current_time(dir);
 
        SDFAT_I(inode)->fid.size = i_size_read(inode);
 
@@ -2764,7 +2768,7 @@ 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;
+       ts = current_time(old_inode);
 
        SDFAT_I(old_inode)->fid.size = i_size_read(old_inode);
 
@@ -2842,7 +2846,7 @@ static int sdfat_cont_expand(struct inode *inode, loff_t size)
        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))
@@ -3100,7 +3104,7 @@ static void sdfat_truncate(struct inode *inode, loff_t old_size)
        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
@@ -3528,7 +3532,8 @@ static int sdfat_readpages(struct file *file, struct address_space *mapping,
 }
 
 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;
@@ -3552,7 +3557,7 @@ static inline void sdfat_submit_fullpage_bio(struct block_device *bdev,
        __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)
@@ -3687,7 +3692,7 @@ 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);
 
@@ -3752,7 +3757,7 @@ static int sdfat_check_writable(struct super_block *sb)
        if (fsapi_check_bdi_valid(sb))
                return -EIO;
 
-       if (sb->s_flags & MS_RDONLY)
+       if (sb_rdonly(sb))
                return -EROFS;
 
        return 0;
@@ -3827,7 +3832,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_SEC;
+               inode->i_mtime = inode->i_ctime = current_time(inode);
                fid->attr |= ATTR_ARCHIVE;
                mark_inode_dirty(inode);
        }
@@ -4039,7 +4044,7 @@ static struct inode *sdfat_alloc_inode(struct super_block *sb)
        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);
@@ -4049,6 +4054,28 @@ static void sdfat_destroy_inode(struct inode *inode)
        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;
@@ -4084,7 +4111,7 @@ static int sdfat_write_inode(struct inode *inode, struct writeback_control *wbc)
 
 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);
@@ -4112,23 +4139,8 @@ static void sdfat_evict_inode(struct inode *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;
@@ -4143,14 +4155,63 @@ static void sdfat_put_super(struct super_block *sb)
                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)" : "");
@@ -4181,7 +4242,7 @@ static void sdfat_write_super(struct super_block *sb)
        /* 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);
@@ -4309,7 +4370,8 @@ static int sdfat_statfs(struct dentry *dentry, struct kstatfs *buf)
        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;
 }
@@ -4321,7 +4383,7 @@ static int sdfat_remount(struct super_block *sb, int *flags, char *data)
        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;
 
@@ -4330,8 +4392,8 @@ static int sdfat_remount(struct super_block *sb, int *flags, char *data)
        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;
@@ -4394,7 +4456,11 @@ static int __sdfat_show_options(struct seq_file *m, struct super_block *sb)
 
 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,
@@ -4837,7 +4903,7 @@ static int sdfat_read_root(struct inode *inode)
        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;
@@ -4921,11 +4987,18 @@ static int sdfat_fill_super(struct super_block *sb, void *data, int silent)
 
        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");
@@ -5072,6 +5145,13 @@ static int __init sdfat_init_inodecache(void)
 
 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);
 }
 
@@ -5220,6 +5300,13 @@ error:
 
 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();