Commit 850f6033 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull exfat updates from Namjae Jeon:

 - fix referencing wrong parent directory information during rename

 - introduce a sys_tz mount option to use system timezone

 - improve performance while zeroing a cluster with dirsync mount option

 - fix slab-out-bounds in exat_clear_bitmap() reported from syzbot

* tag 'exfat-for-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
  exfat: check if cluster num is valid
  exfat: reduce block requests when zeroing a cluster
  block: add sync_blockdev_range()
  exfat: introduce mount option 'sys_tz'
  exfat: fix referencing wrong parent directory information after renaming
parents f30fabe7 64ba4b15
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -200,6 +200,13 @@ int sync_blockdev(struct block_device *bdev)
}
EXPORT_SYMBOL(sync_blockdev);

int sync_blockdev_range(struct block_device *bdev, loff_t lstart, loff_t lend)
{
	return filemap_write_and_wait_range(bdev->bd_inode->i_mapping,
			lstart, lend);
}
EXPORT_SYMBOL(sync_blockdev_range);

/*
 * Write out and wait upon all dirty data associated with this
 * device.   Filesystem data as well as the underlying block
+6 −2
Original line number Diff line number Diff line
@@ -148,7 +148,9 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync)
	struct super_block *sb = inode->i_sb;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);

	WARN_ON(clu < EXFAT_FIRST_CLUSTER);
	if (!is_valid_cluster(sbi, clu))
		return -EINVAL;

	ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
	i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
	b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
@@ -166,7 +168,9 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync)
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct exfat_mount_options *opts = &sbi->options;

	WARN_ON(clu < EXFAT_FIRST_CLUSTER);
	if (!is_valid_cluster(sbi, clu))
		return;

	ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
	i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
	b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
+7 −0
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ struct exfat_mount_options {
	/* on error: continue, panic, remount-ro */
	enum exfat_error_mode errors;
	unsigned utf8:1, /* Use of UTF-8 character set */
		 sys_tz:1, /* Use local timezone */
		 discard:1, /* Issue discard requests on deletions */
		 keep_last_dots:1; /* Keep trailing periods in paths */
	int time_offset; /* Offset of timestamps from UTC (in minutes) */
@@ -381,6 +382,12 @@ static inline int exfat_sector_to_cluster(struct exfat_sb_info *sbi,
		EXFAT_RESERVED_CLUSTERS;
}

static inline bool is_valid_cluster(struct exfat_sb_info *sbi,
		unsigned int clus)
{
	return clus >= EXFAT_FIRST_CLUSTER && clus < sbi->num_clusters;
}

/* super.c */
int exfat_set_volume_dirty(struct super_block *sb);
int exfat_clear_volume_dirty(struct super_block *sb);
+17 −30
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <linux/buffer_head.h>
#include <linux/blkdev.h>

#include "exfat_raw.h"
#include "exfat_fs.h"
@@ -81,12 +82,6 @@ int exfat_ent_set(struct super_block *sb, unsigned int loc,
	return 0;
}

static inline bool is_valid_cluster(struct exfat_sb_info *sbi,
		unsigned int clus)
{
	return clus >= EXFAT_FIRST_CLUSTER && clus < sbi->num_clusters;
}

int exfat_ent_get(struct super_block *sb, unsigned int loc,
		unsigned int *content)
{
@@ -274,10 +269,9 @@ int exfat_zeroed_cluster(struct inode *dir, unsigned int clu)
{
	struct super_block *sb = dir->i_sb;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
	int nr_bhs = MAX_BUF_PER_PAGE;
	struct buffer_head *bh;
	sector_t blknr, last_blknr;
	int err, i, n;
	int i;

	blknr = exfat_cluster_to_sector(sbi, clu);
	last_blknr = blknr + sbi->sect_per_clus;
@@ -291,30 +285,23 @@ int exfat_zeroed_cluster(struct inode *dir, unsigned int clu)
	}

	/* Zeroing the unused blocks on this cluster */
	while (blknr < last_blknr) {
		for (n = 0; n < nr_bhs && blknr < last_blknr; n++, blknr++) {
			bhs[n] = sb_getblk(sb, blknr);
			if (!bhs[n]) {
				err = -ENOMEM;
				goto release_bhs;
			}
			memset(bhs[n]->b_data, 0, sb->s_blocksize);
	for (i = blknr; i < last_blknr; i++) {
		bh = sb_getblk(sb, i);
		if (!bh)
			return -ENOMEM;

		memset(bh->b_data, 0, sb->s_blocksize);
		set_buffer_uptodate(bh);
		mark_buffer_dirty(bh);
		brelse(bh);
	}

		err = exfat_update_bhs(bhs, n, IS_DIRSYNC(dir));
		if (err)
			goto release_bhs;
	if (IS_DIRSYNC(dir))
		return sync_blockdev_range(sb->s_bdev,
				EXFAT_BLK_TO_B(blknr, sb),
				EXFAT_BLK_TO_B(last_blknr, sb) - 1);

		for (i = 0; i < n; i++)
			brelse(bhs[i]);
	}
	return 0;

release_bhs:
	exfat_err(sb, "failed zeroed sect %llu\n", (unsigned long long)blknr);
	for (i = 0; i < n; i++)
		bforget(bhs[i]);
	return err;
}

int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
+8 −2
Original line number Diff line number Diff line
@@ -74,6 +74,13 @@ static void exfat_adjust_tz(struct timespec64 *ts, u8 tz_off)
		ts->tv_sec += TIMEZONE_SEC(0x80 - tz_off);
}

static inline int exfat_tz_offset(struct exfat_sb_info *sbi)
{
	if (sbi->options.sys_tz)
		return -sys_tz.tz_minuteswest;
	return sbi->options.time_offset;
}

/* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
		u8 tz, __le16 time, __le16 date, u8 time_cs)
@@ -96,8 +103,7 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
		/* Adjust timezone to UTC0. */
		exfat_adjust_tz(ts, tz & ~EXFAT_TZ_VALID);
	else
		/* Convert from local time to UTC using time_offset. */
		ts->tv_sec -= sbi->options.time_offset * SECS_PER_MIN;
		ts->tv_sec -= exfat_tz_offset(sbi) * SECS_PER_MIN;
}

/* Convert linear UNIX date to a EXFAT time/date pair. */
Loading