summaryrefslogtreecommitdiffstats
path: root/fs/ext4/super.c
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 /fs/ext4/super.c
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>
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r--fs/ext4/super.c85
1 files changed, 85 insertions, 0 deletions
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]);