Signed-off-by: Gabriel Krisman Bertazi <krisman@xxxxxxxxxxxxxxx> --- fs/ext4/ext4.h | 1 + fs/ext4/super.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 3241475a1733..22f49d7d3efc 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1366,6 +1366,7 @@ struct ext4_sb_info { struct kobject s_kobj; struct completion s_kobj_unregister; struct super_block *s_sb; + struct nls_table *encoding; /* Journaling */ struct journal_s *s_journal; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 39bf464c35f1..bbf0a5c4104b 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -42,6 +42,7 @@ #include <linux/cleancache.h> #include <linux/uaccess.h> #include <linux/iversion.h> +#include <linux/nls.h> #include <linux/kthread.h> #include <linux/freezer.h> @@ -1352,6 +1353,7 @@ enum { Opt_dioread_nolock, Opt_dioread_lock, Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache, + Opt_encoding, }; static const match_table_t tokens = { @@ -1434,6 +1436,7 @@ static const match_table_t tokens = { {Opt_noinit_itable, "noinit_itable"}, {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, {Opt_test_dummy_encryption, "test_dummy_encryption"}, + {Opt_encoding, "encoding=%s"}, {Opt_nombcache, "nombcache"}, {Opt_nombcache, "no_mbcache"}, /* for backward compatibility */ {Opt_removed, "check=none"}, /* mount option from ext2/3 */ @@ -1644,9 +1647,24 @@ static const struct mount_opts { {Opt_max_dir_size_kb, 0, MOPT_GTE0}, {Opt_test_dummy_encryption, 0, MOPT_GTE0}, {Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET}, + {Opt_encoding, 0, MOPT_EXT4_ONLY | MOPT_STRING}, {Opt_err, 0, 0} }; +static void split_charset_version(char *encoding_arg, char **charset, + char **version) +{ + char *separator; + *version = NULL; + *charset = encoding_arg; + + separator = strchr(encoding_arg, '-'); + if (separator && *separator && *(separator+1) != '\0') { + *separator = '\0'; + *version = separator + 1; + } +} + static int handle_mount_opt(struct super_block *sb, char *opt, int token, substring_t *args, unsigned long *journal_devnum, unsigned int *journal_ioprio, int is_remount) @@ -1879,6 +1897,21 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, sbi->s_mount_opt |= m->mount_opt; } else if (token == Opt_data_err_ignore) { sbi->s_mount_opt &= ~m->mount_opt; + } else if (token == Opt_encoding) { + char *encoding_arg = match_strdup(&args[0]); + char *charset = NULL; + char *version = NULL; + + split_charset_version(encoding_arg, &charset, &version); + + sbi->encoding = load_nls_version(charset, version); + if (IS_ERR(sbi->encoding)) { + ext4_msg(sb, KERN_ERR, "Encoding %s-%s not supported", + charset,version); + kfree(encoding_arg); + return -1; + } + kfree(encoding_arg); } else { if (!args->from) arg = 1; @@ -1965,6 +1998,12 @@ static int parse_options(char *options, struct super_block *sb, return 0; } } + + if (!sbi->encoding) { + ext4_msg(sb, KERN_WARNING, "Encoding not explicitly specified " + "or identified on the superblock. ASCII is assumed."); + } + return 1; } @@ -3595,6 +3634,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) &journal_ioprio, 0)) goto failed_mount; + if (!sbi->encoding) { + sbi->encoding = load_nls("ascii"); + if (!sbi->encoding) + goto failed_mount; + } + if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { printk_once(KERN_WARNING "EXT4-fs: Warning: mounting " "with data=journal disables delayed " -- 2.17.0