fs: sdfat: Update to version 2.3.0
* Samsung version G975FXXU3BSKO Change-Id: I11a2c361ba70441d2a75188a4f91d3cd324d1a9e Signed-off-by: Kevin F. Haggerty <haggertk@lineageos.org>
This commit is contained in:
parent
ab4d4ec6ff
commit
21fd5d5610
|
@ -120,3 +120,8 @@ config SDFAT_STATISTICS
|
||||||
bool "Enable statistics for bigdata"
|
bool "Enable statistics for bigdata"
|
||||||
depends on SDFAT_FS
|
depends on SDFAT_FS
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SDFAT_UEVENT
|
||||||
|
bool "Enable uevent"
|
||||||
|
depends on SDFAT_FS
|
||||||
|
default y
|
||||||
|
|
|
@ -98,6 +98,14 @@ typedef struct {
|
||||||
/* Type Definitions */
|
/* Type Definitions */
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
/* should be merged it to DATE_TIME_T */
|
/* should be merged it to DATE_TIME_T */
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
u8 off : 7;
|
||||||
|
u8 valid : 1;
|
||||||
|
};
|
||||||
|
u8 value;
|
||||||
|
} TIMEZONE_T;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u16 sec; /* 0 ~ 59 */
|
u16 sec; /* 0 ~ 59 */
|
||||||
u16 min; /* 0 ~ 59 */
|
u16 min; /* 0 ~ 59 */
|
||||||
|
@ -105,9 +113,9 @@ typedef struct {
|
||||||
u16 day; /* 1 ~ 31 */
|
u16 day; /* 1 ~ 31 */
|
||||||
u16 mon; /* 1 ~ 12 */
|
u16 mon; /* 1 ~ 12 */
|
||||||
u16 year; /* 0 ~ 127 (since 1980) */
|
u16 year; /* 0 ~ 127 (since 1980) */
|
||||||
|
TIMEZONE_T tz;
|
||||||
} TIMESTAMP_T;
|
} TIMESTAMP_T;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u16 Year;
|
u16 Year;
|
||||||
u16 Month;
|
u16 Month;
|
||||||
|
@ -116,6 +124,7 @@ typedef struct {
|
||||||
u16 Minute;
|
u16 Minute;
|
||||||
u16 Second;
|
u16 Second;
|
||||||
u16 MilliSecond;
|
u16 MilliSecond;
|
||||||
|
TIMEZONE_T Timezone;
|
||||||
} DATE_TIME_T;
|
} DATE_TIME_T;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -33,12 +33,27 @@
|
||||||
#include <linux/writeback.h>
|
#include <linux/writeback.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/log2.h>
|
#include <linux/log2.h>
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||||
|
#include <linux/iversion.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "sdfat.h"
|
#include "sdfat.h"
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
#include <asm/unaligned.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 */
|
/* Constant & Macro Definitions */
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
@ -1956,10 +1971,10 @@ s32 fscore_lookup(struct inode *inode, u8 *path, FILE_ID_T *fid)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* check the validation of hint_stat and initialize it if required */
|
/* check the validation of hint_stat and initialize it if required */
|
||||||
if (dir_fid->version != (u32)(GET_IVERSION(inode) & 0xffffffff)) {
|
if (dir_fid->version != (u32)inode_peek_iversion(inode)) {
|
||||||
dir_fid->hint_stat.clu = dir.dir;
|
dir_fid->hint_stat.clu = dir.dir;
|
||||||
dir_fid->hint_stat.eidx = 0;
|
dir_fid->hint_stat.eidx = 0;
|
||||||
dir_fid->version = (u32)(GET_IVERSION(inode) & 0xffffffff);
|
dir_fid->version = (u32)inode_peek_iversion(inode);
|
||||||
dir_fid->hint_femp.eidx = -1;
|
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.Minute = tm.min;
|
||||||
info->CreateTimestamp.Second = tm.sec;
|
info->CreateTimestamp.Second = tm.sec;
|
||||||
info->CreateTimestamp.MilliSecond = 0;
|
info->CreateTimestamp.MilliSecond = 0;
|
||||||
|
info->CreateTimestamp.Timezone.value = tm.tz.value;
|
||||||
|
|
||||||
fsi->fs_func->get_entry_time(ep, &tm, TM_MODIFY);
|
fsi->fs_func->get_entry_time(ep, &tm, TM_MODIFY);
|
||||||
info->ModifyTimestamp.Year = tm.year;
|
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.Minute = tm.min;
|
||||||
info->ModifyTimestamp.Second = tm.sec;
|
info->ModifyTimestamp.Second = tm.sec;
|
||||||
info->ModifyTimestamp.MilliSecond = 0;
|
info->ModifyTimestamp.MilliSecond = 0;
|
||||||
|
info->ModifyTimestamp.Timezone.value = tm.tz.value;
|
||||||
|
|
||||||
memset((s8 *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T));
|
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);
|
fsi->fs_func->set_entry_attr(ep, info->Attr);
|
||||||
|
|
||||||
/* set FILE_INFO structure using the acquired DENTRY_T */
|
/* set FILE_INFO structure using the acquired DENTRY_T */
|
||||||
|
tm.tz = info->CreateTimestamp.Timezone;
|
||||||
tm.sec = info->CreateTimestamp.Second;
|
tm.sec = info->CreateTimestamp.Second;
|
||||||
tm.min = info->CreateTimestamp.Minute;
|
tm.min = info->CreateTimestamp.Minute;
|
||||||
tm.hour = info->CreateTimestamp.Hour;
|
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;
|
tm.year = info->CreateTimestamp.Year;
|
||||||
fsi->fs_func->set_entry_time(ep, &tm, TM_CREATE);
|
fsi->fs_func->set_entry_time(ep, &tm, TM_CREATE);
|
||||||
|
|
||||||
|
tm.tz = info->ModifyTimestamp.Timezone;
|
||||||
tm.sec = info->ModifyTimestamp.Second;
|
tm.sec = info->ModifyTimestamp.Second;
|
||||||
tm.min = info->ModifyTimestamp.Minute;
|
tm.min = info->ModifyTimestamp.Minute;
|
||||||
tm.hour = info->ModifyTimestamp.Hour;
|
tm.hour = info->ModifyTimestamp.Hour;
|
||||||
|
|
|
@ -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)
|
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;
|
FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case TM_CREATE:
|
case TM_CREATE:
|
||||||
t = le16_to_cpu(ep->create_time);
|
t = le16_to_cpu(ep->create_time);
|
||||||
d = le16_to_cpu(ep->create_date);
|
d = le16_to_cpu(ep->create_date);
|
||||||
|
tz = ep->create_tz;
|
||||||
break;
|
break;
|
||||||
case TM_MODIFY:
|
case TM_MODIFY:
|
||||||
t = le16_to_cpu(ep->modify_time);
|
t = le16_to_cpu(ep->modify_time);
|
||||||
d = le16_to_cpu(ep->modify_date);
|
d = le16_to_cpu(ep->modify_date);
|
||||||
|
tz = ep->modify_tz;
|
||||||
break;
|
break;
|
||||||
case TM_ACCESS:
|
case TM_ACCESS:
|
||||||
t = le16_to_cpu(ep->access_time);
|
t = le16_to_cpu(ep->access_time);
|
||||||
d = le16_to_cpu(ep->access_date);
|
d = le16_to_cpu(ep->access_date);
|
||||||
|
tz = ep->access_tz;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tp->tz.value = tz;
|
||||||
tp->sec = (t & 0x001F) << 1;
|
tp->sec = (t & 0x001F) << 1;
|
||||||
tp->min = (t >> 5) & 0x003F;
|
tp->min = (t >> 5) & 0x003F;
|
||||||
tp->hour = (t >> 11);
|
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:
|
case TM_CREATE:
|
||||||
ep->create_time = cpu_to_le16(t);
|
ep->create_time = cpu_to_le16(t);
|
||||||
ep->create_date = cpu_to_le16(d);
|
ep->create_date = cpu_to_le16(d);
|
||||||
|
ep->create_tz = tp->tz.value;
|
||||||
break;
|
break;
|
||||||
case TM_MODIFY:
|
case TM_MODIFY:
|
||||||
ep->modify_time = cpu_to_le16(t);
|
ep->modify_time = cpu_to_le16(t);
|
||||||
ep->modify_date = cpu_to_le16(d);
|
ep->modify_date = cpu_to_le16(d);
|
||||||
|
ep->modify_tz = tp->tz.value;
|
||||||
break;
|
break;
|
||||||
case TM_ACCESS:
|
case TM_ACCESS:
|
||||||
ep->access_time = cpu_to_le16(t);
|
ep->access_time = cpu_to_le16(t);
|
||||||
ep->access_date = cpu_to_le16(d);
|
ep->access_date = cpu_to_le16(d);
|
||||||
|
ep->access_tz = tp->tz.value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} /* end of exfat_set_entry_time */
|
} /* 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);
|
exfat_set_entry_time((DENTRY_T *) ep, tp, TM_ACCESS);
|
||||||
ep->create_time_ms = 0;
|
ep->create_time_ms = 0;
|
||||||
ep->modify_time_ms = 0;
|
ep->modify_time_ms = 0;
|
||||||
ep->access_time_ms = 0;
|
|
||||||
} /* end of __init_file_entry */
|
} /* end of __init_file_entry */
|
||||||
|
|
||||||
static void __init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size)
|
static void __init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size)
|
||||||
|
|
|
@ -441,6 +441,7 @@ static void fat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tp->tz.value = 0x00;
|
||||||
tp->sec = (t & 0x001F) << 1;
|
tp->sec = (t & 0x001F) << 1;
|
||||||
tp->min = (t >> 5) & 0x003F;
|
tp->min = (t >> 5) & 0x003F;
|
||||||
tp->hour = (t >> 11);
|
tp->hour = (t >> 11);
|
||||||
|
|
|
@ -52,6 +52,58 @@
|
||||||
#define ST_LOG(fmt, ...)
|
#define ST_LOG(fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* 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
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
* sdfat_fs_error reports a file system problem that might indicate fa data
|
||||||
* corruption/inconsistency. Depending on 'errors' mount option the
|
* corruption/inconsistency. Depending on 'errors' mount option the
|
||||||
|
@ -99,6 +151,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",
|
ST_LOG("[SDFAT](%s[%d:%d]): Filesystem has been set read-only\n",
|
||||||
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
|
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
|
||||||
#endif
|
#endif
|
||||||
|
sdfat_uevent_ro_remount(sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__sdfat_fs_error);
|
EXPORT_SYMBOL(__sdfat_fs_error);
|
||||||
|
@ -174,8 +227,9 @@ static time_t accum_days_in_year[] = {
|
||||||
0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
|
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). */
|
/* 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_compat *ts,
|
void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
|
||||||
DATE_TIME_T *tp)
|
DATE_TIME_T *tp)
|
||||||
{
|
{
|
||||||
time_t year = tp->Year;
|
time_t year = tp->Year;
|
||||||
|
@ -191,22 +245,45 @@ void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec_compat *ts,
|
||||||
+ (year * 365 + ld + accum_days_in_year[tp->Month]
|
+ (year * 365 + ld + accum_days_in_year[tp->Month]
|
||||||
+ (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY;
|
+ (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY;
|
||||||
|
|
||||||
if (!sbi->options.tz_utc)
|
|
||||||
ts->tv_sec += sys_tz.tz_minuteswest * SECS_PER_MIN;
|
|
||||||
|
|
||||||
ts->tv_nsec = 0;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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. */
|
/* Convert linear UNIX date to a FAT time/date pair. */
|
||||||
void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, struct timespec_compat *ts,
|
void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
|
||||||
DATE_TIME_T *tp)
|
DATE_TIME_T *tp)
|
||||||
{
|
{
|
||||||
|
bool tz_valid = (sbi->fsi.vol_type == EXFAT) ? true : false;
|
||||||
time_t second = ts->tv_sec;
|
time_t second = ts->tv_sec;
|
||||||
time_t day, month, year;
|
time_t day, month, year;
|
||||||
time_t ld; /* leap day */
|
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;
|
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? */
|
/* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
|
||||||
if (second < UNIX_SECS_1980) {
|
if (second < UNIX_SECS_1980) {
|
||||||
|
@ -262,7 +339,7 @@ void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, struct timespec_compat *ts,
|
||||||
|
|
||||||
TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tp)
|
TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tp)
|
||||||
{
|
{
|
||||||
struct timespec_compat ts = CURRENT_TIME_SEC;
|
sdfat_timespec_t ts = CURRENT_TIME_SEC;
|
||||||
DATE_TIME_T dt;
|
DATE_TIME_T dt;
|
||||||
|
|
||||||
sdfat_time_unix2fat(sbi, &ts, &dt);
|
sdfat_time_unix2fat(sbi, &ts, &dt);
|
||||||
|
@ -273,6 +350,7 @@ TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tp)
|
||||||
tp->hour = dt.Hour;
|
tp->hour = dt.Hour;
|
||||||
tp->min = dt.Minute;
|
tp->min = dt.Minute;
|
||||||
tp->sec = dt.Second;
|
tp->sec = dt.Second;
|
||||||
|
tp->tz.value = dt.Timezone.value;
|
||||||
|
|
||||||
return tp;
|
return tp;
|
||||||
}
|
}
|
||||||
|
|
113
fs/sdfat/sdfat.c
113
fs/sdfat/sdfat.c
|
@ -54,7 +54,9 @@
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
#include <asm/current.h>
|
#include <asm/current.h>
|
||||||
#include <asm/unaligned.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>
|
#include <linux/aio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -138,6 +140,18 @@ static int __sdfat_cmpi(const struct dentry *dentry, unsigned int len,
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
|
* 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)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
|
||||||
/* EMPTY */
|
/* EMPTY */
|
||||||
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) */
|
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) */
|
||||||
|
@ -889,6 +903,15 @@ static int sdfat_file_fsync(struct file *filp, int datasync)
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* MORE FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
|
* 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)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||||
static void sdfat_writepage_end_io(struct bio *bio)
|
static void sdfat_writepage_end_io(struct bio *bio)
|
||||||
{
|
{
|
||||||
|
@ -1215,7 +1238,8 @@ static int __sdfat_revalidate_common(struct dentry *dentry)
|
||||||
|
|
||||||
spin_lock(&dentry->d_lock);
|
spin_lock(&dentry->d_lock);
|
||||||
if ((!dentry->d_inode) && (!__check_dstate_locked(dentry) &&
|
if ((!dentry->d_inode) && (!__check_dstate_locked(dentry) &&
|
||||||
(dentry->d_time != GET_IVERSION(dentry->d_parent->d_inode)))) {
|
(dentry->d_time !=
|
||||||
|
(unsigned long)inode_peek_iversion(dentry->d_parent->d_inode)))) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
|
@ -2363,7 +2387,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct super_block *sb = dir->i_sb;
|
struct super_block *sb = dir->i_sb;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct timespec_compat ts;
|
sdfat_timespec_t ts;
|
||||||
FILE_ID_T fid;
|
FILE_ID_T fid;
|
||||||
loff_t i_pos;
|
loff_t i_pos;
|
||||||
int err;
|
int err;
|
||||||
|
@ -2380,7 +2404,7 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry)
|
||||||
|
|
||||||
__lock_d_revalidate(dentry);
|
__lock_d_revalidate(dentry);
|
||||||
|
|
||||||
INC_IVERSION(dir);
|
inode_inc_iversion(dir);
|
||||||
dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
|
dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
|
||||||
if (IS_DIRSYNC(dir))
|
if (IS_DIRSYNC(dir))
|
||||||
(void) sdfat_sync_inode(dir);
|
(void) sdfat_sync_inode(dir);
|
||||||
|
@ -2393,7 +2417,8 @@ static int __sdfat_create(struct inode *dir, struct dentry *dentry)
|
||||||
err = PTR_ERR(inode);
|
err = PTR_ERR(inode);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
INC_IVERSION(inode);
|
|
||||||
|
inode_inc_iversion(inode);
|
||||||
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
|
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
|
||||||
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
|
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
|
||||||
|
|
||||||
|
@ -2510,7 +2535,7 @@ static struct dentry *__sdfat_lookup(struct inode *dir, struct dentry *dentry)
|
||||||
dput(alias);
|
dput(alias);
|
||||||
out:
|
out:
|
||||||
/* initialize d_time even though it is positive dentry */
|
/* initialize d_time even though it is positive dentry */
|
||||||
dentry->d_time = GET_IVERSION(dir);
|
dentry->d_time = (unsigned long)inode_peek_iversion(dir);
|
||||||
__unlock_super(sb);
|
__unlock_super(sb);
|
||||||
|
|
||||||
dentry = d_splice_alias(inode, dentry);
|
dentry = d_splice_alias(inode, dentry);
|
||||||
|
@ -2528,7 +2553,8 @@ static int sdfat_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
struct super_block *sb = dir->i_sb;
|
struct super_block *sb = dir->i_sb;
|
||||||
struct timespec_compat ts;
|
|
||||||
|
sdfat_timespec_t ts;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
__lock_super(sb);
|
__lock_super(sb);
|
||||||
|
@ -2547,7 +2573,7 @@ static int sdfat_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
|
|
||||||
__lock_d_revalidate(dentry);
|
__lock_d_revalidate(dentry);
|
||||||
|
|
||||||
INC_IVERSION(dir);
|
inode_inc_iversion(dir);
|
||||||
dir->i_mtime = dir->i_atime = ts;
|
dir->i_mtime = dir->i_atime = ts;
|
||||||
if (IS_DIRSYNC(dir))
|
if (IS_DIRSYNC(dir))
|
||||||
(void) sdfat_sync_inode(dir);
|
(void) sdfat_sync_inode(dir);
|
||||||
|
@ -2557,7 +2583,7 @@ static int sdfat_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
clear_nlink(inode);
|
clear_nlink(inode);
|
||||||
inode->i_mtime = inode->i_atime = ts;
|
inode->i_mtime = inode->i_atime = ts;
|
||||||
sdfat_detach(inode);
|
sdfat_detach(inode);
|
||||||
dentry->d_time = GET_IVERSION(dir);
|
dentry->d_time = (unsigned long)inode_peek_iversion(dir);
|
||||||
out:
|
out:
|
||||||
__unlock_d_revalidate(dentry);
|
__unlock_d_revalidate(dentry);
|
||||||
__unlock_super(sb);
|
__unlock_super(sb);
|
||||||
|
@ -2569,7 +2595,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t
|
||||||
{
|
{
|
||||||
struct super_block *sb = dir->i_sb;
|
struct super_block *sb = dir->i_sb;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct timespec_compat ts;
|
sdfat_timespec_t ts;
|
||||||
FILE_ID_T fid;
|
FILE_ID_T fid;
|
||||||
loff_t i_pos;
|
loff_t i_pos;
|
||||||
int err;
|
int err;
|
||||||
|
@ -2599,7 +2625,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t
|
||||||
|
|
||||||
__lock_d_revalidate(dentry);
|
__lock_d_revalidate(dentry);
|
||||||
|
|
||||||
INC_IVERSION(dir);
|
inode_inc_iversion(dir);
|
||||||
dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
|
dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
|
||||||
if (IS_DIRSYNC(dir))
|
if (IS_DIRSYNC(dir))
|
||||||
(void) sdfat_sync_inode(dir);
|
(void) sdfat_sync_inode(dir);
|
||||||
|
@ -2612,7 +2638,7 @@ static int sdfat_symlink(struct inode *dir, struct dentry *dentry, const char *t
|
||||||
err = PTR_ERR(inode);
|
err = PTR_ERR(inode);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
INC_IVERSION(inode);
|
inode_inc_iversion(inode);
|
||||||
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
|
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
|
||||||
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
|
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
|
||||||
|
|
||||||
|
@ -2636,7 +2662,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct super_block *sb = dir->i_sb;
|
struct super_block *sb = dir->i_sb;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct timespec_compat ts;
|
sdfat_timespec_t ts;
|
||||||
FILE_ID_T fid;
|
FILE_ID_T fid;
|
||||||
loff_t i_pos;
|
loff_t i_pos;
|
||||||
int err;
|
int err;
|
||||||
|
@ -2653,7 +2679,7 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry)
|
||||||
|
|
||||||
__lock_d_revalidate(dentry);
|
__lock_d_revalidate(dentry);
|
||||||
|
|
||||||
INC_IVERSION(dir);
|
inode_inc_iversion(dir);
|
||||||
dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
|
dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
|
||||||
if (IS_DIRSYNC(dir))
|
if (IS_DIRSYNC(dir))
|
||||||
(void) sdfat_sync_inode(dir);
|
(void) sdfat_sync_inode(dir);
|
||||||
|
@ -2667,7 +2693,8 @@ static int __sdfat_mkdir(struct inode *dir, struct dentry *dentry)
|
||||||
err = PTR_ERR(inode);
|
err = PTR_ERR(inode);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
INC_IVERSION(inode);
|
|
||||||
|
inode_inc_iversion(inode);
|
||||||
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
|
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
|
||||||
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
|
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
|
||||||
|
|
||||||
|
@ -2687,7 +2714,7 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
struct super_block *sb = dir->i_sb;
|
struct super_block *sb = dir->i_sb;
|
||||||
struct timespec_compat ts;
|
sdfat_timespec_t ts;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
__lock_super(sb);
|
__lock_super(sb);
|
||||||
|
@ -2704,7 +2731,7 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry)
|
||||||
|
|
||||||
__lock_d_revalidate(dentry);
|
__lock_d_revalidate(dentry);
|
||||||
|
|
||||||
INC_IVERSION(dir);
|
inode_inc_iversion(dir);
|
||||||
dir->i_mtime = dir->i_atime = ts;
|
dir->i_mtime = dir->i_atime = ts;
|
||||||
if (IS_DIRSYNC(dir))
|
if (IS_DIRSYNC(dir))
|
||||||
(void) sdfat_sync_inode(dir);
|
(void) sdfat_sync_inode(dir);
|
||||||
|
@ -2715,7 +2742,7 @@ static int sdfat_rmdir(struct inode *dir, struct dentry *dentry)
|
||||||
clear_nlink(inode);
|
clear_nlink(inode);
|
||||||
inode->i_mtime = inode->i_atime = ts;
|
inode->i_mtime = inode->i_atime = ts;
|
||||||
sdfat_detach(inode);
|
sdfat_detach(inode);
|
||||||
dentry->d_time = GET_IVERSION(dir);
|
dentry->d_time = (unsigned long)inode_peek_iversion(dir);
|
||||||
out:
|
out:
|
||||||
__unlock_d_revalidate(dentry);
|
__unlock_d_revalidate(dentry);
|
||||||
__unlock_super(sb);
|
__unlock_super(sb);
|
||||||
|
@ -2728,7 +2755,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
{
|
{
|
||||||
struct inode *old_inode, *new_inode;
|
struct inode *old_inode, *new_inode;
|
||||||
struct super_block *sb = old_dir->i_sb;
|
struct super_block *sb = old_dir->i_sb;
|
||||||
struct timespec_compat ts;
|
sdfat_timespec_t ts;
|
||||||
loff_t i_pos;
|
loff_t i_pos;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -2752,7 +2779,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
__lock_d_revalidate(old_dentry);
|
__lock_d_revalidate(old_dentry);
|
||||||
__lock_d_revalidate(new_dentry);
|
__lock_d_revalidate(new_dentry);
|
||||||
|
|
||||||
INC_IVERSION(new_dir);
|
inode_inc_iversion(new_dir);
|
||||||
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = ts;
|
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = ts;
|
||||||
if (IS_DIRSYNC(new_dir))
|
if (IS_DIRSYNC(new_dir))
|
||||||
(void) sdfat_sync_inode(new_dir);
|
(void) sdfat_sync_inode(new_dir);
|
||||||
|
@ -2773,7 +2800,7 @@ static int __sdfat_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
inc_nlink(new_dir);
|
inc_nlink(new_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
INC_IVERSION(old_dir);
|
inode_inc_iversion(old_dir);
|
||||||
old_dir->i_ctime = old_dir->i_mtime = ts;
|
old_dir->i_ctime = old_dir->i_mtime = ts;
|
||||||
if (IS_DIRSYNC(old_dir))
|
if (IS_DIRSYNC(old_dir))
|
||||||
(void) sdfat_sync_inode(old_dir);
|
(void) sdfat_sync_inode(old_dir);
|
||||||
|
@ -2882,6 +2909,18 @@ static int sdfat_sanitize_mode(const struct sdfat_sb_info *sbi,
|
||||||
return 0;
|
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)
|
static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -2897,7 +2936,7 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
|
||||||
&& (attr->ia_size > i_size_read(inode))) {
|
&& (attr->ia_size > i_size_read(inode))) {
|
||||||
error = sdfat_cont_expand(inode, attr->ia_size);
|
error = sdfat_cont_expand(inode, attr->ia_size);
|
||||||
if (error || attr->ia_valid == ATTR_SIZE)
|
if (error || attr->ia_valid == ATTR_SIZE)
|
||||||
return error;
|
goto out;
|
||||||
attr->ia_valid &= ~ATTR_SIZE;
|
attr->ia_valid &= ~ATTR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2911,7 +2950,7 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
|
||||||
error = setattr_prepare(dentry, attr);
|
error = setattr_prepare(dentry, attr);
|
||||||
attr->ia_valid = ia_valid;
|
attr->ia_valid = ia_valid;
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
goto out;
|
||||||
|
|
||||||
if (((attr->ia_valid & ATTR_UID) &&
|
if (((attr->ia_valid & ATTR_UID) &&
|
||||||
(!uid_eq(attr->ia_uid, sbi->options.fs_uid))) ||
|
(!uid_eq(attr->ia_uid, sbi->options.fs_uid))) ||
|
||||||
|
@ -2919,7 +2958,8 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
|
||||||
(!gid_eq(attr->ia_gid, sbi->options.fs_gid))) ||
|
(!gid_eq(attr->ia_gid, sbi->options.fs_gid))) ||
|
||||||
((attr->ia_valid & ATTR_MODE) &&
|
((attr->ia_valid & ATTR_MODE) &&
|
||||||
(attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | S_IRWXUGO)))) {
|
(attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | S_IRWXUGO)))) {
|
||||||
return -EPERM;
|
error = -EPERM;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2935,6 +2975,10 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
|
||||||
|
|
||||||
/* patch 1.2.0 : fixed the problem of size mismatch. */
|
/* patch 1.2.0 : fixed the problem of size mismatch. */
|
||||||
if (attr->ia_valid & ATTR_SIZE) {
|
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);
|
old_size = i_size_read(inode);
|
||||||
|
|
||||||
/* TO CHECK evicting directory works correctly */
|
/* TO CHECK evicting directory works correctly */
|
||||||
|
@ -2944,8 +2988,7 @@ static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
|
||||||
}
|
}
|
||||||
setattr_copy(inode, attr);
|
setattr_copy(inode, attr);
|
||||||
mark_inode_dirty(inode);
|
mark_inode_dirty(inode);
|
||||||
|
out:
|
||||||
|
|
||||||
TMSG("%s exited with err(%d)\n", __func__, error);
|
TMSG("%s exited with err(%d)\n", __func__, error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -3894,7 +3937,7 @@ static int sdfat_fill_inode(struct inode *inode, const FILE_ID_T *fid)
|
||||||
SDFAT_I(inode)->target = NULL;
|
SDFAT_I(inode)->target = NULL;
|
||||||
inode->i_uid = sbi->options.fs_uid;
|
inode->i_uid = sbi->options.fs_uid;
|
||||||
inode->i_gid = sbi->options.fs_gid;
|
inode->i_gid = sbi->options.fs_gid;
|
||||||
INC_IVERSION(inode);
|
inode_inc_iversion(inode);
|
||||||
inode->i_generation = get_seconds();
|
inode->i_generation = get_seconds();
|
||||||
|
|
||||||
if (fsapi_read_inode(inode, &info) < 0) {
|
if (fsapi_read_inode(inode, &info) < 0) {
|
||||||
|
@ -3972,7 +4015,7 @@ static struct inode *sdfat_build_inode(struct super_block *sb,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
inode->i_ino = iunique(sb, SDFAT_ROOT_INO);
|
inode->i_ino = iunique(sb, SDFAT_ROOT_INO);
|
||||||
SET_IVERSION(inode, 1);
|
inode_set_iversion(inode, 1);
|
||||||
err = sdfat_fill_inode(inode, fid);
|
err = sdfat_fill_inode(inode, fid);
|
||||||
if (err) {
|
if (err) {
|
||||||
iput(inode);
|
iput(inode);
|
||||||
|
@ -4801,7 +4844,7 @@ static int sdfat_read_root(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
struct sdfat_sb_info *sbi = SDFAT_SB(sb);
|
struct sdfat_sb_info *sbi = SDFAT_SB(sb);
|
||||||
struct timespec_compat ts;
|
sdfat_timespec_t ts;
|
||||||
FS_INFO_T *fsi = &(sbi->fsi);
|
FS_INFO_T *fsi = &(sbi->fsi);
|
||||||
DIR_ENTRY_T info;
|
DIR_ENTRY_T info;
|
||||||
|
|
||||||
|
@ -4827,7 +4870,7 @@ static int sdfat_read_root(struct inode *inode)
|
||||||
|
|
||||||
inode->i_uid = sbi->options.fs_uid;
|
inode->i_uid = sbi->options.fs_uid;
|
||||||
inode->i_gid = sbi->options.fs_gid;
|
inode->i_gid = sbi->options.fs_gid;
|
||||||
INC_IVERSION(inode);
|
inode_inc_iversion(inode);
|
||||||
inode->i_generation = 0;
|
inode->i_generation = 0;
|
||||||
inode->i_mode = sdfat_make_mode(sbi, ATTR_SUBDIR, S_IRWXUGO);
|
inode->i_mode = sdfat_make_mode(sbi, ATTR_SUBDIR, S_IRWXUGO);
|
||||||
inode->i_op = &sdfat_dir_inode_operations;
|
inode->i_op = &sdfat_dir_inode_operations;
|
||||||
|
@ -4955,7 +4998,7 @@ static int sdfat_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
}
|
}
|
||||||
|
|
||||||
root_inode->i_ino = SDFAT_ROOT_INO;
|
root_inode->i_ino = SDFAT_ROOT_INO;
|
||||||
SET_IVERSION(root_inode, 1);
|
inode_set_iversion(root_inode, 1);
|
||||||
|
|
||||||
err = sdfat_read_root(root_inode);
|
err = sdfat_read_root(root_inode);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -5127,7 +5170,7 @@ static int __init init_sdfat_fs(void)
|
||||||
|
|
||||||
sdfat_kset = kset_create_and_add("sdfat", NULL, fs_kobj);
|
sdfat_kset = kset_create_and_add("sdfat", NULL, fs_kobj);
|
||||||
if (!sdfat_kset) {
|
if (!sdfat_kset) {
|
||||||
pr_err("[SDFAT] failed to create fs_kobj\n");
|
pr_err("[SDFAT] failed to create sdfat kset\n");
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -5142,6 +5185,10 @@ static int __init init_sdfat_fs(void)
|
||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
err = sdfat_uevent_init(sdfat_kset);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
err = sdfat_init_inodecache();
|
err = sdfat_init_inodecache();
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_err("[SDFAT] failed to initialize inode cache\n");
|
pr_err("[SDFAT] failed to initialize inode cache\n");
|
||||||
|
@ -5172,6 +5219,7 @@ static int __init init_sdfat_fs(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
error:
|
||||||
|
sdfat_uevent_uninit();
|
||||||
sdfat_statistics_uninit();
|
sdfat_statistics_uninit();
|
||||||
|
|
||||||
if (sdfat_kset) {
|
if (sdfat_kset) {
|
||||||
|
@ -5189,6 +5237,7 @@ error:
|
||||||
|
|
||||||
static void __exit exit_sdfat_fs(void)
|
static void __exit exit_sdfat_fs(void)
|
||||||
{
|
{
|
||||||
|
sdfat_uevent_uninit();
|
||||||
sdfat_statistics_uninit();
|
sdfat_statistics_uninit();
|
||||||
|
|
||||||
if (sdfat_kset) {
|
if (sdfat_kset) {
|
||||||
|
|
|
@ -241,6 +241,12 @@ struct sdfat_inode_info {
|
||||||
struct inode vfs_inode;
|
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
|
* FIXME : needs on-disk-slot in-memory data
|
||||||
*/
|
*/
|
||||||
|
@ -382,6 +388,18 @@ static inline void setup_sdfat_xattr_handler(struct super_block *sb) {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* sdfat/misc.c */
|
/* 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
|
extern void
|
||||||
__sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
|
__sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
|
||||||
__printf(3, 4) __cold;
|
__printf(3, 4) __cold;
|
||||||
|
@ -397,9 +415,9 @@ __sdfat_msg(struct super_block *sb, const char *lv, int st, const char *fmt, ...
|
||||||
#define sdfat_log_msg(sb, lv, fmt, args...) \
|
#define sdfat_log_msg(sb, lv, fmt, args...) \
|
||||||
__sdfat_msg(sb, lv, 1, fmt, ## args)
|
__sdfat_msg(sb, lv, 1, fmt, ## args)
|
||||||
extern void sdfat_log_version(void);
|
extern void sdfat_log_version(void);
|
||||||
extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec_compat *ts,
|
extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
|
||||||
DATE_TIME_T *tp);
|
DATE_TIME_T *tp);
|
||||||
extern void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, struct timespec_compat *ts,
|
extern void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
|
||||||
DATE_TIME_T *tp);
|
DATE_TIME_T *tp);
|
||||||
extern TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tm);
|
extern TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tm);
|
||||||
|
|
||||||
|
|
|
@ -363,8 +363,10 @@ typedef struct {
|
||||||
__le16 access_date; // aligned
|
__le16 access_date; // aligned
|
||||||
__u8 create_time_ms;
|
__u8 create_time_ms;
|
||||||
__u8 modify_time_ms;
|
__u8 modify_time_ms;
|
||||||
__u8 access_time_ms;
|
__u8 create_tz;
|
||||||
__u8 reserved2[9];
|
__u8 modify_tz;
|
||||||
|
__u8 access_tz;
|
||||||
|
__u8 reserved2[7];
|
||||||
} FILE_DENTRY_T;
|
} FILE_DENTRY_T;
|
||||||
|
|
||||||
/* EXFAT stream extension directory entry (32 bytes) */
|
/* EXFAT stream extension directory entry (32 bytes) */
|
||||||
|
|
|
@ -22,4 +22,4 @@
|
||||||
/* PURPOSE : sdFAT File Manager */
|
/* PURPOSE : sdFAT File Manager */
|
||||||
/* */
|
/* */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
#define SDFAT_VERSION "2.1.8-lineage"
|
#define SDFAT_VERSION "2.3.0-lineage"
|
||||||
|
|
Loading…
Reference in New Issue