Commit 6f8cd037 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-5.7-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat

Pull exfat fixes from Namjae Jeon:

 - several bug fixes(broken mount discard option, remount failure,
   memory leak)

 - add missing MODULE_ALIAS_FS for automatically loading exfat module.

 - set s_time_gran and truncate atime with exfat timestamp granularity.

* tag 'for-5.7-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
  exfat: truncate atimes to 2s granularity
  exfat: properly set s_time_gran
  exfat: remove 'bps' mount-option
  exfat: Unify access to the boot sector
  exfat: add missing MODULE_ALIAS_FS()
  exfat: Fix discard support
parents 3cda7799 81df1ad4
...@@ -91,7 +91,6 @@ static int exfat_allocate_bitmap(struct super_block *sb, ...@@ -91,7 +91,6 @@ static int exfat_allocate_bitmap(struct super_block *sb,
} }
} }
sbi->pbr_bh = NULL;
return 0; return 0;
} }
...@@ -137,8 +136,6 @@ void exfat_free_bitmap(struct exfat_sb_info *sbi) ...@@ -137,8 +136,6 @@ void exfat_free_bitmap(struct exfat_sb_info *sbi)
{ {
int i; int i;
brelse(sbi->pbr_bh);
for (i = 0; i < sbi->map_sectors; i++) for (i = 0; i < sbi->map_sectors; i++)
__brelse(sbi->vol_amap[i]); __brelse(sbi->vol_amap[i]);
......
...@@ -507,6 +507,7 @@ void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...) ...@@ -507,6 +507,7 @@ void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...)
__printf(3, 4) __cold; __printf(3, 4) __cold;
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 tz, __le16 time, __le16 date, u8 time_ms); u8 tz, __le16 time, __le16 date, u8 time_ms);
void exfat_truncate_atime(struct timespec64 *ts);
void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 *tz, __le16 *time, __le16 *date, u8 *time_ms); u8 *tz, __le16 *time, __le16 *date, u8 *time_ms);
unsigned short exfat_calc_chksum_2byte(void *data, int len, unsigned short exfat_calc_chksum_2byte(void *data, int len,
......
...@@ -273,6 +273,7 @@ int exfat_getattr(const struct path *path, struct kstat *stat, ...@@ -273,6 +273,7 @@ int exfat_getattr(const struct path *path, struct kstat *stat,
struct exfat_inode_info *ei = EXFAT_I(inode); struct exfat_inode_info *ei = EXFAT_I(inode);
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
exfat_truncate_atime(&stat->atime);
stat->result_mask |= STATX_BTIME; stat->result_mask |= STATX_BTIME;
stat->btime.tv_sec = ei->i_crtime.tv_sec; stat->btime.tv_sec = ei->i_crtime.tv_sec;
stat->btime.tv_nsec = ei->i_crtime.tv_nsec; stat->btime.tv_nsec = ei->i_crtime.tv_nsec;
...@@ -339,6 +340,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -339,6 +340,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr)
} }
setattr_copy(inode, attr); setattr_copy(inode, attr);
exfat_truncate_atime(&inode->i_atime);
mark_inode_dirty(inode); mark_inode_dirty(inode);
out: out:
......
...@@ -88,7 +88,8 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, ...@@ -88,7 +88,8 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
if (time_ms) { if (time_ms) {
ts->tv_sec += time_ms / 100; ts->tv_sec += time_ms / 100;
ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC; ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC;
} } else
ts->tv_nsec = 0;
if (tz & EXFAT_TZ_VALID) if (tz & EXFAT_TZ_VALID)
/* Adjust timezone to UTC0. */ /* Adjust timezone to UTC0. */
...@@ -124,6 +125,17 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, ...@@ -124,6 +125,17 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
*tz = EXFAT_TZ_VALID; *tz = EXFAT_TZ_VALID;
} }
/*
* The timestamp for access_time has double seconds granularity.
* (There is no 10msIncrement field for access_time unlike create/modify_time)
* atime also has only a 2-second resolution.
*/
void exfat_truncate_atime(struct timespec64 *ts)
{
ts->tv_sec = round_down(ts->tv_sec, 2);
ts->tv_nsec = 0;
}
unsigned short exfat_calc_chksum_2byte(void *data, int len, unsigned short exfat_calc_chksum_2byte(void *data, int len,
unsigned short chksum, int type) unsigned short chksum, int type)
{ {
......
...@@ -595,6 +595,7 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -595,6 +595,7 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
inode_inc_iversion(inode); inode_inc_iversion(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = inode->i_mtime = inode->i_atime = inode->i_ctime =
EXFAT_I(inode)->i_crtime = current_time(inode); EXFAT_I(inode)->i_crtime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
/* timestamp is already written, so mark_inode_dirty() is unneeded. */ /* timestamp is already written, so mark_inode_dirty() is unneeded. */
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
...@@ -854,6 +855,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) ...@@ -854,6 +855,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
inode_inc_iversion(dir); inode_inc_iversion(dir);
dir->i_mtime = dir->i_atime = current_time(dir); dir->i_mtime = dir->i_atime = current_time(dir);
exfat_truncate_atime(&dir->i_atime);
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
exfat_sync_inode(dir); exfat_sync_inode(dir);
else else
...@@ -861,6 +863,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) ...@@ -861,6 +863,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
clear_nlink(inode); clear_nlink(inode);
inode->i_mtime = inode->i_atime = current_time(inode); inode->i_mtime = inode->i_atime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
exfat_unhash_inode(inode); exfat_unhash_inode(inode);
exfat_d_version_set(dentry, inode_query_iversion(dir)); exfat_d_version_set(dentry, inode_query_iversion(dir));
unlock: unlock:
...@@ -903,6 +906,7 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -903,6 +906,7 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
inode_inc_iversion(inode); inode_inc_iversion(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = inode->i_mtime = inode->i_atime = inode->i_ctime =
EXFAT_I(inode)->i_crtime = current_time(inode); EXFAT_I(inode)->i_crtime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
/* timestamp is already written, so mark_inode_dirty() is unneeded. */ /* timestamp is already written, so mark_inode_dirty() is unneeded. */
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
...@@ -1019,6 +1023,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1019,6 +1023,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
inode_inc_iversion(dir); inode_inc_iversion(dir);
dir->i_mtime = dir->i_atime = current_time(dir); dir->i_mtime = dir->i_atime = current_time(dir);
exfat_truncate_atime(&dir->i_atime);
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
exfat_sync_inode(dir); exfat_sync_inode(dir);
else else
...@@ -1027,6 +1032,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1027,6 +1032,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
clear_nlink(inode); clear_nlink(inode);
inode->i_mtime = inode->i_atime = current_time(inode); inode->i_mtime = inode->i_atime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
exfat_unhash_inode(inode); exfat_unhash_inode(inode);
exfat_d_version_set(dentry, inode_query_iversion(dir)); exfat_d_version_set(dentry, inode_query_iversion(dir));
unlock: unlock:
...@@ -1387,6 +1393,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1387,6 +1393,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
inode_inc_iversion(new_dir); inode_inc_iversion(new_dir);
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime =
EXFAT_I(new_dir)->i_crtime = current_time(new_dir); EXFAT_I(new_dir)->i_crtime = current_time(new_dir);
exfat_truncate_atime(&new_dir->i_atime);
if (IS_DIRSYNC(new_dir)) if (IS_DIRSYNC(new_dir))
exfat_sync_inode(new_dir); exfat_sync_inode(new_dir);
else else
......
...@@ -49,6 +49,7 @@ static void exfat_put_super(struct super_block *sb) ...@@ -49,6 +49,7 @@ static void exfat_put_super(struct super_block *sb)
sync_blockdev(sb->s_bdev); sync_blockdev(sb->s_bdev);
exfat_set_vol_flags(sb, VOL_CLEAN); exfat_set_vol_flags(sb, VOL_CLEAN);
exfat_free_bitmap(sbi); exfat_free_bitmap(sbi);
brelse(sbi->pbr_bh);
mutex_unlock(&sbi->s_lock); mutex_unlock(&sbi->s_lock);
call_rcu(&sbi->rcu, exfat_delayed_free); call_rcu(&sbi->rcu, exfat_delayed_free);
...@@ -100,7 +101,7 @@ static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -100,7 +101,7 @@ static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag) int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag)
{ {
struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct pbr64 *bpb; struct pbr64 *bpb = (struct pbr64 *)sbi->pbr_bh->b_data;
bool sync = 0; bool sync = 0;
/* flags are not changed */ /* flags are not changed */
...@@ -115,15 +116,6 @@ int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag) ...@@ -115,15 +116,6 @@ int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag)
if (sb_rdonly(sb)) if (sb_rdonly(sb))
return 0; return 0;
if (!sbi->pbr_bh) {
sbi->pbr_bh = sb_bread(sb, 0);
if (!sbi->pbr_bh) {
exfat_msg(sb, KERN_ERR, "failed to read boot sector");
return -ENOMEM;
}
}
bpb = (struct pbr64 *)sbi->pbr_bh->b_data;
bpb->bsx.vol_flags = cpu_to_le16(new_flag); bpb->bsx.vol_flags = cpu_to_le16(new_flag);
if (new_flag == VOL_DIRTY && !buffer_dirty(sbi->pbr_bh)) if (new_flag == VOL_DIRTY && !buffer_dirty(sbi->pbr_bh))
...@@ -159,7 +151,6 @@ static int exfat_show_options(struct seq_file *m, struct dentry *root) ...@@ -159,7 +151,6 @@ static int exfat_show_options(struct seq_file *m, struct dentry *root)
seq_puts(m, ",iocharset=utf8"); seq_puts(m, ",iocharset=utf8");
else if (sbi->nls_io) else if (sbi->nls_io)
seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); seq_printf(m, ",iocharset=%s", sbi->nls_io->charset);
seq_printf(m, ",bps=%ld", sb->s_blocksize);
if (opts->errors == EXFAT_ERRORS_CONT) if (opts->errors == EXFAT_ERRORS_CONT)
seq_puts(m, ",errors=continue"); seq_puts(m, ",errors=continue");
else if (opts->errors == EXFAT_ERRORS_PANIC) else if (opts->errors == EXFAT_ERRORS_PANIC)
...@@ -351,14 +342,15 @@ static int exfat_read_root(struct inode *inode) ...@@ -351,14 +342,15 @@ static int exfat_read_root(struct inode *inode)
exfat_save_attr(inode, ATTR_SUBDIR); exfat_save_attr(inode, ATTR_SUBDIR);
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
current_time(inode); current_time(inode);
exfat_truncate_atime(&inode->i_atime);
exfat_cache_init_inode(inode); exfat_cache_init_inode(inode);
return 0; return 0;
} }
static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb, static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb)
struct buffer_head **prev_bh)
{ {
struct pbr *p_pbr = (struct pbr *) (*prev_bh)->b_data; struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct pbr *p_pbr = (struct pbr *) (sbi->pbr_bh)->b_data;
unsigned short logical_sect = 0; unsigned short logical_sect = 0;
logical_sect = 1 << p_pbr->bsx.f64.sect_size_bits; logical_sect = 1 << p_pbr->bsx.f64.sect_size_bits;
...@@ -378,26 +370,23 @@ static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb, ...@@ -378,26 +370,23 @@ static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb,
} }
if (logical_sect > sb->s_blocksize) { if (logical_sect > sb->s_blocksize) {
struct buffer_head *bh = NULL; brelse(sbi->pbr_bh);
sbi->pbr_bh = NULL;
__brelse(*prev_bh);
*prev_bh = NULL;
if (!sb_set_blocksize(sb, logical_sect)) { if (!sb_set_blocksize(sb, logical_sect)) {
exfat_msg(sb, KERN_ERR, exfat_msg(sb, KERN_ERR,
"unable to set blocksize %u", logical_sect); "unable to set blocksize %u", logical_sect);
return NULL; return NULL;
} }
bh = sb_bread(sb, 0); sbi->pbr_bh = sb_bread(sb, 0);
if (!bh) { if (!sbi->pbr_bh) {
exfat_msg(sb, KERN_ERR, exfat_msg(sb, KERN_ERR,
"unable to read boot sector (logical sector size = %lu)", "unable to read boot sector (logical sector size = %lu)",
sb->s_blocksize); sb->s_blocksize);
return NULL; return NULL;
} }
*prev_bh = bh; p_pbr = (struct pbr *)sbi->pbr_bh->b_data;
p_pbr = (struct pbr *) bh->b_data;
} }
return p_pbr; return p_pbr;
} }
...@@ -408,21 +397,20 @@ static int __exfat_fill_super(struct super_block *sb) ...@@ -408,21 +397,20 @@ static int __exfat_fill_super(struct super_block *sb)
int ret; int ret;
struct pbr *p_pbr; struct pbr *p_pbr;
struct pbr64 *p_bpb; struct pbr64 *p_bpb;
struct buffer_head *bh;
struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_sb_info *sbi = EXFAT_SB(sb);
/* set block size to read super block */ /* set block size to read super block */
sb_min_blocksize(sb, 512); sb_min_blocksize(sb, 512);
/* read boot sector */ /* read boot sector */
bh = sb_bread(sb, 0); sbi->pbr_bh = sb_bread(sb, 0);
if (!bh) { if (!sbi->pbr_bh) {
exfat_msg(sb, KERN_ERR, "unable to read boot sector"); exfat_msg(sb, KERN_ERR, "unable to read boot sector");
return -EIO; return -EIO;
} }
/* PRB is read */ /* PRB is read */
p_pbr = (struct pbr *)bh->b_data; p_pbr = (struct pbr *)sbi->pbr_bh->b_data;
/* check the validity of PBR */ /* check the validity of PBR */
if (le16_to_cpu((p_pbr->signature)) != PBR_SIGNATURE) { if (le16_to_cpu((p_pbr->signature)) != PBR_SIGNATURE) {
...@@ -433,7 +421,7 @@ static int __exfat_fill_super(struct super_block *sb) ...@@ -433,7 +421,7 @@ static int __exfat_fill_super(struct super_block *sb)
/* check logical sector size */ /* check logical sector size */
p_pbr = exfat_read_pbr_with_logical_sector(sb, &bh); p_pbr = exfat_read_pbr_with_logical_sector(sb);
if (!p_pbr) { if (!p_pbr) {
ret = -EIO; ret = -EIO;
goto free_bh; goto free_bh;
...@@ -514,7 +502,7 @@ static int __exfat_fill_super(struct super_block *sb) ...@@ -514,7 +502,7 @@ static int __exfat_fill_super(struct super_block *sb)
free_upcase_table: free_upcase_table:
exfat_free_upcase_table(sbi); exfat_free_upcase_table(sbi);
free_bh: free_bh:
brelse(bh); brelse(sbi->pbr_bh);
return ret; return ret;
} }
...@@ -531,17 +519,18 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -531,17 +519,18 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
if (opts->discard) { if (opts->discard) {
struct request_queue *q = bdev_get_queue(sb->s_bdev); struct request_queue *q = bdev_get_queue(sb->s_bdev);
if (!blk_queue_discard(q)) if (!blk_queue_discard(q)) {
exfat_msg(sb, KERN_WARNING, exfat_msg(sb, KERN_WARNING,
"mounting with \"discard\" option, but the device does not support discard"); "mounting with \"discard\" option, but the device does not support discard");
opts->discard = 0; opts->discard = 0;
}
} }
sb->s_flags |= SB_NODIRATIME; sb->s_flags |= SB_NODIRATIME;
sb->s_magic = EXFAT_SUPER_MAGIC; sb->s_magic = EXFAT_SUPER_MAGIC;
sb->s_op = &exfat_sops; sb->s_op = &exfat_sops;
sb->s_time_gran = 1; sb->s_time_gran = 10 * NSEC_PER_MSEC;
sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS; sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS;
sb->s_time_max = EXFAT_MAX_TIMESTAMP_SECS; sb->s_time_max = EXFAT_MAX_TIMESTAMP_SECS;
...@@ -605,6 +594,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -605,6 +594,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
free_table: free_table:
exfat_free_upcase_table(sbi); exfat_free_upcase_table(sbi);
exfat_free_bitmap(sbi); exfat_free_bitmap(sbi);
brelse(sbi->pbr_bh);
check_nls_io: check_nls_io:
unload_nls(sbi->nls_io); unload_nls(sbi->nls_io);
...@@ -717,6 +707,7 @@ static void __exit exit_exfat_fs(void) ...@@ -717,6 +707,7 @@ static void __exit exit_exfat_fs(void)
module_init(init_exfat_fs); module_init(init_exfat_fs);
module_exit(exit_exfat_fs); module_exit(exit_exfat_fs);
MODULE_ALIAS_FS("exfat");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("exFAT filesystem support"); MODULE_DESCRIPTION("exFAT filesystem support");
MODULE_AUTHOR("Samsung Electronics Co., Ltd."); MODULE_AUTHOR("Samsung Electronics Co., Ltd.");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment