Skip to content

Commit 5aba543

Browse files
drosen-googleJaegeuk Kim
authored andcommitted
f2fs: include charset encoding information in the superblock
Add charset encoding to f2fs to support casefolding. It is modeled after the same feature introduced in commit c83ad55 ("ext4: include charset encoding information in the superblock") Currently this is not compatible with encryption, similar to the current ext4 imlpementation. This will change in the future. >From the ext4 patch: """ The s_encoding field stores a magic number indicating the encoding format and version used globally by file and directory names in the filesystem. The s_encoding_flags defines policies for using the charset encoding, like how to handle invalid sequences. The magic number is mapped to the exact charset table, but the mapping is specific to ext4. Since we don't have any commitment to support old encodings, the only encoding I am supporting right now is utf8-12.1.0. The current implementation prevents the user from enabling encoding and per-directory encryption on the same filesystem at the same time. The incompatibility between these features lies in how we do efficient directory searches when we cannot be sure the encryption of the user provided fname will match the actual hash stored in the disk without decrypting every directory entry, because of normalization cases. My quickest solution is to simply block the concurrent use of these features for now, and enable it later, once we have a better solution. """ Signed-off-by: Daniel Rosenberg <[email protected]> Reviewed-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent 71e90b4 commit 5aba543

File tree

6 files changed

+142
-1
lines changed

6 files changed

+142
-1
lines changed

Documentation/ABI/testing/sysfs-fs-f2fs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,10 @@ Description:
251251
If checkpoint=disable, it displays the number of blocks that are unusable.
252252
If checkpoint=enable it displays the enumber of blocks that would be unusable
253253
if checkpoint=disable were to be set.
254+
255+
What: /sys/fs/f2fs/<disk>/encoding
256+
Date July 2019
257+
Contact: "Daniel Rosenberg" <[email protected]>
258+
Description:
259+
Displays name and version of the encoding set for the filesystem.
260+
If no encoding is set, displays (none)

Documentation/filesystems/f2fs.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,9 @@ Files in /sys/fs/f2fs/<devname>
413413
that would be unusable if checkpoint=disable were
414414
to be set.
415415

416+
encoding This shows the encoding used for casefolding.
417+
If casefolding is not enabled, returns (none)
418+
416419
================================================================================
417420
USAGE
418421
================================================================================

fs/f2fs/f2fs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ struct f2fs_mount_info {
153153
#define F2FS_FEATURE_LOST_FOUND 0x0200
154154
#define F2FS_FEATURE_VERITY 0x0400 /* reserved */
155155
#define F2FS_FEATURE_SB_CHKSUM 0x0800
156+
#define F2FS_FEATURE_CASEFOLD 0x1000
156157

157158
#define __F2FS_HAS_FEATURE(raw_super, mask) \
158159
((raw_super->feature & cpu_to_le32(mask)) != 0)
@@ -1169,6 +1170,10 @@ struct f2fs_sb_info {
11691170
int valid_super_block; /* valid super block no */
11701171
unsigned long s_flag; /* flags for sbi */
11711172
struct mutex writepages; /* mutex for writepages() */
1173+
#ifdef CONFIG_UNICODE
1174+
struct unicode_map *s_encoding;
1175+
__u16 s_encoding_flags;
1176+
#endif
11721177

11731178
#ifdef CONFIG_BLK_DEV_ZONED
11741179
unsigned int blocks_per_blkz; /* F2FS blocks per zone */
@@ -3565,6 +3570,7 @@ F2FS_FEATURE_FUNCS(quota_ino, QUOTA_INO);
35653570
F2FS_FEATURE_FUNCS(inode_crtime, INODE_CRTIME);
35663571
F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND);
35673572
F2FS_FEATURE_FUNCS(sb_chksum, SB_CHKSUM);
3573+
F2FS_FEATURE_FUNCS(casefold, CASEFOLD);
35683574

35693575
#ifdef CONFIG_BLK_DEV_ZONED
35703576
static inline bool f2fs_blkz_is_seq(struct f2fs_sb_info *sbi, int devi,

fs/f2fs/super.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/f2fs_fs.h>
2424
#include <linux/sysfs.h>
2525
#include <linux/quota.h>
26+
#include <linux/unicode.h>
2627

2728
#include "f2fs.h"
2829
#include "node.h"
@@ -222,6 +223,36 @@ void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...)
222223
va_end(args);
223224
}
224225

226+
#ifdef CONFIG_UNICODE
227+
static const struct f2fs_sb_encodings {
228+
__u16 magic;
229+
char *name;
230+
char *version;
231+
} f2fs_sb_encoding_map[] = {
232+
{F2FS_ENC_UTF8_12_1, "utf8", "12.1.0"},
233+
};
234+
235+
static int f2fs_sb_read_encoding(const struct f2fs_super_block *sb,
236+
const struct f2fs_sb_encodings **encoding,
237+
__u16 *flags)
238+
{
239+
__u16 magic = le16_to_cpu(sb->s_encoding);
240+
int i;
241+
242+
for (i = 0; i < ARRAY_SIZE(f2fs_sb_encoding_map); i++)
243+
if (magic == f2fs_sb_encoding_map[i].magic)
244+
break;
245+
246+
if (i >= ARRAY_SIZE(f2fs_sb_encoding_map))
247+
return -EINVAL;
248+
249+
*encoding = &f2fs_sb_encoding_map[i];
250+
*flags = le16_to_cpu(sb->s_encoding_flags);
251+
252+
return 0;
253+
}
254+
#endif
255+
225256
static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
226257
{
227258
block_t limit = min((sbi->user_block_count << 1) / 1000,
@@ -798,6 +829,13 @@ static int parse_options(struct super_block *sb, char *options)
798829
return -EINVAL;
799830
}
800831
#endif
832+
#ifndef CONFIG_UNICODE
833+
if (f2fs_sb_has_casefold(sbi)) {
834+
f2fs_err(sbi,
835+
"Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE");
836+
return -EINVAL;
837+
}
838+
#endif
801839

802840
if (F2FS_IO_SIZE_BITS(sbi) && !test_opt(sbi, LFS)) {
803841
f2fs_err(sbi, "Should set mode=lfs with %uKB-sized IO",
@@ -1103,6 +1141,9 @@ static void f2fs_put_super(struct super_block *sb)
11031141
destroy_percpu_info(sbi);
11041142
for (i = 0; i < NR_PAGE_TYPE; i++)
11051143
kvfree(sbi->write_io[i]);
1144+
#ifdef CONFIG_UNICODE
1145+
utf8_unload(sbi->s_encoding);
1146+
#endif
11061147
kvfree(sbi);
11071148
}
11081149

@@ -3075,6 +3116,52 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
30753116
return 0;
30763117
}
30773118

3119+
static int f2fs_setup_casefold(struct f2fs_sb_info *sbi)
3120+
{
3121+
#ifdef CONFIG_UNICODE
3122+
if (f2fs_sb_has_casefold(sbi) && !sbi->s_encoding) {
3123+
const struct f2fs_sb_encodings *encoding_info;
3124+
struct unicode_map *encoding;
3125+
__u16 encoding_flags;
3126+
3127+
if (f2fs_sb_has_encrypt(sbi)) {
3128+
f2fs_err(sbi,
3129+
"Can't mount with encoding and encryption");
3130+
return -EINVAL;
3131+
}
3132+
3133+
if (f2fs_sb_read_encoding(sbi->raw_super, &encoding_info,
3134+
&encoding_flags)) {
3135+
f2fs_err(sbi,
3136+
"Encoding requested by superblock is unknown");
3137+
return -EINVAL;
3138+
}
3139+
3140+
encoding = utf8_load(encoding_info->version);
3141+
if (IS_ERR(encoding)) {
3142+
f2fs_err(sbi,
3143+
"can't mount with superblock charset: %s-%s "
3144+
"not supported by the kernel. flags: 0x%x.",
3145+
encoding_info->name, encoding_info->version,
3146+
encoding_flags);
3147+
return PTR_ERR(encoding);
3148+
}
3149+
f2fs_info(sbi, "Using encoding defined by superblock: "
3150+
"%s-%s with flags 0x%hx", encoding_info->name,
3151+
encoding_info->version?:"\b", encoding_flags);
3152+
3153+
sbi->s_encoding = encoding;
3154+
sbi->s_encoding_flags = encoding_flags;
3155+
}
3156+
#else
3157+
if (f2fs_sb_has_casefold(sbi)) {
3158+
f2fs_err(sbi, "Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE");
3159+
return -EINVAL;
3160+
}
3161+
#endif
3162+
return 0;
3163+
}
3164+
30783165
static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi)
30793166
{
30803167
struct f2fs_sm_info *sm_i = SM_I(sbi);
@@ -3171,6 +3258,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
31713258
le32_to_cpu(raw_super->log_blocksize);
31723259
sb->s_max_links = F2FS_LINK_MAX;
31733260

3261+
err = f2fs_setup_casefold(sbi);
3262+
if (err)
3263+
goto free_options;
3264+
31743265
#ifdef CONFIG_QUOTA
31753266
sb->dq_op = &f2fs_quota_operations;
31763267
sb->s_qcop = &f2fs_quotactl_ops;
@@ -3521,6 +3612,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
35213612
free_bio_info:
35223613
for (i = 0; i < NR_PAGE_TYPE; i++)
35233614
kvfree(sbi->write_io[i]);
3615+
3616+
#ifdef CONFIG_UNICODE
3617+
utf8_unload(sbi->s_encoding);
3618+
#endif
35243619
free_options:
35253620
#ifdef CONFIG_QUOTA
35263621
for (i = 0; i < MAXQUOTAS; i++)

fs/f2fs/sysfs.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/proc_fs.h>
1111
#include <linux/f2fs_fs.h>
1212
#include <linux/seq_file.h>
13+
#include <linux/unicode.h>
1314

1415
#include "f2fs.h"
1516
#include "segment.h"
@@ -81,6 +82,19 @@ static ssize_t unusable_show(struct f2fs_attr *a,
8182
(unsigned long long)unusable);
8283
}
8384

85+
static ssize_t encoding_show(struct f2fs_attr *a,
86+
struct f2fs_sb_info *sbi, char *buf)
87+
{
88+
#ifdef CONFIG_UNICODE
89+
if (f2fs_sb_has_casefold(sbi))
90+
return snprintf(buf, PAGE_SIZE, "%s (%d.%d.%d)\n",
91+
sbi->s_encoding->charset,
92+
(sbi->s_encoding->version >> 16) & 0xff,
93+
(sbi->s_encoding->version >> 8) & 0xff,
94+
sbi->s_encoding->version & 0xff);
95+
#endif
96+
return snprintf(buf, PAGE_SIZE, "(none)");
97+
}
8498

8599
static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a,
86100
struct f2fs_sb_info *sbi, char *buf)
@@ -134,6 +148,9 @@ static ssize_t features_show(struct f2fs_attr *a,
134148
if (f2fs_sb_has_sb_chksum(sbi))
135149
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
136150
len ? ", " : "", "sb_checksum");
151+
if (f2fs_sb_has_casefold(sbi))
152+
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
153+
len ? ", " : "", "casefold");
137154
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
138155
return len;
139156
}
@@ -365,6 +382,7 @@ enum feat_id {
365382
FEAT_INODE_CRTIME,
366383
FEAT_LOST_FOUND,
367384
FEAT_SB_CHECKSUM,
385+
FEAT_CASEFOLD,
368386
};
369387

370388
static ssize_t f2fs_feature_show(struct f2fs_attr *a,
@@ -382,6 +400,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a,
382400
case FEAT_INODE_CRTIME:
383401
case FEAT_LOST_FOUND:
384402
case FEAT_SB_CHECKSUM:
403+
case FEAT_CASEFOLD:
385404
return snprintf(buf, PAGE_SIZE, "supported\n");
386405
}
387406
return 0;
@@ -455,6 +474,7 @@ F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes);
455474
F2FS_GENERAL_RO_ATTR(features);
456475
F2FS_GENERAL_RO_ATTR(current_reserved_blocks);
457476
F2FS_GENERAL_RO_ATTR(unusable);
477+
F2FS_GENERAL_RO_ATTR(encoding);
458478

459479
#ifdef CONFIG_FS_ENCRYPTION
460480
F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO);
@@ -471,6 +491,7 @@ F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO);
471491
F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME);
472492
F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND);
473493
F2FS_FEATURE_RO_ATTR(sb_checksum, FEAT_SB_CHECKSUM);
494+
F2FS_FEATURE_RO_ATTR(casefold, FEAT_CASEFOLD);
474495

475496
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
476497
static struct attribute *f2fs_attrs[] = {
@@ -515,6 +536,7 @@ static struct attribute *f2fs_attrs[] = {
515536
ATTR_LIST(features),
516537
ATTR_LIST(reserved_blocks),
517538
ATTR_LIST(current_reserved_blocks),
539+
ATTR_LIST(encoding),
518540
NULL,
519541
};
520542
ATTRIBUTE_GROUPS(f2fs);
@@ -535,6 +557,7 @@ static struct attribute *f2fs_feat_attrs[] = {
535557
ATTR_LIST(inode_crtime),
536558
ATTR_LIST(lost_found),
537559
ATTR_LIST(sb_checksum),
560+
ATTR_LIST(casefold),
538561
NULL,
539562
};
540563
ATTRIBUTE_GROUPS(f2fs_feat);

include/linux/f2fs_fs.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636

3737
#define F2FS_MAX_QUOTAS 3
3838

39+
#define F2FS_ENC_UTF8_12_1 1
40+
#define F2FS_ENC_STRICT_MODE_FL (1 << 0)
41+
#define f2fs_has_strict_mode(sbi) \
42+
(sbi->s_encoding_flags & F2FS_ENC_STRICT_MODE_FL)
43+
3944
#define F2FS_IO_SIZE(sbi) (1 << F2FS_OPTION(sbi).write_io_size_bits) /* Blocks */
4045
#define F2FS_IO_SIZE_KB(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 2)) /* KB */
4146
#define F2FS_IO_SIZE_BYTES(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 12)) /* B */
@@ -110,7 +115,9 @@ struct f2fs_super_block {
110115
struct f2fs_device devs[MAX_DEVICES]; /* device list */
111116
__le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
112117
__u8 hot_ext_count; /* # of hot file extension */
113-
__u8 reserved[310]; /* valid reserved region */
118+
__le16 s_encoding; /* Filename charset encoding */
119+
__le16 s_encoding_flags; /* Filename charset encoding flags */
120+
__u8 reserved[306]; /* valid reserved region */
114121
__le32 crc; /* checksum of superblock */
115122
} __packed;
116123

0 commit comments

Comments
 (0)