diff mbox series

[v2,21/25] ext4: Add encoding mount options

Message ID 20180815194811.9423-22-krisman@collabora.co.uk
State Not Applicable
Headers show
Series Ext4 Encoding and Case-insensitive support | expand

Commit Message

Gabriel Krisman Bertazi Aug. 15, 2018, 7:48 p.m. UTC
This patch implements two new mount options for ext4: encoding and
encoding_flags.

The encoding option receives a string that identifies the NLS encoding
to be used when mounting the filesystem.  The user can optionally ask
for a specific version by appending the version string after a dash.

The encoding_flags argument allows the user to specify how the NLS
charset must behave.  The exact behavior of the flags are defined at
ext4.h.

encoding_flags is ignored if the user didn't provide an encoding.

Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
 fs/ext4/super.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)
diff mbox series

Patch

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 4ccb932a0dc7..1f1efde74523 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1390,6 +1390,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, Opt_encoding_flags
 };
 
 static const match_table_t tokens = {
@@ -1474,6 +1475,8 @@  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_encoding_flags, "encoding_flags=%u"},
 	{Opt_nombcache, "nombcache"},
 	{Opt_nombcache, "no_mbcache"},	/* for backward compatibility */
 	{Opt_removed, "check=none"},	/* mount option from ext2/3 */
@@ -1686,6 +1689,8 @@  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_encoding_flags, 0, MOPT_EXT4_ONLY},
 	{Opt_err, 0, 0}
 };
 
@@ -1712,6 +1717,27 @@  ext4_sb_read_encoding(const struct ext4_super_block *es,
 
 	return 0;
 }
+
+static struct ext4_sb_encodings *ext4_parse_encoding_opt(char *arg)
+{
+	char *split;
+	struct ext4_sb_encodings *info;
+	ssize_t len = strlen(arg) + 1;
+
+	info = kzalloc(sizeof(struct ext4_sb_encodings) + len, GFP_KERNEL);
+	if (!info)
+		return NULL;
+
+	info->name = ((char*) &info[1]);
+	strncpy(info->name, arg, len);
+
+	split = strchr(info->name, '-');
+	if (split && *(split+1)) {
+		*split = '\0';
+		info->version = split+1;
+	}
+	return info;
+}
 #endif
 
 static int handle_mount_opt(struct super_block *sb, char *opt, int token,
@@ -1946,6 +1972,42 @@  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) {
+		int ret = -1;
+#ifdef CONFIG_NLS
+		char *encoding = match_strdup(&args[0]);
+
+		if (!encoding)
+			return -ENOMEM;
+
+		if (ext4_has_feature_encrypt(sb)) {
+			ext4_msg(sb, KERN_ERR,
+				 "Can't mount with both encoding and encryption");
+			goto encoding_out;
+		}
+
+		sbi->encoding_info = ext4_parse_encoding_opt(encoding);
+		if (!sbi->encoding_info) {
+			ext4_msg(sb, KERN_ERR,
+				 "Encoding %s not supported by ext4", encoding);
+			goto encoding_out;
+		}
+
+		ret = 0;
+encoding_out:
+		kfree(encoding);
+#else
+		ext4_msg(sb, KERN_INFO, "encoding option not supported");
+#endif
+		return ret;
+	} else if (token == Opt_encoding_flags) {
+#ifdef CONFIG_NLS
+		sbi->encoding_flags = arg;
+		return 0;
+#else
+		ext4_msg(sb, KERN_INFO, "encoding flags option not supported");
+		return -1;
+#endif
 	} else {
 		if (!args->from)
 			arg = 1;
@@ -2032,6 +2094,35 @@  static int parse_options(char *options, struct super_block *sb,
 			return 0;
 		}
 	}
+
+#ifdef CONFIG_NLS
+	if (sbi->encoding_info) {
+		sbi->encoding = load_nls_version(sbi->encoding_info->name,
+						 sbi->encoding_info->version,
+						 sbi->encoding_flags);
+		if (IS_ERR(sbi->encoding)) {
+			ext4_msg(sb, KERN_ERR,
+				 "Cannot load encoding: %s %s with flags 0x%hx",
+				 sbi->encoding_info->name,
+				 sbi->encoding_info->version?:"\b",
+				 sbi->encoding_flags & EXT4_ENC_NLS_FL_MASK);
+
+			sbi->encoding = NULL;
+			sbi->encoding_flags = 0;
+			kfree(sbi->encoding_info);
+
+			return 0;
+		}
+		ext4_msg(sb, KERN_INFO,"Using encoding defined by mount option: "
+			 "%s %s with flags 0x%hx", sbi->encoding_info->name,
+			 sbi->encoding_info->version?:"\b", sbi->encoding_flags);
+	} else {
+		/* Make sure the flags are zeroed if the the user didn't
+		   provide the encoding name. */
+		sbi->encoding_flags = 0;
+	}
+
+#endif
 	return 1;
 }