summaryrefslogtreecommitdiff
path: root/fs/exfat
diff options
context:
space:
mode:
authorYuezhang Mo <Yuezhang.Mo@sony.com>2023-07-20 14:40:08 +0800
committerNamjae Jeon <linkinjeon@kernel.org>2023-10-31 10:01:45 +0900
commitee785c15b5906a69d4007b4754e8ae40fb41e0b4 (patch)
treed5960f2815f9fa05ae3310aadad0670aebee52a4 /fs/exfat
parentdab48b8f2fe7264d51ec9eed0adea0fe3c78830a (diff)
exfat: support create zero-size directory
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> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Diffstat (limited to 'fs/exfat')
-rw-r--r--fs/exfat/dir.c12
-rw-r--r--fs/exfat/exfat_fs.h2
-rw-r--r--fs/exfat/namei.c7
-rw-r--r--fs/exfat/super.c7
4 files changed, 20 insertions, 8 deletions
diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
index fdd46aa466e1..9f9295847a4e 100644
--- a/fs/exfat/dir.c
+++ b/fs/exfat/dir.c
@@ -418,11 +418,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);
@@ -488,9 +490,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 99208902883b..a7a2c35d74fb 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 1e9c945130f4..5d737e0b639a 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 = EXFAT_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 ecee1664ab7f..d9d4fa91010b 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -165,6 +165,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;
}
@@ -209,6 +211,7 @@ enum {
Opt_keep_last_dots,
Opt_sys_tz,
Opt_time_offset,
+ Opt_zero_size_dir,
/* Deprecated options */
Opt_utf8,
@@ -237,6 +240,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,
@@ -305,6 +309,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: