NLS charsets wanting to use this feature can implement the load_create() hook, which creates a nls_table for that specific encoding version. The charset code is responsible for freeing the table memory when the module is removed. Signed-off-by: Gabriel Krisman Bertazi <krisman@xxxxxxxxxxxxxxx> --- fs/nls/nls_core.c | 45 ++++++++++++++++++++++++++++++++++++++------- include/linux/nls.h | 5 +++++ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/fs/nls/nls_core.c b/fs/nls/nls_core.c index 200a7f8165e6..19a5a66fe423 100644 --- a/fs/nls/nls_core.c +++ b/fs/nls/nls_core.c @@ -19,10 +19,27 @@ extern struct nls_charset default_charset; static struct nls_charset *charsets = &default_charset; static DEFINE_SPINLOCK(nls_lock); -static struct nls_table *nls_load_table(struct nls_charset *charset) + +static struct nls_table *nls_load_table(struct nls_charset *charset, + const char *version) { - /* For now, return the default table, which is the first one found. */ - return charset->tables; + struct nls_table *tbl; + + if (!charset->load_table) { + /* If there is no table_create, only 1 table is + * supported and it must have been loaded + * statically. + */ + return charset->tables; + } + + tbl = charset->load_table(version); + if (!tbl) { + /* Invalid version */ + return ERR_PTR(-EINVAL); + } + + return tbl; } int __register_nls(struct nls_charset *nls, struct module *owner) @@ -85,21 +102,35 @@ static struct nls_charset *find_nls(const char *charset) return nls; } -struct nls_table *load_nls(char *charset) +struct nls_table *load_nls_version(const char *charset, const char *version) { struct nls_charset *nls_charset; nls_charset = try_then_request_module(find_nls(charset), "nls_%s", charset); - if (!IS_ERR(nls_charset)) + if (IS_ERR(nls_charset)) + return ERR_PTR(-EINVAL); + + return nls_load_table(nls_charset, version); +} +EXPORT_SYMBOL(load_nls_version); + +struct nls_table *load_nls(char *charset) +{ + struct nls_table *table = load_nls_version(charset, NULL); + + /* Pre-versioned load_nls() didn't return error pointers. Let's + * keep the abi for now to prevent breakage. + */ + if (IS_ERR(table)) return NULL; - return nls_load_table(nls_charset); + return table; } void unload_nls(struct nls_table *nls) { - if (nls) + if (!IS_ERR_OR_NULL(nls)) module_put(nls->charset->owner); } diff --git a/include/linux/nls.h b/include/linux/nls.h index cdc95cd9e5d4..e422bd52afbb 100644 --- a/include/linux/nls.h +++ b/include/linux/nls.h @@ -30,6 +30,8 @@ struct nls_ops { struct nls_table { const struct nls_charset *charset; + unsigned int version; + const struct nls_ops *ops; const unsigned char *charset2lower; const unsigned char *charset2upper; @@ -42,6 +44,7 @@ struct nls_charset { struct module *owner; struct nls_table *tables; struct nls_charset *next; + struct nls_table *(*load_table)(const char *version); }; /* this value hold the maximum octet of charset */ @@ -58,6 +61,8 @@ enum utf16_endian { extern int __register_nls(struct nls_charset *, struct module *); extern int unregister_nls(struct nls_charset *); extern struct nls_table *load_nls(char *); +extern struct nls_table *load_nls_version(const char *charset, + const char *version); extern void unload_nls(struct nls_table *); extern struct nls_table *load_nls_default(void); #define register_nls(nls) __register_nls((nls), THIS_MODULE) -- 2.18.0