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

 - fix the error code of rename syscall

 - cleanup and suppress the superfluous error messages

 - remove duplicate directory entry update

 - add exfat git tree in MAINTAINERS

* tag 'exfat-for-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
  MAINTAINERS: Add Namjae's exfat git tree
  exfat: Drop superfluous new line for error messages
  exfat: Downgrade ENAMETOOLONG error message to debug messages
  exfat: Expand exfat_err() and co directly to pr_*() macro
  exfat: Define NLS_NAME_* as bit flags explicitly
  exfat: Return ENAMETOOLONG consistently for oversized paths
  exfat: remove duplicate write inode for extending dir/file
  exfat: remove duplicate write inode for truncating file
  exfat: reuse __exfat_write_inode() to update directory entry
parents e2ebff9c df13a347
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7690,6 +7690,7 @@ M: Namjae Jeon <linkinjeon@kernel.org>
M:	Sungjong Seo <sj1557.seo@samsung.com>
L:	linux-fsdevel@vger.kernel.org
S:	Maintained
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat.git
F:	fs/exfat/
EXT2 FILE SYSTEM
+11 −8
Original line number Diff line number Diff line
@@ -27,9 +27,9 @@ enum exfat_error_mode {
 * exfat nls lossy flag
 */
enum {
	NLS_NAME_NO_LOSSY,	/* no lossy */
	NLS_NAME_LOSSY,		/* just detected incorrect filename(s) */
	NLS_NAME_OVERLEN,	/* the length is over than its limit */
	NLS_NAME_NO_LOSSY =	0,	/* no lossy */
	NLS_NAME_LOSSY =	1 << 0,	/* just detected incorrect filename(s) */
	NLS_NAME_OVERLEN =	1 << 1,	/* the length is over than its limit */
};

#define EXFAT_HASH_BITS		8
@@ -483,6 +483,7 @@ struct inode *exfat_build_inode(struct super_block *sb,
void exfat_hash_inode(struct inode *inode, loff_t i_pos);
void exfat_unhash_inode(struct inode *inode);
struct inode *exfat_iget(struct super_block *sb, loff_t i_pos);
int __exfat_write_inode(struct inode *inode, int sync);
int exfat_write_inode(struct inode *inode, struct writeback_control *wbc);
void exfat_evict_inode(struct inode *inode);
int exfat_block_truncate_page(struct inode *inode, loff_t from);
@@ -508,14 +509,16 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
#define exfat_fs_error_ratelimit(sb, fmt, args...) \
		__exfat_fs_error(sb, __ratelimit(&EXFAT_SB(sb)->ratelimit), \
		fmt, ## args)
void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...)
		__printf(3, 4) __cold;

/* expand to pr_*() with prefix */
#define exfat_err(sb, fmt, ...)						\
	exfat_msg(sb, KERN_ERR, fmt, ##__VA_ARGS__)
	pr_err("exFAT-fs (%s): " fmt "\n", (sb)->s_id, ##__VA_ARGS__)
#define exfat_warn(sb, fmt, ...)					\
	exfat_msg(sb, KERN_WARNING, fmt, ##__VA_ARGS__)
	pr_warn("exFAT-fs (%s): " fmt "\n", (sb)->s_id, ##__VA_ARGS__)
#define exfat_info(sb, fmt, ...)					\
	exfat_msg(sb, KERN_INFO, fmt, ##__VA_ARGS__)
	pr_info("exFAT-fs (%s): " fmt "\n", (sb)->s_id, ##__VA_ARGS__)
#define exfat_debug(sb, fmt, ...)					\
	pr_debug("exFAT-fs (%s): " fmt "\n", (sb)->s_id, ##__VA_ARGS__)

void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
		u8 tz, __le16 time, __le16 date, u8 time_cs);
+1 −1
Original line number Diff line number Diff line
@@ -331,7 +331,7 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
	/* find new cluster */
	if (hint_clu == EXFAT_EOF_CLUSTER) {
		if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) {
			exfat_err(sb, "sbi->clu_srch_ptr is invalid (%u)\n",
			exfat_err(sb, "sbi->clu_srch_ptr is invalid (%u)",
				  sbi->clu_srch_ptr);
			sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER;
		}
+26 −56
Original line number Diff line number Diff line
@@ -101,7 +101,6 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
	struct super_block *sb = inode->i_sb;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct exfat_inode_info *ei = EXFAT_I(inode);
	int evict = (ei->dir.dir == DIR_DELETED) ? 1 : 0;

	/* check if the given file ID is opened */
	if (ei->type != TYPE_FILE && ei->type != TYPE_DIR)
@@ -149,50 +148,19 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
	if (ei->type == TYPE_FILE)
		ei->attr |= ATTR_ARCHIVE;

	/* update the directory entry */
	if (!evict) {
		struct timespec64 ts;
		struct exfat_dentry *ep, *ep2;
		struct exfat_entry_set_cache *es;
		int err;

		es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry,
				ES_ALL_ENTRIES);
		if (!es)
	/*
	 * update the directory entry
	 *
	 * If the directory entry is updated by mark_inode_dirty(), the
	 * directory entry will be written after a writeback cycle of
	 * updating the bitmap/FAT, which may result in clusters being
	 * freed but referenced by the directory entry in the event of a
	 * sudden power failure.
	 * __exfat_write_inode() is called for directory entry, bitmap
	 * and FAT to be written in a same writeback.
	 */
	if (__exfat_write_inode(inode, inode_needs_sync(inode)))
		return -EIO;
		ep = exfat_get_dentry_cached(es, 0);
		ep2 = exfat_get_dentry_cached(es, 1);

		ts = current_time(inode);
		exfat_set_entry_time(sbi, &ts,
				&ep->dentry.file.modify_tz,
				&ep->dentry.file.modify_time,
				&ep->dentry.file.modify_date,
				&ep->dentry.file.modify_time_cs);
		ep->dentry.file.attr = cpu_to_le16(ei->attr);

		/* File size should be zero if there is no cluster allocated */
		if (ei->start_clu == EXFAT_EOF_CLUSTER) {
			ep2->dentry.stream.valid_size = 0;
			ep2->dentry.stream.size = 0;
		} else {
			ep2->dentry.stream.valid_size = cpu_to_le64(new_size);
			ep2->dentry.stream.size = ep2->dentry.stream.valid_size;
		}

		if (new_size == 0) {
			/* Any directory can not be truncated to zero */
			WARN_ON(ei->type != TYPE_FILE);

			ep2->dentry.stream.flags = ALLOC_FAT_CHAIN;
			ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER;
		}

		exfat_update_dir_chksum_with_entry_set(es);
		err = exfat_free_dentry_set(es, inode_needs_sync(inode));
		if (err)
			return err;
	}

	/* cut off from the FAT chain */
	if (ei->flags == ALLOC_FAT_CHAIN && last_clu != EXFAT_FREE_CLUSTER &&
@@ -243,12 +211,6 @@ void exfat_truncate(struct inode *inode, loff_t size)
	if (err)
		goto write_size;

	inode->i_ctime = inode->i_mtime = current_time(inode);
	if (IS_DIRSYNC(inode))
		exfat_sync_inode(inode);
	else
		mark_inode_dirty(inode);

	inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >>
				inode->i_blkbits;
write_size:
@@ -330,6 +292,12 @@ int exfat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
			attr->ia_valid &= ~ATTR_MODE;
	}

	if (attr->ia_valid & ATTR_SIZE)
		inode->i_mtime = inode->i_ctime = current_time(inode);

	setattr_copy(&init_user_ns, inode, attr);
	exfat_truncate_atime(&inode->i_atime);

	if (attr->ia_valid & ATTR_SIZE) {
		error = exfat_block_truncate_page(inode, attr->ia_size);
		if (error)
@@ -337,12 +305,14 @@ int exfat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,

		down_write(&EXFAT_I(inode)->truncate_lock);
		truncate_setsize(inode, attr->ia_size);

		/*
		 * __exfat_write_inode() is called from exfat_truncate(), inode
		 * is already written by it, so mark_inode_dirty() is unneeded.
		 */
		exfat_truncate(inode, attr->ia_size);
		up_write(&EXFAT_I(inode)->truncate_lock);
	}

	setattr_copy(&init_user_ns, inode, attr);
	exfat_truncate_atime(&inode->i_atime);
	} else
		mark_inode_dirty(inode);

out:
+10 −31
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
#include "exfat_raw.h"
#include "exfat_fs.h"

static int __exfat_write_inode(struct inode *inode, int sync)
int __exfat_write_inode(struct inode *inode, int sync)
{
	unsigned long long on_disk_size;
	struct exfat_dentry *ep, *ep2;
@@ -75,6 +75,13 @@ static int __exfat_write_inode(struct inode *inode, int sync)

	ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size);
	ep2->dentry.stream.size = ep2->dentry.stream.valid_size;
	if (on_disk_size) {
		ep2->dentry.stream.flags = ei->flags;
		ep2->dentry.stream.start_clu = cpu_to_le32(ei->start_clu);
	} else {
		ep2->dentry.stream.flags = ALLOC_FAT_CHAIN;
		ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER;
	}

	exfat_update_dir_chksum_with_entry_set(es);
	return exfat_free_dentry_set(es, sync);
@@ -105,7 +112,7 @@ void exfat_sync_inode(struct inode *inode)
static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
		unsigned int *clu, int create)
{
	int ret, modified = false;
	int ret;
	unsigned int last_clu;
	struct exfat_chain new_clu;
	struct super_block *sb = inode->i_sb;
@@ -196,7 +203,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
			if (new_clu.flags == ALLOC_FAT_CHAIN)
				ei->flags = ALLOC_FAT_CHAIN;
			ei->start_clu = new_clu.dir;
			modified = true;
		} else {
			if (new_clu.flags != ei->flags) {
				/* no-fat-chain bit is disabled,
@@ -206,7 +212,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
				exfat_chain_cont_cluster(sb, ei->start_clu,
					num_clusters);
				ei->flags = ALLOC_FAT_CHAIN;
				modified = true;
			}
			if (new_clu.flags == ALLOC_FAT_CHAIN)
				if (exfat_ent_set(sb, last_clu, new_clu.dir))
@@ -216,33 +221,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
		num_clusters += num_to_be_allocated;
		*clu = new_clu.dir;

		if (ei->dir.dir != DIR_DELETED && modified) {
			struct exfat_dentry *ep;
			struct exfat_entry_set_cache *es;
			int err;

			es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry,
				ES_ALL_ENTRIES);
			if (!es)
				return -EIO;
			/* get stream entry */
			ep = exfat_get_dentry_cached(es, 1);

			/* update directory entry */
			ep->dentry.stream.flags = ei->flags;
			ep->dentry.stream.start_clu =
				cpu_to_le32(ei->start_clu);
			ep->dentry.stream.valid_size =
				cpu_to_le64(i_size_read(inode));
			ep->dentry.stream.size =
				ep->dentry.stream.valid_size;

			exfat_update_dir_chksum_with_entry_set(es);
			err = exfat_free_dentry_set(es, inode_needs_sync(inode));
			if (err)
				return err;
		} /* end of if != DIR_DELETED */

		inode->i_blocks +=
			num_to_be_allocated << sbi->sect_per_clus_bits;

@@ -384,6 +362,7 @@ static void exfat_write_failed(struct address_space *mapping, loff_t to)

	if (to > i_size_read(inode)) {
		truncate_pagecache(inode, i_size_read(inode));
		inode->i_mtime = inode->i_ctime = current_time(inode);
		exfat_truncate(inode, EXFAT_I(inode)->i_size_aligned);
	}
}
Loading