aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGabriel Krisman Bertazi <krisman@collabora.co.uk>2019-04-25 14:05:42 -0400
committerTheodore Ts'o <tytso@mit.edu>2019-04-25 14:05:42 -0400
commitc83ad55eaa91c8e85dd8cc3b7b3485fac45ef7bf (patch)
tree6c10e8bab625a1643fc7ca468fa00b6f20899971
parente765b4abb2215b88f227e3bed7757474b6e77402 (diff)
ext4: include charset encoding information in the superblock
Support for encoding is considered an incompatible feature, since it has potential to create collisions of file names in existing filesystems. If the feature flag is not enabled, the entire filesystem will operate on opaque byte sequences, respecting the original behavior. 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: Gabriel Krisman Bertazi <krisman@collabora.co.uk> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--fs/ext4/ext4.h21
-rw-r--r--fs/ext4/super.c85
2 files changed, 105 insertions, 1 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 2a2e6ed9aab4..c1504c471fef 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1313,7 +1313,9 @@ struct ext4_super_block {
1313 __u8 s_first_error_time_hi; 1313 __u8 s_first_error_time_hi;
1314 __u8 s_last_error_time_hi; 1314 __u8 s_last_error_time_hi;
1315 __u8 s_pad[2]; 1315 __u8 s_pad[2];
1316 __le32 s_reserved[96]; /* Padding to the end of the block */ 1316 __le16 s_encoding; /* Filename charset encoding */
1317 __le16 s_encoding_flags; /* Filename charset encoding flags */
1318 __le32 s_reserved[95]; /* Padding to the end of the block */
1317 __le32 s_checksum; /* crc32c(superblock) */ 1319 __le32 s_checksum; /* crc32c(superblock) */
1318}; 1320};
1319 1321
@@ -1338,6 +1340,16 @@ struct ext4_super_block {
1338/* Number of quota types we support */ 1340/* Number of quota types we support */
1339#define EXT4_MAXQUOTAS 3 1341#define EXT4_MAXQUOTAS 3
1340 1342
1343#define EXT4_ENC_UTF8_12_1 1
1344
1345/*
1346 * Flags for ext4_sb_info.s_encoding_flags.
1347 */
1348#define EXT4_ENC_STRICT_MODE_FL (1 << 0)
1349
1350#define ext4_has_strict_mode(sbi) \
1351 (sbi->s_encoding_flags & EXT4_ENC_STRICT_MODE_FL)
1352
1341/* 1353/*
1342 * fourth extended-fs super-block data in memory 1354 * fourth extended-fs super-block data in memory
1343 */ 1355 */
@@ -1387,6 +1399,10 @@ struct ext4_sb_info {
1387 struct kobject s_kobj; 1399 struct kobject s_kobj;
1388 struct completion s_kobj_unregister; 1400 struct completion s_kobj_unregister;
1389 struct super_block *s_sb; 1401 struct super_block *s_sb;
1402#ifdef CONFIG_UNICODE
1403 struct unicode_map *s_encoding;
1404 __u16 s_encoding_flags;
1405#endif
1390 1406
1391 /* Journaling */ 1407 /* Journaling */
1392 struct journal_s *s_journal; 1408 struct journal_s *s_journal;
@@ -1660,6 +1676,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
1660#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ 1676#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
1661#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */ 1677#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
1662#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 1678#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
1679#define EXT4_FEATURE_INCOMPAT_CASEFOLD 0x20000
1663 1680
1664extern void ext4_update_dynamic_rev(struct super_block *sb); 1681extern void ext4_update_dynamic_rev(struct super_block *sb);
1665 1682
@@ -1753,6 +1770,7 @@ EXT4_FEATURE_INCOMPAT_FUNCS(csum_seed, CSUM_SEED)
1753EXT4_FEATURE_INCOMPAT_FUNCS(largedir, LARGEDIR) 1770EXT4_FEATURE_INCOMPAT_FUNCS(largedir, LARGEDIR)
1754EXT4_FEATURE_INCOMPAT_FUNCS(inline_data, INLINE_DATA) 1771EXT4_FEATURE_INCOMPAT_FUNCS(inline_data, INLINE_DATA)
1755EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT) 1772EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT)
1773EXT4_FEATURE_INCOMPAT_FUNCS(casefold, CASEFOLD)
1756 1774
1757#define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR 1775#define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR
1758#define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ 1776#define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \
@@ -1780,6 +1798,7 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT)
1780 EXT4_FEATURE_INCOMPAT_MMP | \ 1798 EXT4_FEATURE_INCOMPAT_MMP | \
1781 EXT4_FEATURE_INCOMPAT_INLINE_DATA | \ 1799 EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
1782 EXT4_FEATURE_INCOMPAT_ENCRYPT | \ 1800 EXT4_FEATURE_INCOMPAT_ENCRYPT | \
1801 EXT4_FEATURE_INCOMPAT_CASEFOLD | \
1783 EXT4_FEATURE_INCOMPAT_CSUM_SEED | \ 1802 EXT4_FEATURE_INCOMPAT_CSUM_SEED | \
1784 EXT4_FEATURE_INCOMPAT_LARGEDIR) 1803 EXT4_FEATURE_INCOMPAT_LARGEDIR)
1785#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ 1804#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 184944d4d8d1..c1b02c3a5a68 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -42,6 +42,7 @@
42#include <linux/cleancache.h> 42#include <linux/cleancache.h>
43#include <linux/uaccess.h> 43#include <linux/uaccess.h>
44#include <linux/iversion.h> 44#include <linux/iversion.h>
45#include <linux/unicode.h>
45 46
46#include <linux/kthread.h> 47#include <linux/kthread.h>
47#include <linux/freezer.h> 48#include <linux/freezer.h>
@@ -1054,6 +1055,9 @@ static void ext4_put_super(struct super_block *sb)
1054 crypto_free_shash(sbi->s_chksum_driver); 1055 crypto_free_shash(sbi->s_chksum_driver);
1055 kfree(sbi->s_blockgroup_lock); 1056 kfree(sbi->s_blockgroup_lock);
1056 fs_put_dax(sbi->s_daxdev); 1057 fs_put_dax(sbi->s_daxdev);
1058#ifdef CONFIG_UNICODE
1059 utf8_unload(sbi->s_encoding);
1060#endif
1057 kfree(sbi); 1061 kfree(sbi);
1058} 1062}
1059 1063
@@ -1750,6 +1754,36 @@ static const struct mount_opts {
1750 {Opt_err, 0, 0} 1754 {Opt_err, 0, 0}
1751}; 1755};
1752 1756
1757#ifdef CONFIG_UNICODE
1758static const struct ext4_sb_encodings {
1759 __u16 magic;
1760 char *name;
1761 char *version;
1762} ext4_sb_encoding_map[] = {
1763 {EXT4_ENC_UTF8_12_1, "utf8", "12.1.0"},
1764};
1765
1766static int ext4_sb_read_encoding(const struct ext4_super_block *es,
1767 const struct ext4_sb_encodings **encoding,
1768 __u16 *flags)
1769{
1770 __u16 magic = le16_to_cpu(es->s_encoding);
1771 int i;
1772
1773 for (i = 0; i < ARRAY_SIZE(ext4_sb_encoding_map); i++)
1774 if (magic == ext4_sb_encoding_map[i].magic)
1775 break;
1776
1777 if (i >= ARRAY_SIZE(ext4_sb_encoding_map))
1778 return -EINVAL;
1779
1780 *encoding = &ext4_sb_encoding_map[i];
1781 *flags = le16_to_cpu(es->s_encoding_flags);
1782
1783 return 0;
1784}
1785#endif
1786
1753static int handle_mount_opt(struct super_block *sb, char *opt, int token, 1787static int handle_mount_opt(struct super_block *sb, char *opt, int token,
1754 substring_t *args, unsigned long *journal_devnum, 1788 substring_t *args, unsigned long *journal_devnum,
1755 unsigned int *journal_ioprio, int is_remount) 1789 unsigned int *journal_ioprio, int is_remount)
@@ -2880,6 +2914,15 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
2880 return 0; 2914 return 0;
2881 } 2915 }
2882 2916
2917#ifndef CONFIG_UNICODE
2918 if (ext4_has_feature_casefold(sb)) {
2919 ext4_msg(sb, KERN_ERR,
2920 "Filesystem with casefold feature cannot be "
2921 "mounted without CONFIG_UNICODE");
2922 return 0;
2923 }
2924#endif
2925
2883 if (readonly) 2926 if (readonly)
2884 return 1; 2927 return 1;
2885 2928
@@ -3770,6 +3813,43 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
3770 &journal_ioprio, 0)) 3813 &journal_ioprio, 0))
3771 goto failed_mount; 3814 goto failed_mount;
3772 3815
3816#ifdef CONFIG_UNICODE
3817 if (ext4_has_feature_casefold(sb) && !sbi->s_encoding) {
3818 const struct ext4_sb_encodings *encoding_info;
3819 struct unicode_map *encoding;
3820 __u16 encoding_flags;
3821
3822 if (ext4_has_feature_encrypt(sb)) {
3823 ext4_msg(sb, KERN_ERR,
3824 "Can't mount with encoding and encryption");
3825 goto failed_mount;
3826 }
3827
3828 if (ext4_sb_read_encoding(es, &encoding_info,
3829 &encoding_flags)) {
3830 ext4_msg(sb, KERN_ERR,
3831 "Encoding requested by superblock is unknown");
3832 goto failed_mount;
3833 }
3834
3835 encoding = utf8_load(encoding_info->version);
3836 if (IS_ERR(encoding)) {
3837 ext4_msg(sb, KERN_ERR,
3838 "can't mount with superblock charset: %s-%s "
3839 "not supported by the kernel. flags: 0x%x.",
3840 encoding_info->name, encoding_info->version,
3841 encoding_flags);
3842 goto failed_mount;
3843 }
3844 ext4_msg(sb, KERN_INFO,"Using encoding defined by superblock: "
3845 "%s-%s with flags 0x%hx", encoding_info->name,
3846 encoding_info->version?:"\b", encoding_flags);
3847
3848 sbi->s_encoding = encoding;
3849 sbi->s_encoding_flags = encoding_flags;
3850 }
3851#endif
3852
3773 if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { 3853 if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
3774 printk_once(KERN_WARNING "EXT4-fs: Warning: mounting " 3854 printk_once(KERN_WARNING "EXT4-fs: Warning: mounting "
3775 "with data=journal disables delayed " 3855 "with data=journal disables delayed "
@@ -4586,6 +4666,11 @@ failed_mount2:
4586failed_mount: 4666failed_mount:
4587 if (sbi->s_chksum_driver) 4667 if (sbi->s_chksum_driver)
4588 crypto_free_shash(sbi->s_chksum_driver); 4668 crypto_free_shash(sbi->s_chksum_driver);
4669
4670#ifdef CONFIG_UNICODE
4671 utf8_unload(sbi->s_encoding);
4672#endif
4673
4589#ifdef CONFIG_QUOTA 4674#ifdef CONFIG_QUOTA
4590 for (i = 0; i < EXT4_MAXQUOTAS; i++) 4675 for (i = 0; i < EXT4_MAXQUOTAS; i++)
4591 kfree(sbi->s_qf_names[i]); 4676 kfree(sbi->s_qf_names[i]);