diff mbox series

[v1,2/2] exfat: support create zero-size directory

Message ID PUZPR04MB631677F6E573FC9062A2BF2981E7A@PUZPR04MB6316.apcprd04.prod.outlook.com (mailing list archive)
State New, archived
Headers show
Series exfat: support zero-size directory | expand

Commit Message

Yuezhang.Mo@sony.com Aug. 29, 2023, 4:50 a.m. UTC
This commit adds mount option 'zero_size_dir'. If this option
enabled, don't allocate a cluster to directory when creating
it, and set the directory size to 0.

On Windows, a cluster is allocated for a directory when it is
created, so the mount option is disabled by default.

Signed-off-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
Reviewed-by: Andy Wu <Andy.Wu@sony.com>
Reviewed-by: Aoyama Wataru <wataru.aoyama@sony.com>
---
 fs/exfat/dir.c      | 12 ++++++------
 fs/exfat/exfat_fs.h |  2 ++
 fs/exfat/namei.c    |  7 +++++--
 fs/exfat/super.c    |  7 +++++++
 4 files changed, 20 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
index 598081d0d059..9ad5ff01456e 100644
--- a/fs/exfat/dir.c
+++ b/fs/exfat/dir.c
@@ -417,11 +417,13 @@  static void exfat_set_entry_type(struct exfat_dentry *ep, unsigned int type)
 }
 
 static void exfat_init_stream_entry(struct exfat_dentry *ep,
-		unsigned char flags, unsigned int start_clu,
-		unsigned long long size)
+		unsigned int start_clu, unsigned long long size)
 {
 	exfat_set_entry_type(ep, TYPE_STREAM);
-	ep->dentry.stream.flags = flags;
+	if (size == 0)
+		ep->dentry.stream.flags = ALLOC_FAT_CHAIN;
+	else
+		ep->dentry.stream.flags = ALLOC_NO_FAT_CHAIN;
 	ep->dentry.stream.start_clu = cpu_to_le32(start_clu);
 	ep->dentry.stream.valid_size = cpu_to_le64(size);
 	ep->dentry.stream.size = cpu_to_le64(size);
@@ -487,9 +489,7 @@  int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir,
 	if (!ep)
 		return -EIO;
 
-	exfat_init_stream_entry(ep,
-		(type == TYPE_FILE) ? ALLOC_FAT_CHAIN : ALLOC_NO_FAT_CHAIN,
-		start_clu, size);
+	exfat_init_stream_entry(ep, start_clu, size);
 	exfat_update_bh(bh, IS_DIRSYNC(inode));
 	brelse(bh);
 
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index 729ada9e26e8..cbf32949ff67 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -234,6 +234,8 @@  struct exfat_mount_options {
 		 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) */
+	/* Support creating zero-size directory, default: false */
+	bool zero_size_dir;
 };
 
 /*
diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c
index 43774693f65f..23220dd874e3 100644
--- a/fs/exfat/namei.c
+++ b/fs/exfat/namei.c
@@ -518,7 +518,7 @@  static int exfat_add_entry(struct inode *inode, const char *path,
 		goto out;
 	}
 
-	if (type == TYPE_DIR) {
+	if (type == TYPE_DIR && !sbi->options.zero_size_dir) {
 		ret = exfat_alloc_new_dir(inode, &clu);
 		if (ret)
 			goto out;
@@ -551,7 +551,10 @@  static int exfat_add_entry(struct inode *inode, const char *path,
 		info->num_subdirs = 0;
 	} else {
 		info->attr = ATTR_SUBDIR;
-		info->start_clu = start_clu;
+		if (sbi->options.zero_size_dir)
+			info->start_clu = EXFAT_EOF_CLUSTER;
+		else
+			info->start_clu = start_clu;
 		info->size = clu_size;
 		info->num_subdirs = EXFAT_MIN_SUBDIR;
 	}
diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index 8c32460e031e..b1e03276e0a0 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -174,6 +174,8 @@  static int exfat_show_options(struct seq_file *m, struct dentry *root)
 		seq_puts(m, ",sys_tz");
 	else if (opts->time_offset)
 		seq_printf(m, ",time_offset=%d", opts->time_offset);
+	if (opts->zero_size_dir)
+		seq_puts(m, ",zero_size_dir");
 	return 0;
 }
 
@@ -218,6 +220,7 @@  enum {
 	Opt_keep_last_dots,
 	Opt_sys_tz,
 	Opt_time_offset,
+	Opt_zero_size_dir,
 
 	/* Deprecated options */
 	Opt_utf8,
@@ -246,6 +249,7 @@  static const struct fs_parameter_spec exfat_parameters[] = {
 	fsparam_flag("keep_last_dots",		Opt_keep_last_dots),
 	fsparam_flag("sys_tz",			Opt_sys_tz),
 	fsparam_s32("time_offset",		Opt_time_offset),
+	fsparam_flag("zero_size_dir",		Opt_zero_size_dir),
 	__fsparam(NULL, "utf8",			Opt_utf8, fs_param_deprecated,
 		  NULL),
 	__fsparam(NULL, "debug",		Opt_debug, fs_param_deprecated,
@@ -314,6 +318,9 @@  static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param)
 			return -EINVAL;
 		opts->time_offset = result.int_32;
 		break;
+	case Opt_zero_size_dir:
+		opts->zero_size_dir = true;
+		break;
 	case Opt_utf8:
 	case Opt_debug:
 	case Opt_namecase: