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,
}
}
sbi->pbr_bh = NULL;
return 0;
}
......@@ -137,8 +136,6 @@ void exfat_free_bitmap(struct exfat_sb_info *sbi)
{
int i;
brelse(sbi->pbr_bh);
for (i = 0; i < sbi->map_sectors; i++)
__brelse(sbi->vol_amap[i]);
......
......@@ -507,6 +507,7 @@ void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...)
__printf(3, 4) __cold;
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
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,
u8 *tz, __le16 *time, __le16 *date, u8 *time_ms);
unsigned short exfat_calc_chksum_2byte(void *data, int len,
......
......@@ -273,6 +273,7 @@ int exfat_getattr(const struct path *path, struct kstat *stat,
struct exfat_inode_info *ei = EXFAT_I(inode);
generic_fillattr(inode, stat);
exfat_truncate_atime(&stat->atime);
stat->result_mask |= STATX_BTIME;
stat->btime.tv_sec = ei->i_crtime.tv_sec;
stat->btime.tv_nsec = ei->i_crtime.tv_nsec;
......@@ -339,6 +340,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr)
}
setattr_copy(inode, attr);
exfat_truncate_atime(&inode->i_atime);
mark_inode_dirty(inode);
out:
......
......@@ -88,7 +88,8 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
if (time_ms) {
ts->tv_sec += time_ms / 100;
ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC;
}
} else
ts->tv_nsec = 0;
if (tz & EXFAT_TZ_VALID)
/* Adjust timezone to UTC0. */
......@@ -124,6 +125,17 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
*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 chksum, int type)
{
......
......@@ -595,6 +595,7 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
inode_inc_iversion(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime =
EXFAT_I(inode)->i_crtime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
d_instantiate(dentry, inode);
......@@ -854,6 +855,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
inode_inc_iversion(dir);
dir->i_mtime = dir->i_atime = current_time(dir);
exfat_truncate_atime(&dir->i_atime);
if (IS_DIRSYNC(dir))
exfat_sync_inode(dir);
else
......@@ -861,6 +863,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
clear_nlink(inode);
inode->i_mtime = inode->i_atime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
exfat_unhash_inode(inode);
exfat_d_version_set(dentry, inode_query_iversion(dir));
unlock:
......@@ -903,6 +906,7 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
inode_inc_iversion(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime =
EXFAT_I(inode)->i_crtime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
d_instantiate(dentry, inode);
......@@ -1019,6 +1023,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
inode_inc_iversion(dir);
dir->i_mtime = dir->i_atime = current_time(dir);
exfat_truncate_atime(&dir->i_atime);
if (IS_DIRSYNC(dir))
exfat_sync_inode(dir);
else
......@@ -1027,6 +1032,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
clear_nlink(inode);
inode->i_mtime = inode->i_atime = current_time(inode);
exfat_truncate_atime(&inode->i_atime);
exfat_unhash_inode(inode);
exfat_d_version_set(dentry, inode_query_iversion(dir));
unlock:
......@@ -1387,6 +1393,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
inode_inc_iversion(new_dir);
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime =
EXFAT_I(new_dir)->i_crtime = current_time(new_dir);
exfat_truncate_atime(&new_dir->i_atime);
if (IS_DIRSYNC(new_dir))
exfat_sync_inode(new_dir);
else
......
......@@ -49,6 +49,7 @@ static void exfat_put_super(struct super_block *sb)
sync_blockdev(sb->s_bdev);
exfat_set_vol_flags(sb, VOL_CLEAN);
exfat_free_bitmap(sbi);
brelse(sbi->pbr_bh);
mutex_unlock(&sbi->s_lock);
call_rcu(&sbi->rcu, exfat_delayed_free);
......@@ -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)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct pbr64 *bpb;
struct pbr64 *bpb = (struct pbr64 *)sbi->pbr_bh->b_data;
bool sync = 0;
/* flags are not changed */
......@@ -115,15 +116,6 @@ int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag)
if (sb_rdonly(sb))
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);
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)
seq_puts(m, ",iocharset=utf8");
else if (sbi->nls_io)
seq_printf(m, ",iocharset=%s", sbi->nls_io->charset);
seq_printf(m, ",bps=%ld", sb->s_blocksize);
if (opts->errors == EXFAT_ERRORS_CONT)
seq_puts(m, ",errors=continue");
else if (opts->errors == EXFAT_ERRORS_PANIC)
......@@ -351,14 +342,15 @@ static int exfat_read_root(struct inode *inode)
exfat_save_attr(inode, ATTR_SUBDIR);
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
current_time(inode);
exfat_truncate_atime(&inode->i_atime);
exfat_cache_init_inode(inode);
return 0;
}
static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb,
struct buffer_head **prev_bh)
static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb)
{
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;
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,
}
if (logical_sect > sb->s_blocksize) {
struct buffer_head *bh = NULL;
__brelse(*prev_bh);
*prev_bh = NULL;
brelse(sbi->pbr_bh);
sbi->pbr_bh = NULL;
if (!sb_set_blocksize(sb, logical_sect)) {
exfat_msg(sb, KERN_ERR,
"unable to set blocksize %u", logical_sect);
return NULL;
}
bh = sb_bread(sb, 0);
if (!bh) {
sbi->pbr_bh = sb_bread(sb, 0);
if (!sbi->pbr_bh) {
exfat_msg(sb, KERN_ERR,
"unable to read boot sector (logical sector size = %lu)",
sb->s_blocksize);
return NULL;
}
*prev_bh = bh;
p_pbr = (struct pbr *) bh->b_data;
p_pbr = (struct pbr *)sbi->pbr_bh->b_data;
}
return p_pbr;
}
......@@ -408,21 +397,20 @@ static int __exfat_fill_super(struct super_block *sb)
int ret;
struct pbr *p_pbr;
struct pbr64 *p_bpb;
struct buffer_head *bh;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
/* set block size to read super block */
sb_min_blocksize(sb, 512);
/* read boot sector */
bh = sb_bread(sb, 0);
if (!bh) {
sbi->pbr_bh = sb_bread(sb, 0);
if (!sbi->pbr_bh) {
exfat_msg(sb, KERN_ERR, "unable to read boot sector");
return -EIO;
}
/* PRB is read */
p_pbr = (struct pbr *)bh->b_data;
p_pbr = (struct pbr *)sbi->pbr_bh->b_data;
/* check the validity of PBR */
if (le16_to_cpu((p_pbr->signature)) != PBR_SIGNATURE) {
......@@ -433,7 +421,7 @@ static int __exfat_fill_super(struct super_block *sb)
/* 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) {
ret = -EIO;
goto free_bh;
......@@ -514,7 +502,7 @@ static int __exfat_fill_super(struct super_block *sb)
free_upcase_table:
exfat_free_upcase_table(sbi);
free_bh:
brelse(bh);
brelse(sbi->pbr_bh);
return ret;
}
......@@ -531,17 +519,18 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
if (opts->discard) {
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,
"mounting with \"discard\" option, but the device does not support discard");
opts->discard = 0;
opts->discard = 0;
}
}
sb->s_flags |= SB_NODIRATIME;
sb->s_magic = EXFAT_SUPER_MAGIC;
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_max = EXFAT_MAX_TIMESTAMP_SECS;
......@@ -605,6 +594,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
free_table:
exfat_free_upcase_table(sbi);
exfat_free_bitmap(sbi);
brelse(sbi->pbr_bh);
check_nls_io:
unload_nls(sbi->nls_io);
......@@ -717,6 +707,7 @@ static void __exit exit_exfat_fs(void)
module_init(init_exfat_fs);
module_exit(exit_exfat_fs);
MODULE_ALIAS_FS("exfat");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("exFAT filesystem support");
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