summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Rosenberg <drosen@google.com>2019-07-23 19:05:28 -0400
committerJaegeuk Kim <jaegeuk@kernel.org>2019-08-23 10:57:13 -0400
commit5aba54302a46fdd589040b928d5d010e5ace1234 (patch)
tree8b6cc699256578666a66b49f8b72ae2eae36c143
parent71e90b4654a9298f9e2375cc733d57b8bf92ce73 (diff)
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 c83ad55eaa91 ("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 <drosen@google.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--Documentation/ABI/testing/sysfs-fs-f2fs7
-rw-r--r--Documentation/filesystems/f2fs.txt3
-rw-r--r--fs/f2fs/f2fs.h6
-rw-r--r--fs/f2fs/super.c95
-rw-r--r--fs/f2fs/sysfs.c23
-rw-r--r--include/linux/f2fs_fs.h9
6 files changed, 142 insertions, 1 deletions
diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
index dca326e0ee3e..7ab2b1b5e255 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -251,3 +251,10 @@ Description:
251 If checkpoint=disable, it displays the number of blocks that are unusable. 251 If checkpoint=disable, it displays the number of blocks that are unusable.
252 If checkpoint=enable it displays the enumber of blocks that would be unusable 252 If checkpoint=enable it displays the enumber of blocks that would be unusable
253 if checkpoint=disable were to be set. 253 if checkpoint=disable were to be set.
254
255What: /sys/fs/f2fs/<disk>/encoding
256Date July 2019
257Contact: "Daniel Rosenberg" <drosen@google.com>
258Description:
259 Displays name and version of the encoding set for the filesystem.
260 If no encoding is set, displays (none)
diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt
index 496fa28b2492..5fa38ab373ca 100644
--- a/Documentation/filesystems/f2fs.txt
+++ b/Documentation/filesystems/f2fs.txt
@@ -413,6 +413,9 @@ Files in /sys/fs/f2fs/<devname>
413 that would be unusable if checkpoint=disable were 413 that would be unusable if checkpoint=disable were
414 to be set. 414 to be set.
415 415
416encoding This shows the encoding used for casefolding.
417 If casefolding is not enabled, returns (none)
418
416================================================================================ 419================================================================================
417USAGE 420USAGE
418================================================================================ 421================================================================================
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 4fa9a618b31a..dd69e1559839 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -153,6 +153,7 @@ struct f2fs_mount_info {
153#define F2FS_FEATURE_LOST_FOUND 0x0200 153#define F2FS_FEATURE_LOST_FOUND 0x0200
154#define F2FS_FEATURE_VERITY 0x0400 /* reserved */ 154#define F2FS_FEATURE_VERITY 0x0400 /* reserved */
155#define F2FS_FEATURE_SB_CHKSUM 0x0800 155#define F2FS_FEATURE_SB_CHKSUM 0x0800
156#define F2FS_FEATURE_CASEFOLD 0x1000
156 157
157#define __F2FS_HAS_FEATURE(raw_super, mask) \ 158#define __F2FS_HAS_FEATURE(raw_super, mask) \
158 ((raw_super->feature & cpu_to_le32(mask)) != 0) 159 ((raw_super->feature & cpu_to_le32(mask)) != 0)
@@ -1169,6 +1170,10 @@ struct f2fs_sb_info {
1169 int valid_super_block; /* valid super block no */ 1170 int valid_super_block; /* valid super block no */
1170 unsigned long s_flag; /* flags for sbi */ 1171 unsigned long s_flag; /* flags for sbi */
1171 struct mutex writepages; /* mutex for writepages() */ 1172 struct mutex writepages; /* mutex for writepages() */
1173#ifdef CONFIG_UNICODE
1174 struct unicode_map *s_encoding;
1175 __u16 s_encoding_flags;
1176#endif
1172 1177
1173#ifdef CONFIG_BLK_DEV_ZONED 1178#ifdef CONFIG_BLK_DEV_ZONED
1174 unsigned int blocks_per_blkz; /* F2FS blocks per zone */ 1179 unsigned int blocks_per_blkz; /* F2FS blocks per zone */
@@ -3565,6 +3570,7 @@ F2FS_FEATURE_FUNCS(quota_ino, QUOTA_INO);
3565F2FS_FEATURE_FUNCS(inode_crtime, INODE_CRTIME); 3570F2FS_FEATURE_FUNCS(inode_crtime, INODE_CRTIME);
3566F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND); 3571F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND);
3567F2FS_FEATURE_FUNCS(sb_chksum, SB_CHKSUM); 3572F2FS_FEATURE_FUNCS(sb_chksum, SB_CHKSUM);
3573F2FS_FEATURE_FUNCS(casefold, CASEFOLD);
3568 3574
3569#ifdef CONFIG_BLK_DEV_ZONED 3575#ifdef CONFIG_BLK_DEV_ZONED
3570static inline bool f2fs_blkz_is_seq(struct f2fs_sb_info *sbi, int devi, 3576static inline bool f2fs_blkz_is_seq(struct f2fs_sb_info *sbi, int devi,
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 9167deb0c417..8bebee8e0186 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -23,6 +23,7 @@
23#include <linux/f2fs_fs.h> 23#include <linux/f2fs_fs.h>
24#include <linux/sysfs.h> 24#include <linux/sysfs.h>
25#include <linux/quota.h> 25#include <linux/quota.h>
26#include <linux/unicode.h>
26 27
27#include "f2fs.h" 28#include "f2fs.h"
28#include "node.h" 29#include "node.h"
@@ -222,6 +223,36 @@ void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...)
222 va_end(args); 223 va_end(args);
223} 224}
224 225
226#ifdef CONFIG_UNICODE
227static 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
235static 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
225static inline void limit_reserve_root(struct f2fs_sb_info *sbi) 256static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
226{ 257{
227 block_t limit = min((sbi->user_block_count << 1) / 1000, 258 block_t limit = min((sbi->user_block_count << 1) / 1000,
@@ -798,6 +829,13 @@ static int parse_options(struct super_block *sb, char *options)
798 return -EINVAL; 829 return -EINVAL;
799 } 830 }
800#endif 831#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
801 839
802 if (F2FS_IO_SIZE_BITS(sbi) && !test_opt(sbi, LFS)) { 840 if (F2FS_IO_SIZE_BITS(sbi) && !test_opt(sbi, LFS)) {
803 f2fs_err(sbi, "Should set mode=lfs with %uKB-sized IO", 841 f2fs_err(sbi, "Should set mode=lfs with %uKB-sized IO",
@@ -1103,6 +1141,9 @@ static void f2fs_put_super(struct super_block *sb)
1103 destroy_percpu_info(sbi); 1141 destroy_percpu_info(sbi);
1104 for (i = 0; i < NR_PAGE_TYPE; i++) 1142 for (i = 0; i < NR_PAGE_TYPE; i++)
1105 kvfree(sbi->write_io[i]); 1143 kvfree(sbi->write_io[i]);
1144#ifdef CONFIG_UNICODE
1145 utf8_unload(sbi->s_encoding);
1146#endif
1106 kvfree(sbi); 1147 kvfree(sbi);
1107} 1148}
1108 1149
@@ -3075,6 +3116,52 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
3075 return 0; 3116 return 0;
3076} 3117}
3077 3118
3119static 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
3078static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi) 3165static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi)
3079{ 3166{
3080 struct f2fs_sm_info *sm_i = SM_I(sbi); 3167 struct f2fs_sm_info *sm_i = SM_I(sbi);
@@ -3171,6 +3258,10 @@ try_onemore:
3171 le32_to_cpu(raw_super->log_blocksize); 3258 le32_to_cpu(raw_super->log_blocksize);
3172 sb->s_max_links = F2FS_LINK_MAX; 3259 sb->s_max_links = F2FS_LINK_MAX;
3173 3260
3261 err = f2fs_setup_casefold(sbi);
3262 if (err)
3263 goto free_options;
3264
3174#ifdef CONFIG_QUOTA 3265#ifdef CONFIG_QUOTA
3175 sb->dq_op = &f2fs_quota_operations; 3266 sb->dq_op = &f2fs_quota_operations;
3176 sb->s_qcop = &f2fs_quotactl_ops; 3267 sb->s_qcop = &f2fs_quotactl_ops;
@@ -3521,6 +3612,10 @@ free_percpu:
3521free_bio_info: 3612free_bio_info:
3522 for (i = 0; i < NR_PAGE_TYPE; i++) 3613 for (i = 0; i < NR_PAGE_TYPE; i++)
3523 kvfree(sbi->write_io[i]); 3614 kvfree(sbi->write_io[i]);
3615
3616#ifdef CONFIG_UNICODE
3617 utf8_unload(sbi->s_encoding);
3618#endif
3524free_options: 3619free_options:
3525#ifdef CONFIG_QUOTA 3620#ifdef CONFIG_QUOTA
3526 for (i = 0; i < MAXQUOTAS; i++) 3621 for (i = 0; i < MAXQUOTAS; i++)
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index 3aeacd0aacfd..f9fcca695db9 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -10,6 +10,7 @@
10#include <linux/proc_fs.h> 10#include <linux/proc_fs.h>
11#include <linux/f2fs_fs.h> 11#include <linux/f2fs_fs.h>
12#include <linux/seq_file.h> 12#include <linux/seq_file.h>
13#include <linux/unicode.h>
13 14
14#include "f2fs.h" 15#include "f2fs.h"
15#include "segment.h" 16#include "segment.h"
@@ -81,6 +82,19 @@ static ssize_t unusable_show(struct f2fs_attr *a,
81 (unsigned long long)unusable); 82 (unsigned long long)unusable);
82} 83}
83 84
85static 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}
84 98
85static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, 99static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a,
86 struct f2fs_sb_info *sbi, char *buf) 100 struct f2fs_sb_info *sbi, char *buf)
@@ -134,6 +148,9 @@ static ssize_t features_show(struct f2fs_attr *a,
134 if (f2fs_sb_has_sb_chksum(sbi)) 148 if (f2fs_sb_has_sb_chksum(sbi))
135 len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", 149 len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
136 len ? ", " : "", "sb_checksum"); 150 len ? ", " : "", "sb_checksum");
151 if (f2fs_sb_has_casefold(sbi))
152 len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
153 len ? ", " : "", "casefold");
137 len += snprintf(buf + len, PAGE_SIZE - len, "\n"); 154 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
138 return len; 155 return len;
139} 156}
@@ -365,6 +382,7 @@ enum feat_id {
365 FEAT_INODE_CRTIME, 382 FEAT_INODE_CRTIME,
366 FEAT_LOST_FOUND, 383 FEAT_LOST_FOUND,
367 FEAT_SB_CHECKSUM, 384 FEAT_SB_CHECKSUM,
385 FEAT_CASEFOLD,
368}; 386};
369 387
370static ssize_t f2fs_feature_show(struct f2fs_attr *a, 388static ssize_t f2fs_feature_show(struct f2fs_attr *a,
@@ -382,6 +400,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a,
382 case FEAT_INODE_CRTIME: 400 case FEAT_INODE_CRTIME:
383 case FEAT_LOST_FOUND: 401 case FEAT_LOST_FOUND:
384 case FEAT_SB_CHECKSUM: 402 case FEAT_SB_CHECKSUM:
403 case FEAT_CASEFOLD:
385 return snprintf(buf, PAGE_SIZE, "supported\n"); 404 return snprintf(buf, PAGE_SIZE, "supported\n");
386 } 405 }
387 return 0; 406 return 0;
@@ -455,6 +474,7 @@ F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes);
455F2FS_GENERAL_RO_ATTR(features); 474F2FS_GENERAL_RO_ATTR(features);
456F2FS_GENERAL_RO_ATTR(current_reserved_blocks); 475F2FS_GENERAL_RO_ATTR(current_reserved_blocks);
457F2FS_GENERAL_RO_ATTR(unusable); 476F2FS_GENERAL_RO_ATTR(unusable);
477F2FS_GENERAL_RO_ATTR(encoding);
458 478
459#ifdef CONFIG_FS_ENCRYPTION 479#ifdef CONFIG_FS_ENCRYPTION
460F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO); 480F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO);
@@ -471,6 +491,7 @@ F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO);
471F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME); 491F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME);
472F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND); 492F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND);
473F2FS_FEATURE_RO_ATTR(sb_checksum, FEAT_SB_CHECKSUM); 493F2FS_FEATURE_RO_ATTR(sb_checksum, FEAT_SB_CHECKSUM);
494F2FS_FEATURE_RO_ATTR(casefold, FEAT_CASEFOLD);
474 495
475#define ATTR_LIST(name) (&f2fs_attr_##name.attr) 496#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
476static struct attribute *f2fs_attrs[] = { 497static struct attribute *f2fs_attrs[] = {
@@ -515,6 +536,7 @@ static struct attribute *f2fs_attrs[] = {
515 ATTR_LIST(features), 536 ATTR_LIST(features),
516 ATTR_LIST(reserved_blocks), 537 ATTR_LIST(reserved_blocks),
517 ATTR_LIST(current_reserved_blocks), 538 ATTR_LIST(current_reserved_blocks),
539 ATTR_LIST(encoding),
518 NULL, 540 NULL,
519}; 541};
520ATTRIBUTE_GROUPS(f2fs); 542ATTRIBUTE_GROUPS(f2fs);
@@ -535,6 +557,7 @@ static struct attribute *f2fs_feat_attrs[] = {
535 ATTR_LIST(inode_crtime), 557 ATTR_LIST(inode_crtime),
536 ATTR_LIST(lost_found), 558 ATTR_LIST(lost_found),
537 ATTR_LIST(sb_checksum), 559 ATTR_LIST(sb_checksum),
560 ATTR_LIST(casefold),
538 NULL, 561 NULL,
539}; 562};
540ATTRIBUTE_GROUPS(f2fs_feat); 563ATTRIBUTE_GROUPS(f2fs_feat);
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index 52af9ac164b4..284738996028 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -36,6 +36,11 @@
36 36
37#define F2FS_MAX_QUOTAS 3 37#define F2FS_MAX_QUOTAS 3
38 38
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
39#define F2FS_IO_SIZE(sbi) (1 << F2FS_OPTION(sbi).write_io_size_bits) /* Blocks */ 44#define F2FS_IO_SIZE(sbi) (1 << F2FS_OPTION(sbi).write_io_size_bits) /* Blocks */
40#define F2FS_IO_SIZE_KB(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 2)) /* KB */ 45#define F2FS_IO_SIZE_KB(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 2)) /* KB */
41#define F2FS_IO_SIZE_BYTES(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 12)) /* B */ 46#define F2FS_IO_SIZE_BYTES(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 12)) /* B */
@@ -110,7 +115,9 @@ struct f2fs_super_block {
110 struct f2fs_device devs[MAX_DEVICES]; /* device list */ 115 struct f2fs_device devs[MAX_DEVICES]; /* device list */
111 __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */ 116 __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
112 __u8 hot_ext_count; /* # of hot file extension */ 117 __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 */
114 __le32 crc; /* checksum of superblock */ 121 __le32 crc; /* checksum of superblock */
115} __packed; 122} __packed;
116 123