fs: sdfat: Update to version 2.3.0
authorKevin F. Haggerty <haggertk@lineageos.org>
Fri, 13 Dec 2019 23:38:33 +0000 (16:38 -0700)
committerDanny Wood <danwood76@gmail.com>
Thu, 18 Feb 2021 09:12:57 +0000 (09:12 +0000)
* Samsung version G975FXXU3BSKO

Change-Id: I11a2c361ba70441d2a75188a4f91d3cd324d1a9e
Signed-off-by: Kevin F. Haggerty <haggertk@lineageos.org>
fs/sdfat/Kconfig
fs/sdfat/api.h
fs/sdfat/core.c
fs/sdfat/core_exfat.c
fs/sdfat/core_fat.c
fs/sdfat/misc.c
fs/sdfat/sdfat.c
fs/sdfat/sdfat.h
fs/sdfat/sdfat_fs.h
fs/sdfat/version.h

index 3a15bbb55526fcefeeeed1b8f3d5be3da0518a56..6c0d268dc838c98e7a5bc81d9ac360e2b316e47e 100644 (file)
@@ -120,3 +120,8 @@ config SDFAT_STATISTICS
        bool "enable statistics for bigdata"
        depends on SDFAT_FS
        default y
+
+config SDFAT_UEVENT
+       bool "Enable uevent"
+       depends on SDFAT_FS
+       default y
index df6a32fb8b3e1d0739cb0d6975f2a963adb90338..344297ab58aefce6a8f881194ae9902ea3e88669 100644 (file)
@@ -98,6 +98,14 @@ typedef struct {
 /*  Type Definitions                                                    */
 /*----------------------------------------------------------------------*/
 /* should be merged it to DATE_TIME_T */
+typedef union {
+       struct {
+               u8 off : 7;
+               u8 valid : 1;
+       };
+       u8 value;
+} TIMEZONE_T;
+
 typedef struct {
        u16      sec;        /* 0 ~ 59               */
        u16      min;        /* 0 ~ 59               */
@@ -105,9 +113,9 @@ typedef struct {
        u16      day;        /* 1 ~ 31               */
        u16      mon;        /* 1 ~ 12               */
        u16      year;       /* 0 ~ 127 (since 1980) */
+       TIMEZONE_T tz;
 } TIMESTAMP_T;
 
-
 typedef struct {
        u16      Year;
        u16      Month;
@@ -116,6 +124,7 @@ typedef struct {
        u16      Minute;
        u16      Second;
        u16      MilliSecond;
+       TIMEZONE_T Timezone;
 } DATE_TIME_T;
 
 typedef struct {
index 618c9e7f72d1ff8e92ee7c785e55dedc5a587fb1..3a5af0b83d5994564a69aa2746875302aec2ba74 100644 (file)
 #include <linux/writeback.h>
 #include <linux/kernel.h>
 #include <linux/log2.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
+#include <linux/iversion.h>
+#endif
 
 #include "sdfat.h"
 #include "core.h"
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 
+
+/*************************************************************************
+ * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
+ *************************************************************************/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)
+static inline u64 inode_peek_iversion(struct inode *inode)
+{
+       return inode->i_version;
+}
+#endif
+
+
 /*----------------------------------------------------------------------*/
 /*  Constant & Macro Definitions                                        */
 /*----------------------------------------------------------------------*/
@@ -1956,10 +1971,10 @@ s32 fscore_lookup(struct inode *inode, u8 *path, FILE_ID_T *fid)
                return ret;
 
        /* check the validation of hint_stat and initialize it if required */
-       if (dir_fid->version != (u32)(inode->i_version & 0xffffffff)) {
+       if (dir_fid->version != (u32)inode_peek_iversion(inode)) {
                dir_fid->hint_stat.clu = dir.dir;
                dir_fid->hint_stat.eidx = 0;
-               dir_fid->version = (u32)(inode->i_version & 0xffffffff);
+               dir_fid->version = (u32)inode_peek_iversion(inode);
                dir_fid->hint_femp.eidx = -1;
        }
 
@@ -2956,6 +2971,7 @@ s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info)
        info->CreateTimestamp.Minute = tm.min;
        info->CreateTimestamp.Second = tm.sec;
        info->CreateTimestamp.MilliSecond = 0;
+       info->CreateTimestamp.Timezone.value = tm.tz.value;
 
        fsi->fs_func->get_entry_time(ep, &tm, TM_MODIFY);
        info->ModifyTimestamp.Year = tm.year;
@@ -2965,6 +2981,7 @@ s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info)
        info->ModifyTimestamp.Minute = tm.min;
        info->ModifyTimestamp.Second = tm.sec;
        info->ModifyTimestamp.MilliSecond = 0;
+       info->ModifyTimestamp.Timezone.value = tm.tz.value;
 
        memset((s8 *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T));
 
@@ -3067,6 +3084,7 @@ s32 fscore_write_inode(struct inode *inode, DIR_ENTRY_T *info, s32 sync)
        fsi->fs_func->set_entry_attr(ep, info->Attr);
 
        /* set FILE_INFO structure using the acquired DENTRY_T */
+       tm.tz  = info->CreateTimestamp.Timezone;
        tm.sec  = info->CreateTimestamp.Second;
        tm.min  = info->CreateTimestamp.Minute;
        tm.hour = info->CreateTimestamp.Hour;
@@ -3075,6 +3093,7 @@ s32 fscore_write_inode(struct inode *inode, DIR_ENTRY_T *info, s32 sync)
        tm.year = info->CreateTimestamp.Year;
        fsi->fs_func->set_entry_time(ep, &tm, TM_CREATE);
 
+       tm.tz  = info->ModifyTimestamp.Timezone;
        tm.sec  = info->ModifyTimestamp.Second;
        tm.min  = info->ModifyTimestamp.Minute;
        tm.hour = info->ModifyTimestamp.Hour;
index 08c45b09bb78c40b37a379bddc75b1755c0a75f2..cde77205744556c0611f33ff50520ad11f081fb9 100644 (file)
@@ -222,24 +222,28 @@ static void exfat_set_entry_size(DENTRY_T *p_entry, u64 size)
 
 static void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
 {
-       u16 t = 0x00, d = 0x21;
+       u16 t = 0x00, d = 0x21, tz = 0x00;
        FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
 
        switch (mode) {
        case TM_CREATE:
                t = le16_to_cpu(ep->create_time);
                d = le16_to_cpu(ep->create_date);
+               tz = ep->create_tz;
                break;
        case TM_MODIFY:
                t = le16_to_cpu(ep->modify_time);
                d = le16_to_cpu(ep->modify_date);
+               tz = ep->modify_tz;
                break;
        case TM_ACCESS:
                t = le16_to_cpu(ep->access_time);
                d = le16_to_cpu(ep->access_date);
+               tz = ep->access_tz;
                break;
        }
 
+       tp->tz.value = tz;
        tp->sec  = (t & 0x001F) << 1;
        tp->min  = (t >> 5) & 0x003F;
        tp->hour = (t >> 11);
@@ -260,14 +264,17 @@ static void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
        case TM_CREATE:
                ep->create_time = cpu_to_le16(t);
                ep->create_date = cpu_to_le16(d);
+               ep->create_tz = tp->tz.value;
                break;
        case TM_MODIFY:
                ep->modify_time = cpu_to_le16(t);
                ep->modify_date = cpu_to_le16(d);
+               ep->modify_tz = tp->tz.value;
                break;
        case TM_ACCESS:
                ep->access_time = cpu_to_le16(t);
                ep->access_date = cpu_to_le16(d);
+               ep->access_tz = tp->tz.value;
                break;
        }
 } /* end of exfat_set_entry_time */
@@ -285,7 +292,6 @@ static void __init_file_entry(struct super_block *sb, FILE_DENTRY_T *ep, u32 typ
        exfat_set_entry_time((DENTRY_T *) ep, tp, TM_ACCESS);
        ep->create_time_ms = 0;
        ep->modify_time_ms = 0;
-       ep->access_time_ms = 0;
 } /* end of __init_file_entry */
 
 static void __init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size)
index d25ec32d3b310b2f5c71bcecac2e9d3806aef33e..5e0a196ae42b1fed1b3629279ba6a77bb74fce75 100644 (file)
@@ -441,6 +441,7 @@ static void fat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
                break;
        }
 
+       tp->tz.value = 0x00;
        tp->sec  = (t & 0x001F) << 1;
        tp->min  = (t >> 5) & 0x003F;
        tp->hour = (t >> 11);
index 9b07d1dea43ae6e3e4c914e3417a66502959618e..ac1de710b58a2b978f1196a2a06caaa6b39510f6 100644 (file)
 /*************************************************************************
  * 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)
+#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
 
 
+#ifdef CONFIG_SDFAT_UEVENT
+static struct kobject sdfat_uevent_kobj;
+
+int sdfat_uevent_init(struct kset *sdfat_kset)
+{
+       int err;
+       struct kobj_type *ktype = get_ktype(&sdfat_kset->kobj);
+
+       sdfat_uevent_kobj.kset = sdfat_kset;
+       err = kobject_init_and_add(&sdfat_uevent_kobj, ktype, NULL, "uevent");
+       if (err)
+               pr_err("[SDFAT] Unable to create sdfat uevent kobj\n");
+
+       return err;
+}
+
+void sdfat_uevent_uninit(void)
+{
+       kobject_del(&sdfat_uevent_kobj);
+       memset(&sdfat_uevent_kobj, 0, sizeof(struct kobject));
+}
+
+void sdfat_uevent_ro_remount(struct super_block *sb)
+{
+       struct block_device *bdev = sb->s_bdev;
+       dev_t bd_dev = bdev ? bdev->bd_dev : 0;
+
+       char major[16], minor[16];
+       char *envp[] = { major, minor, NULL };
+
+       snprintf(major, sizeof(major), "MAJOR=%d", MAJOR(bd_dev));
+       snprintf(minor, sizeof(minor), "MINOR=%d", MINOR(bd_dev));
+
+       kobject_uevent_env(&sdfat_uevent_kobj, KOBJ_CHANGE, envp);
+
+       ST_LOG("[SDFAT](%s[%d:%d]): Uevent triggered\n",
+                       sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
+}
+#endif
+
 /*
  * sdfat_fs_error reports a file system problem that might indicate fa data
  * corruption/inconsistency. Depending on 'errors' mount option the
@@ -103,6 +147,7 @@ void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
                ST_LOG("[SDFAT](%s[%d:%d]): Filesystem has been set read-only\n",
                        sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
 #endif
+               sdfat_uevent_ro_remount(sb);
        }
 }
 EXPORT_SYMBOL(__sdfat_fs_error);
@@ -178,9 +223,10 @@ static time_t accum_days_in_year[] = {
        0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
 };
 
+#define TIMEZONE_SEC(x)        ((x) * 15 * SECS_PER_MIN)
 /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
-void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec *ts,
-               DATE_TIME_T *tp)
+void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
+                                                               DATE_TIME_T *tp)
 {
        time_t year = tp->Year;
        time_t ld; /* leap day */
@@ -195,22 +241,45 @@ void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec *ts,
                        + (year * 365 + ld + accum_days_in_year[tp->Month]
                        + (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY;
 
-       if (!sbi->options.tz_utc)
+       ts->tv_nsec = 0;
+
+       /* Treat as local time */
+       if (!sbi->options.tz_utc && !tp->Timezone.valid) {
                ts->tv_sec += sys_tz.tz_minuteswest * SECS_PER_MIN;
+               return;
+       }
 
-       ts->tv_nsec = 0;
+       /* Treat as UTC time */
+       if (!tp->Timezone.valid)
+               return;
+
+       /* Treat as UTC time, but need to adjust timezone to UTC0 */
+       if (tp->Timezone.off <= 0x3F)
+               ts->tv_sec -= TIMEZONE_SEC(tp->Timezone.off);
+       else /* 0x40 <= (tp->Timezone & 0x7F) <=0x7F */
+               ts->tv_sec += TIMEZONE_SEC(0x80 - tp->Timezone.off);
 }
 
+#define TIMEZONE_CUR_OFFSET()  ((sys_tz.tz_minuteswest / (-15)) & 0x7F)
 /* Convert linear UNIX date to a FAT time/date pair. */
-void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, struct timespec *ts,
-               DATE_TIME_T *tp)
+void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
+                                                               DATE_TIME_T *tp)
 {
+       bool tz_valid = (sbi->fsi.vol_type == EXFAT) ? true : false;
        time_t second = ts->tv_sec;
        time_t day, month, year;
        time_t ld; /* leap day */
 
-       if (!sbi->options.tz_utc)
+       tp->Timezone.value = 0x00;
+
+       /* Treats as local time with proper time */
+       if (tz_valid || !sbi->options.tz_utc) {
                second -= sys_tz.tz_minuteswest * SECS_PER_MIN;
+               if (tz_valid) {
+                       tp->Timezone.valid = 1;
+                       tp->Timezone.off = TIMEZONE_CUR_OFFSET();
+               }
+       }
 
        /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
        if (second < UNIX_SECS_1980) {
@@ -266,7 +335,7 @@ 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 = CURRENT_TIME_SEC;
+       sdfat_timespec_t ts = CURRENT_TIME_SEC;
        DATE_TIME_T dt;
 
        sdfat_time_unix2fat(sbi, &ts, &dt);
@@ -277,6 +346,7 @@ TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tp)
        tp->hour = dt.Hour;
        tp->min = dt.Minute;
        tp->sec = dt.Second;
+       tp->tz.value = dt.Timezone.value;
 
        return tp;
 }
index 0bf64ad20f67c77b493992cda2e42d9b8bfbd20a..65fcbf7e5ad82f754cfd90f1dea3ee63e79b5c96 100644 (file)
@@ -54,7 +54,9 @@
 #include <linux/vmalloc.h>
 #include <asm/current.h>
 #include <asm/unaligned.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
+#include <linux/iversion.h>
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
 #include <linux/aio.h>
 #endif
 
@@ -138,6 +140,18 @@ static int __sdfat_cmpi(const struct dentry *dentry, unsigned int len,
 /*************************************************************************
  * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
  *************************************************************************/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)
+static inline void inode_set_iversion(struct inode *inode, u64 val)
+{
+       inode->i_version = val;
+}
+static inline u64 inode_peek_iversion(struct inode *inode)
+{
+       return inode->i_version;
+}
+#endif
+
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
        /* EMPTY */
 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) */
@@ -148,10 +162,6 @@ static inline void bio_set_dev(struct bio *bio, struct block_device *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)
@@ -894,6 +904,15 @@ 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)
 {
@@ -1220,7 +1239,8 @@ static int __sdfat_revalidate_common(struct dentry *dentry)
 
        spin_lock(&dentry->d_lock);
        if ((!dentry->d_inode) && (!__check_dstate_locked(dentry) &&
-               (dentry->d_time != dentry->d_parent->d_inode->i_version))) {
+               (dentry->d_time !=
+               (unsigned long)inode_peek_iversion(dentry->d_parent->d_inode)))) {
                ret = 0;
        }
        spin_unlock(&dentry->d_lock);
@@ -2368,7 +2388,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry)
 {
        struct super_block *sb = dir->i_sb;
        struct inode *inode;
-       struct timespec ts;
+       sdfat_timespec_t ts;
        FILE_ID_T fid;
        loff_t i_pos;
        int err;
@@ -2385,7 +2405,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry)
 
        __lock_d_revalidate(dentry);
 
-       dir->i_version++;
+       inode_inc_iversion(dir);
        dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
        if (IS_DIRSYNC(dir))
                (void) sdfat_sync_inode(dir);
@@ -2398,7 +2418,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry)
                err = PTR_ERR(inode);
                goto out;
        }
-       inode->i_version++;
+       inode_inc_iversion(inode);
        inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
        /* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
@@ -2515,7 +2535,7 @@ static struct dentry *__sdfat_lookup(struct inode *dir, struct dentry *dentry)
        dput(alias);
 out:
        /* initialize d_time even though it is positive dentry */
-       dentry->d_time = dir->i_version;
+       dentry->d_time = (unsigned long)inode_peek_iversion(dir);
        __unlock_super(sb);
 
        dentry = d_splice_alias(inode, dentry);
@@ -2533,7 +2553,7 @@ 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;
+       sdfat_timespec_t ts;
        int err;
 
        __lock_super(sb);
@@ -2552,7 +2572,7 @@ static int sdfat_unlink(struct inode *dir, struct dentry *dentry)
 
        __lock_d_revalidate(dentry);
 
-       dir->i_version++;
+       inode_inc_iversion(dir);
        dir->i_mtime = dir->i_atime = ts;
        if (IS_DIRSYNC(dir))
                (void) sdfat_sync_inode(dir);
@@ -2562,7 +2582,7 @@ static int sdfat_unlink(struct inode *dir, struct dentry *dentry)
        clear_nlink(inode);
        inode->i_mtime = inode->i_atime = ts;
        sdfat_detach(inode);
-       dentry->d_time = dir->i_version;
+       dentry->d_time = (unsigned long)inode_peek_iversion(dir);
 out:
        __unlock_d_revalidate(dentry);
        __unlock_super(sb);
@@ -2574,7 +2594,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;
+       sdfat_timespec_t ts;
        FILE_ID_T fid;
        loff_t i_pos;
        int err;
@@ -2604,7 +2624,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t
 
        __lock_d_revalidate(dentry);
 
-       dir->i_version++;
+       inode_inc_iversion(dir);
        dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
        if (IS_DIRSYNC(dir))
                (void) sdfat_sync_inode(dir);
@@ -2617,7 +2637,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t
                err = PTR_ERR(inode);
                goto out;
        }
-       inode->i_version++;
+       inode_inc_iversion(inode);
        inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
        /* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
@@ -2641,7 +2661,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry)
 {
        struct super_block *sb = dir->i_sb;
        struct inode *inode;
-       struct timespec ts;
+       sdfat_timespec_t ts;
        FILE_ID_T fid;
        loff_t i_pos;
        int err;
@@ -2658,7 +2678,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry)
 
        __lock_d_revalidate(dentry);
 
-       dir->i_version++;
+       inode_inc_iversion(dir);
        dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
        if (IS_DIRSYNC(dir))
                (void) sdfat_sync_inode(dir);
@@ -2672,7 +2692,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry)
                err = PTR_ERR(inode);
                goto out;
        }
-       inode->i_version++;
+       inode_inc_iversion(inode);
        inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
        /* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
@@ -2692,7 +2712,7 @@ 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;
+       sdfat_timespec_t ts;
        int err;
 
        __lock_super(sb);
@@ -2709,7 +2729,7 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry)
 
        __lock_d_revalidate(dentry);
 
-       dir->i_version++;
+       inode_inc_iversion(dir);
        dir->i_mtime = dir->i_atime = ts;
        if (IS_DIRSYNC(dir))
                (void) sdfat_sync_inode(dir);
@@ -2720,7 +2740,7 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry)
        clear_nlink(inode);
        inode->i_mtime = inode->i_atime = ts;
        sdfat_detach(inode);
-       dentry->d_time = dir->i_version;
+       dentry->d_time = (unsigned long)inode_peek_iversion(dir);
 out:
        __unlock_d_revalidate(dentry);
        __unlock_super(sb);
@@ -2733,7 +2753,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;
+       sdfat_timespec_t ts;
        loff_t i_pos;
        int err;
 
@@ -2757,7 +2777,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry,
        __lock_d_revalidate(old_dentry);
        __lock_d_revalidate(new_dentry);
 
-       new_dir->i_version++;
+       inode_inc_iversion(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);
@@ -2778,7 +2798,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry,
                        inc_nlink(new_dir);
        }
 
-       old_dir->i_version++;
+       inode_inc_iversion(old_dir);
        old_dir->i_ctime = old_dir->i_mtime = ts;
        if (IS_DIRSYNC(old_dir))
                (void) sdfat_sync_inode(old_dir);
@@ -2887,6 +2907,18 @@ static int sdfat_sanitize_mode(const struct sdfat_sb_info *sbi,
        return 0;
 }
 
+/*
+ * sdfat_block_truncate_page() zeroes out a mapping from file offset `from'
+ * up to the end of the block which corresponds to `from'.
+ * This is required during truncate to physically zeroout the tail end
+ * of that block so it doesn't yield old data if the file is later grown.
+ * Also, avoid causing failure from fsx for cases of "data past EOF"
+ */
+static int sdfat_block_truncate_page(struct inode *inode, loff_t from)
+{
+       return block_truncate_page(inode->i_mapping, from, sdfat_get_block);
+}
+
 static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
 {
 
@@ -2902,7 +2934,7 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
                && (attr->ia_size > i_size_read(inode))) {
                error = sdfat_cont_expand(inode, attr->ia_size);
                if (error || attr->ia_valid == ATTR_SIZE)
-                       return error;
+                       goto out;
                attr->ia_valid &= ~ATTR_SIZE;
        }
 
@@ -2916,7 +2948,7 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
        error = setattr_prepare(dentry, attr);
        attr->ia_valid = ia_valid;
        if (error)
-               return error;
+               goto out;
 
        if (((attr->ia_valid & ATTR_UID) &&
                 (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) ||
@@ -2924,7 +2956,8 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
                 (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) ||
                ((attr->ia_valid & ATTR_MODE) &&
                 (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | S_IRWXUGO)))) {
-               return -EPERM;
+               error = -EPERM;
+               goto out;
        }
 
        /*
@@ -2940,6 +2973,10 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
 
        /* patch 1.2.0 : fixed the problem of size mismatch. */
        if (attr->ia_valid & ATTR_SIZE) {
+               error = sdfat_block_truncate_page(inode, attr->ia_size);
+               if (error)
+                       goto out;
+
                old_size = i_size_read(inode);
 
                /* TO CHECK evicting directory works correctly */
@@ -2949,8 +2986,7 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
        }
        setattr_copy(inode, attr);
        mark_inode_dirty(inode);
-
-
+out:
        TMSG("%s exited with err(%d)\n", __func__, error);
        return error;
 }
@@ -3899,7 +3935,7 @@ static int sdfat_fill_inode(struct inode *inode, const FILE_ID_T *fid)
        SDFAT_I(inode)->target = NULL;
        inode->i_uid = sbi->options.fs_uid;
        inode->i_gid = sbi->options.fs_gid;
-       inode->i_version++;
+       inode_inc_iversion(inode);
        inode->i_generation = get_seconds();
 
        if (fsapi_read_inode(inode, &info) < 0) {
@@ -3977,7 +4013,7 @@ static struct inode *sdfat_build_inode(struct super_block *sb,
                goto out;
        }
        inode->i_ino = iunique(sb, SDFAT_ROOT_INO);
-       inode->i_version = 1;
+       inode_set_iversion(inode, 1);
        err = sdfat_fill_inode(inode, fid);
        if (err) {
                iput(inode);
@@ -4797,7 +4833,7 @@ 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;
+       sdfat_timespec_t ts;
        FS_INFO_T *fsi = &(sbi->fsi);
        DIR_ENTRY_T info;
 
@@ -4823,7 +4859,7 @@ static int sdfat_read_root(struct inode *inode)
 
        inode->i_uid = sbi->options.fs_uid;
        inode->i_gid = sbi->options.fs_gid;
-       inode->i_version++;
+       inode_inc_iversion(inode);
        inode->i_generation = 0;
        inode->i_mode = sdfat_make_mode(sbi, ATTR_SUBDIR, S_IRWXUGO);
        inode->i_op = &sdfat_dir_inode_operations;
@@ -4947,7 +4983,7 @@ static int sdfat_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        root_inode->i_ino = SDFAT_ROOT_INO;
-       root_inode->i_version = 1;
+       inode_set_iversion(root_inode, 1);
 
        err = sdfat_read_root(root_inode);
        if (err) {
@@ -5117,7 +5153,7 @@ static int __init init_sdfat_fs(void)
 
        sdfat_kset = kset_create_and_add("sdfat", NULL, fs_kobj);
        if (!sdfat_kset) {
-               pr_err("[SDFAT] failed to create fs_kobj\n");
+               pr_err("[SDFAT] failed to create sdfat kset\n");
                err = -ENOMEM;
                goto error;
        }
@@ -5132,6 +5168,10 @@ static int __init init_sdfat_fs(void)
        if (err)
                goto error;
 
+       err = sdfat_uevent_init(sdfat_kset);
+       if (err)
+               goto error;
+
        err = sdfat_init_inodecache();
        if (err) {
                pr_err("[SDFAT] failed to initialize inode cache\n");
@@ -5162,6 +5202,7 @@ static int __init init_sdfat_fs(void)
 
        return 0;
 error:
+       sdfat_uevent_uninit();
        sdfat_statistics_uninit();
 
        if (sdfat_kset) {
@@ -5179,6 +5220,7 @@ error:
 
 static void __exit exit_sdfat_fs(void)
 {
+       sdfat_uevent_uninit();
        sdfat_statistics_uninit();
 
        if (sdfat_kset) {
index 5ac46598a7b64edd38edafc66d1501680576221a..60f7811c7b99ebb2bdaae8ffff9c65bd75c5fbd7 100644 (file)
@@ -209,6 +209,12 @@ struct sdfat_inode_info {
        struct inode vfs_inode;
 };
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
+typedef struct timespec64      sdfat_timespec_t;
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) */
+typedef struct timespec                sdfat_timespec_t;
+#endif
+
 /*
  * FIXME : needs on-disk-slot in-memory data
  */
@@ -350,6 +356,18 @@ static inline void setup_sdfat_xattr_handler(struct super_block *sb) {};
 #endif
 
 /* sdfat/misc.c */
+#ifdef CONFIG_SDFAT_UEVENT
+extern int sdfat_uevent_init(struct kset *sdfat_kset);
+extern void sdfat_uevent_uninit(void);
+extern void sdfat_uevent_ro_remount(struct super_block *sb);
+#else
+static inline int sdfat_uevent_init(struct kset *sdfat_kset)
+{
+       return 0;
+}
+static inline void sdfat_uevent_uninit(void) {};
+static inline void sdfat_uevent_ro_remount(struct super_block *sb) {};
+#endif
 extern void
 __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
        __printf(3, 4) __cold;
@@ -365,9 +383,9 @@ __sdfat_msg(struct super_block *sb, const char *lv, int st, const char *fmt, ...
 #define sdfat_log_msg(sb, lv, fmt, args...)          \
        __sdfat_msg(sb, lv, 1, fmt, ## args)
 extern void sdfat_log_version(void);
-extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec *ts,
+extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
                                DATE_TIME_T *tp);
-extern void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, struct timespec *ts,
+extern void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
                                DATE_TIME_T *tp);
 extern TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tm);
 
index 487ac3f8af3a535e8744ee3dc38e7dba14ab58a5..b012e406fb23f161246e9a9fed0f7ccb53bcf68a 100644 (file)
@@ -363,8 +363,10 @@ typedef struct {
        __le16  access_date;            // aligned
        __u8    create_time_ms;
        __u8    modify_time_ms;
-       __u8    access_time_ms;
-       __u8    reserved2[9];
+       __u8    create_tz;
+       __u8    modify_tz;
+       __u8    access_tz;
+       __u8    reserved2[7];
 } FILE_DENTRY_T;
 
 /* EXFAT stream extension directory entry (32 bytes) */
index 3cd0b73691ac3ccc5326dfaab2f2bfbd2a1f10dd..44e44e03d8479de5d4642c826875ccd799c6896d 100644 (file)
@@ -22,4 +22,4 @@
 /*  PURPOSE : sdFAT File Manager                                        */
 /*                                                                      */
 /************************************************************************/
-#define SDFAT_VERSION  "2.1.8-lineage"
+#define SDFAT_VERSION  "2.3.0-lineage"