diff options
| -rw-r--r-- | Kconfig | 5 | ||||
| -rw-r--r-- | api.h | 11 | ||||
| -rw-r--r-- | core.c | 23 | ||||
| -rw-r--r-- | core_exfat.c | 10 | ||||
| -rw-r--r-- | core_fat.c | 1 | ||||
| -rw-r--r-- | misc.c | 91 | ||||
| -rw-r--r-- | sdfat.c | 113 | ||||
| -rw-r--r-- | sdfat.h | 22 | ||||
| -rw-r--r-- | sdfat_fs.h | 6 | ||||
| -rw-r--r-- | version.h | 2 |
10 files changed, 229 insertions, 55 deletions
@@ -119,3 +119,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 @@ -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 { @@ -33,12 +33,27 @@ #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; diff --git a/core_exfat.c b/core_exfat.c index 08c45b09bb78..9e4b994d0e90 100644 --- a/core_exfat.c +++ b/core_exfat.c @@ -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) diff --git a/core_fat.c b/core_fat.c index d25ec32d3b31..5e0a196ae42b 100644 --- a/core_fat.c +++ b/core_fat.c @@ -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); @@ -55,8 +55,53 @@ /************************************************************************* * 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 /* @@ -102,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); @@ -177,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 */ @@ -194,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) { @@ -265,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); @@ -276,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; } @@ -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) */ @@ -147,9 +161,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, @@ -893,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) { @@ -1219,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); @@ -2367,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; @@ -2384,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); @@ -2397,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. */ @@ -2514,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); @@ -2532,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); @@ -2551,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); @@ -2561,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); @@ -2573,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; @@ -2603,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); @@ -2616,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. */ @@ -2640,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; @@ -2657,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); @@ -2671,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. */ @@ -2691,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); @@ -2708,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); @@ -2719,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); @@ -2732,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; @@ -2756,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); @@ -2777,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); @@ -2886,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) { @@ -2901,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; } @@ -2915,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))) || @@ -2923,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; } /* @@ -2939,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 */ @@ -2948,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; } @@ -3898,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) { @@ -3976,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); @@ -4796,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; @@ -4822,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; @@ -4946,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) { @@ -5121,7 +5158,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; } @@ -5136,6 +5173,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"); @@ -5166,6 +5207,7 @@ static int __init init_sdfat_fs(void) return 0; error: + sdfat_uevent_uninit(); sdfat_statistics_uninit(); if (sdfat_kset) { @@ -5183,6 +5225,7 @@ error: static void __exit exit_sdfat_fs(void) { + sdfat_uevent_uninit(); sdfat_statistics_uninit(); if (sdfat_kset) { @@ -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); diff --git a/sdfat_fs.h b/sdfat_fs.h index 7044f8549655..23b5cda2f58c 100644 --- a/sdfat_fs.h +++ b/sdfat_fs.h @@ -366,8 +366,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) */ diff --git a/version.h b/version.h index c96fcf47b753..44e44e03d847 100644 --- a/version.h +++ b/version.h @@ -22,4 +22,4 @@ /* PURPOSE : sdFAT File Manager */ /* */ /************************************************************************/ -#define SDFAT_VERSION "2.1.10-lineage" +#define SDFAT_VERSION "2.3.0-lineage" |
