return rc;
 }
 
-static inline int get_next_dfs_tgt(const char *path,
-                                  struct dfs_cache_tgt_list *tgt_list,
-                                  struct dfs_cache_tgt_iterator **tgt_it)
+static int get_next_dfs_tgt(struct dfs_cache_tgt_list *tgt_list,
+                           struct dfs_cache_tgt_iterator **tgt_it)
 {
        if (!*tgt_it)
                *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
                           struct cifs_ses **ses, struct cifs_tcon **tcon)
 {
        int rc;
+       char *npath = NULL;
        struct dfs_cache_tgt_list tgt_list = {0};
        struct dfs_cache_tgt_iterator *tgt_it = NULL;
        struct smb3_fs_context tmp_ctx = {NULL};
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
                return -EOPNOTSUPP;
 
-       cifs_dbg(FYI, "%s: path=%s full_path=%s\n", __func__, path, full_path);
+       npath = dfs_cache_canonical_path(path, cifs_sb->local_nls, cifs_remap(cifs_sb));
+       if (IS_ERR(npath))
+               return PTR_ERR(npath);
 
-       rc = dfs_cache_noreq_find(path, NULL, &tgt_list);
+       cifs_dbg(FYI, "%s: path=%s full_path=%s\n", __func__, npath, full_path);
+
+       rc = dfs_cache_noreq_find(npath, NULL, &tgt_list);
        if (rc)
-               return rc;
+               goto out;
        /*
         * We use a 'tmp_ctx' here because we need pass it down to the mount_{get,put} functions to
         * test connection against new DFS targets.
                char *fake_devname = NULL, *mdata = NULL;
 
                /* Get next DFS target server - if any */
-               rc = get_next_dfs_tgt(path, &tgt_list, &tgt_it);
+               rc = get_next_dfs_tgt(&tgt_list, &tgt_it);
                if (rc)
                        break;
 
-               rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref);
+               rc = dfs_cache_get_tgt_referral(npath, tgt_it, &ref);
                if (rc)
                        break;
 
        }
 
 out:
+       kfree(npath);
        smb3_cleanup_fs_context_contents(&tmp_ctx);
        dfs_cache_free_tgts(&tgt_list);
        return rc;
        if (ses) {
                spin_lock(&cifs_tcp_ses_lock);
                ses->ses_count++;
-               cifs_dbg(FYI, "%s: new ses_count=%d\n", __func__, ses->ses_count);
-               if (ses->tcon_ipc) {
-                       cifs_dbg(FYI, "%s: ipc tcon: %s\n", __func__, ses->tcon_ipc->treeName);
-                       ses->tcon_ipc->remap = cifs_remap(cifs_sb);
-               }
                spin_unlock(&cifs_tcp_ses_lock);
                dfs_cache_add_refsrv_session(mount_id, ses);
        }
 }
 
 /* Check if resolved targets can handle any DFS referrals */
-static int is_referral_server(const char *ref_path, struct cifs_tcon *tcon, bool *ref_server)
+static int is_referral_server(const char *ref_path, struct cifs_sb_info *cifs_sb,
+                             struct cifs_tcon *tcon, bool *ref_server)
 {
        int rc;
        struct dfs_info3_param ref = {0};
 
+       cifs_dbg(FYI, "%s: ref_path=%s\n", __func__, ref_path);
+
        if (is_tcon_dfs(tcon)) {
                *ref_server = true;
        } else {
-               cifs_dbg(FYI, "%s: ref_path=%s\n", __func__, ref_path);
+               char *npath;
 
-               rc = dfs_cache_noreq_find(ref_path, &ref, NULL);
+               npath = dfs_cache_canonical_path(ref_path, cifs_sb->local_nls, cifs_remap(cifs_sb));
+               if (IS_ERR(npath))
+                       return PTR_ERR(npath);
+
+               rc = dfs_cache_noreq_find(npath, &ref, NULL);
+               kfree(npath);
                if (rc) {
                        cifs_dbg(VFS, "%s: dfs_cache_noreq_find: failed (rc=%d)\n", __func__, rc);
                        return rc;
                        continue;
 
                /* Make sure that requests go through new root servers */
-               rc = is_referral_server(ref_path + 1, tcon, &ref_server);
+               rc = is_referral_server(ref_path + 1, cifs_sb, tcon, &ref_server);
                if (rc)
                        break;
                if (ref_server)
                goto error;
 
        kfree(ref_path);
-       ref_path = NULL;
        /*
         * Store DFS full path in both superblock and tree connect structures.
         *
         * links, the prefix path is included in both and may be changed during reconnect.  See
         * cifs_tree_connect().
         */
-       cifs_sb->origin_fullpath = kstrdup(full_path, GFP_KERNEL);
-       if (!cifs_sb->origin_fullpath) {
+       ref_path = dfs_cache_canonical_path(full_path, cifs_sb->local_nls, cifs_remap(cifs_sb));
+       kfree(full_path);
+       full_path = NULL;
+
+       if (IS_ERR(ref_path)) {
+               rc = PTR_ERR(ref_path);
+               ref_path = NULL;
+               goto error;
+       }
+       cifs_sb->origin_fullpath = ref_path;
+
+       ref_path = kstrdup(cifs_sb->origin_fullpath, GFP_KERNEL);
+       if (!ref_path) {
                rc = -ENOMEM;
                goto error;
        }
        spin_lock(&cifs_tcp_ses_lock);
-       tcon->dfs_path = full_path;
-       full_path = NULL;
-       tcon->remap = cifs_remap(cifs_sb);
+       tcon->dfs_path = ref_path;
+       ref_path = NULL;
        spin_unlock(&cifs_tcp_ses_lock);
 
        /*
 
 static int cache_ttl;
 static DEFINE_SPINLOCK(cache_ttl_lock);
 
-static struct nls_table *cache_nlsc;
+static struct nls_table *cache_cp;
 
 /*
  * Number of entries in the cache
        }
 }
 
-static int get_normalized_path(const char *path, const char **npath)
+/**
+ * dfs_cache_canonical_path - get a canonical DFS path
+ *
+ * @path: DFS path
+ * @cp: codepage
+ * @remap: mapping type
+ *
+ * Return canonical path if success, otherwise error.
+ */
+char *dfs_cache_canonical_path(const char *path, const struct nls_table *cp, int remap)
 {
+       char *tmp;
+       int plen = 0;
+       char *npath;
+
        if (!path || strlen(path) < 3 || (*path != '\\' && *path != '/'))
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
+
+       if (unlikely(strcmp(cp->charset, cache_cp->charset))) {
+               tmp = (char *)cifs_strndup_to_utf16(path, strlen(path), &plen, cp, remap);
+               if (!tmp) {
+                       cifs_dbg(VFS, "%s: failed to convert path to utf16\n", __func__);
+                       return ERR_PTR(-EINVAL);
+               }
 
-       if (*path == '\\') {
-               *npath = path;
+               npath = cifs_strndup_from_utf16(tmp, plen, true, cache_cp);
+               kfree(tmp);
+
+               if (!npath) {
+                       cifs_dbg(VFS, "%s: failed to convert path from utf16\n", __func__);
+                       return ERR_PTR(-EINVAL);
+               }
        } else {
-               char *s = kstrdup(path, GFP_KERNEL);
-               if (!s)
-                       return -ENOMEM;
-               convert_delimiter(s, '\\');
-               *npath = s;
+               npath = kstrdup(path, GFP_KERNEL);
+               if (!npath)
+                       return ERR_PTR(-ENOMEM);
        }
-       return 0;
-}
-
-static inline void free_normalized_path(const char *path, const char *npath)
-{
-       if (path != npath)
-               kfree(npath);
+       convert_delimiter(npath, '\\');
+       return npath;
 }
 
 static inline bool cache_entry_expired(const struct cache_entry *ce)
                INIT_HLIST_HEAD(&cache_htable[i]);
 
        atomic_set(&cache_count, 0);
-       cache_nlsc = load_nls_default();
+       cache_cp = load_nls("utf8");
+       if (!cache_cp)
+               cache_cp = load_nls_default();
 
        cifs_dbg(FYI, "%s: initialized DFS referral cache\n", __func__);
        return 0;
 void dfs_cache_destroy(void)
 {
        cancel_delayed_work_sync(&refresh_task);
-       unload_nls(cache_nlsc);
+       unload_nls(cache_cp);
        free_mount_group_list();
        flush_cache_ents();
        kmem_cache_destroy(cache_slab);
        return rc;
 }
 
-static int get_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
-                           const struct nls_table *nls_codepage, int remap,
-                           const char *path,  struct dfs_info3_param **refs,
-                           int *numrefs)
+static int get_dfs_referral(const unsigned int xid, struct cifs_ses *ses, const char *path,
+                           struct dfs_info3_param **refs, int *numrefs)
 {
        cifs_dbg(FYI, "%s: get an DFS referral for %s\n", __func__, path);
 
        if (!ses || !ses->server || !ses->server->ops->get_dfs_refer)
                return -EOPNOTSUPP;
-       if (unlikely(!nls_codepage))
+       if (unlikely(!cache_cp))
                return -EINVAL;
 
        *refs = NULL;
        *numrefs = 0;
 
-       return ses->server->ops->get_dfs_refer(xid, ses, path, refs, numrefs,
-                                              nls_codepage, remap);
+       return ses->server->ops->get_dfs_refer(xid, ses, path, refs, numrefs, cache_cp,
+                                              NO_MAP_UNI_RSVD);
 }
 
 /*
  * For interlinks, cifs_mount() and expand_dfs_referral() are supposed to
  * handle them properly.
  */
-static int cache_refresh_path(const unsigned int xid, struct cifs_ses *ses,
-                             const struct nls_table *nls_codepage, int remap, const char *path)
+static int cache_refresh_path(const unsigned int xid, struct cifs_ses *ses, const char *path)
 {
        int rc;
        unsigned int hash;
         * Either the entry was not found, or it is expired.
         * Request a new DFS referral in order to create or update a cache entry.
         */
-       rc = get_dfs_referral(xid, ses, nls_codepage, remap, path,
-                             &refs, &numrefs);
+       rc = get_dfs_referral(xid, ses, path, &refs, &numrefs);
        if (rc)
                goto out_unlock;
 
  * needs to be issued:
  * @xid: syscall xid
  * @ses: smb session to issue the request on
- * @nls_codepage: charset conversion
+ * @cp: codepage
  * @remap: path character remapping type
  * @path: path to lookup in DFS referral cache.
  *
  *
  * Return zero if the target was found, otherwise non-zero.
  */
-int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
-                  const struct nls_table *nls_codepage, int remap,
-                  const char *path, struct dfs_info3_param *ref,
+int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, const struct nls_table *cp,
+                  int remap, const char *path, struct dfs_info3_param *ref,
                   struct dfs_cache_tgt_list *tgt_list)
 {
        int rc;
        const char *npath;
        struct cache_entry *ce;
 
-       rc = get_normalized_path(path, &npath);
-       if (rc)
-               return rc;
+       npath = dfs_cache_canonical_path(path, cp, remap);
+       if (IS_ERR(npath))
+               return PTR_ERR(npath);
 
-       rc = cache_refresh_path(xid, ses, nls_codepage, remap, npath);
+       rc = cache_refresh_path(xid, ses, npath);
        if (rc)
                goto out_free_path;
 
        up_read(&htable_rw_lock);
 
 out_free_path:
-       free_normalized_path(path, npath);
+       kfree(npath);
        return rc;
 }
 
  * expired, nor create a new cache entry if @path hasn't been found. It heavily
  * relies on an existing cache entry.
  *
- * @path: path to lookup in the DFS referral cache.
+ * @path: canonical DFS path to lookup in the DFS referral cache.
  * @ref: when non-NULL, store single DFS referral result in it.
  * @tgt_list: when non-NULL, store complete DFS target list in it.
  *
                         struct dfs_cache_tgt_list *tgt_list)
 {
        int rc;
-       const char *npath;
        struct cache_entry *ce;
 
-       rc = get_normalized_path(path, &npath);
-       if (rc)
-               return rc;
-
-       cifs_dbg(FYI, "%s: path: %s\n", __func__, npath);
+       cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
 
        down_read(&htable_rw_lock);
 
-       ce = lookup_cache_entry(npath, NULL);
+       ce = lookup_cache_entry(path, NULL);
        if (IS_ERR(ce)) {
                rc = PTR_ERR(ce);
                goto out_unlock;
 
 out_unlock:
        up_read(&htable_rw_lock);
-       free_normalized_path(path, npath);
-
        return rc;
 }
 
  *
  * @xid: syscall id
  * @ses: smb session
- * @nls_codepage: charset conversion
+ * @cp: codepage
  * @remap: type of character remapping for paths
- * @path: path to lookup in DFS referral cache.
+ * @path: path to lookup in DFS referral cache
  * @it: DFS target iterator
  *
  * Return zero if the target hint was updated successfully, otherwise non-zero.
  */
 int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
-                            const struct nls_table *nls_codepage, int remap,
-                            const char *path,
+                            const struct nls_table *cp, int remap, const char *path,
                             const struct dfs_cache_tgt_iterator *it)
 {
        int rc;
        struct cache_entry *ce;
        struct cache_dfs_tgt *t;
 
-       rc = get_normalized_path(path, &npath);
-       if (rc)
-               return rc;
+       npath = dfs_cache_canonical_path(path, cp, remap);
+       if (IS_ERR(npath))
+               return PTR_ERR(npath);
 
        cifs_dbg(FYI, "%s: update target hint - path: %s\n", __func__, npath);
 
-       rc = cache_refresh_path(xid, ses, nls_codepage, remap, npath);
+       rc = cache_refresh_path(xid, ses, npath);
        if (rc)
                goto out_free_path;
 
 out_unlock:
        up_write(&htable_rw_lock);
 out_free_path:
-       free_normalized_path(path, npath);
-
+       kfree(npath);
        return rc;
 }
 
  * expired, nor create a new cache entry if @path hasn't been found. It heavily
  * relies on an existing cache entry.
  *
- * @path: path to lookup in DFS referral cache.
+ * @path: canonical DFS path to lookup in DFS referral cache.
  * @it: target iterator which contains the target hint to update the cache
  * entry with.
  *
  * Return zero if the target hint was updated successfully, otherwise non-zero.
  */
-int dfs_cache_noreq_update_tgthint(const char *path,
-                                  const struct dfs_cache_tgt_iterator *it)
+int dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt_iterator *it)
 {
        int rc;
-       const char *npath;
        struct cache_entry *ce;
        struct cache_dfs_tgt *t;
 
        if (!it)
                return -EINVAL;
 
-       rc = get_normalized_path(path, &npath);
-       if (rc)
-               return rc;
-
-       cifs_dbg(FYI, "%s: path: %s\n", __func__, npath);
+       cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
 
        down_write(&htable_rw_lock);
 
-       ce = lookup_cache_entry(npath, NULL);
+       ce = lookup_cache_entry(path, NULL);
        if (IS_ERR(ce)) {
                rc = PTR_ERR(ce);
                goto out_unlock;
 
 out_unlock:
        up_write(&htable_rw_lock);
-       free_normalized_path(path, npath);
-
        return rc;
 }
 
  * dfs_cache_get_tgt_referral - returns a DFS referral (@ref) from a given
  * target iterator (@it).
  *
- * @path: path to lookup in DFS referral cache.
+ * @path: canonical DFS path to lookup in DFS referral cache.
  * @it: DFS target iterator.
  * @ref: DFS referral pointer to set up the gathered information.
  *
  * Return zero if the DFS referral was set up correctly, otherwise non-zero.
  */
-int dfs_cache_get_tgt_referral(const char *path,
-                              const struct dfs_cache_tgt_iterator *it,
+int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iterator *it,
                               struct dfs_info3_param *ref)
 {
        int rc;
-       const char *npath;
        struct cache_entry *ce;
 
        if (!it || !ref)
                return -EINVAL;
 
-       rc = get_normalized_path(path, &npath);
-       if (rc)
-               return rc;
-
-       cifs_dbg(FYI, "%s: path: %s\n", __func__, npath);
+       cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
 
        down_read(&htable_rw_lock);
 
-       ce = lookup_cache_entry(npath, NULL);
+       ce = lookup_cache_entry(path, NULL);
        if (IS_ERR(ce)) {
                rc = PTR_ERR(ce);
                goto out_unlock;
 
 out_unlock:
        up_read(&htable_rw_lock);
-       free_normalized_path(path, npath);
-
        return rc;
 }
 
  *
  * Return zero if target was parsed correctly, otherwise non-zero.
  */
-int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it,
-                           char **share, char **prefix)
+int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share,
+                           char **prefix)
 {
        char *s, sep, *p;
        size_t len;
                ses = find_ipc_from_server_path(sessions, path);
                if (!IS_ERR(ses)) {
                        xid = get_xid();
-                       cache_refresh_path(xid, ses, cache_nlsc, tcon->remap, path);
+                       cache_refresh_path(xid, ses, path);
                        free_xid(xid);
                }
                cifs_put_tcon(tcon);
                                continue;
 
                        xid = get_xid();
-                       rc = get_dfs_referral(xid, ses, cache_nlsc, NO_MAP_UNI_RSVD, ce->path,
-                                             &refs, &numrefs);
+                       rc = get_dfs_referral(xid, ses, ce->path, &refs, &numrefs);
                        free_xid(xid);
 
                        if (!rc)
 
        struct list_head it_list;
 };
 
-extern int dfs_cache_init(void);
-extern void dfs_cache_destroy(void);
+int dfs_cache_init(void);
+void dfs_cache_destroy(void);
 extern const struct proc_ops dfscache_proc_ops;
 
-extern int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
-                         const struct nls_table *nls_codepage, int remap,
-                         const char *path, struct dfs_info3_param *ref,
-                         struct dfs_cache_tgt_list *tgt_list);
-extern int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
-                               struct dfs_cache_tgt_list *tgt_list);
-extern int dfs_cache_update_tgthint(const unsigned int xid,
-                                   struct cifs_ses *ses,
-                                   const struct nls_table *nls_codepage,
-                                   int remap, const char *path,
-                                   const struct dfs_cache_tgt_iterator *it);
-extern int
-dfs_cache_noreq_update_tgthint(const char *path,
-                              const struct dfs_cache_tgt_iterator *it);
-extern int dfs_cache_get_tgt_referral(const char *path,
-                                     const struct dfs_cache_tgt_iterator *it,
-                                     struct dfs_info3_param *ref);
-extern int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it,
-                                  char **share, char **prefix);
+int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, const struct nls_table *cp,
+                  int remap, const char *path, struct dfs_info3_param *ref,
+                  struct dfs_cache_tgt_list *tgt_list);
+int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
+                        struct dfs_cache_tgt_list *tgt_list);
+int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
+                            const struct nls_table *cp, int remap, const char *path,
+                            const struct dfs_cache_tgt_iterator *it);
+int dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt_iterator *it);
+int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iterator *it,
+                              struct dfs_info3_param *ref);
+int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share,
+                           char **prefix);
 void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id);
 void dfs_cache_add_refsrv_session(const uuid_t *mount_id, struct cifs_ses *ses);
+char *dfs_cache_canonical_path(const char *path, const struct nls_table *cp, int remap);
 
 static inline struct dfs_cache_tgt_iterator *
 dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,