Commit c870a8e7 authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French

cifs: handle different charsets in dfs cache

Convert all dfs paths to dfs cache's local codepage (@cache_cp) and
avoid mixing them with different charsets.
Signed-off-by: default avatarPaulo Alcantara (SUSE) <pc@cjr.nz>
Reviewed-by: default avatarAurelien Aptel <aaptel@suse.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent c9f71103
...@@ -72,9 +72,8 @@ struct cifs_sb_info { ...@@ -72,9 +72,8 @@ struct cifs_sb_info {
char *prepath; char *prepath;
/* /*
* Path initially provided by the mount call. We might connect * Canonical DFS path initially provided by the mount call. We might connect to something
* to something different via DFS but we want to keep it to do * different via DFS but we want to keep it to do failover properly.
* failover properly.
*/ */
char *origin_fullpath; /* \\HOST\SHARE\[OPTIONAL PATH] */ char *origin_fullpath; /* \\HOST\SHARE\[OPTIONAL PATH] */
/* randomly generated 128-bit number for indexing dfs mount groups in referral cache */ /* randomly generated 128-bit number for indexing dfs mount groups in referral cache */
......
...@@ -1093,8 +1093,7 @@ struct cifs_tcon { ...@@ -1093,8 +1093,7 @@ struct cifs_tcon {
struct cached_fid crfid; /* Cached root fid */ struct cached_fid crfid; /* Cached root fid */
/* BB add field for back pointer to sb struct(s)? */ /* BB add field for back pointer to sb struct(s)? */
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
char *dfs_path; char *dfs_path; /* canonical DFS path */
int remap:2;
struct list_head ulist; /* cache update list */ struct list_head ulist; /* cache update list */
#endif #endif
}; };
......
...@@ -3010,8 +3010,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, ...@@ -3010,8 +3010,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
return rc; return rc;
} }
static inline int get_next_dfs_tgt(const char *path, static int get_next_dfs_tgt(struct dfs_cache_tgt_list *tgt_list,
struct dfs_cache_tgt_list *tgt_list,
struct dfs_cache_tgt_iterator **tgt_it) struct dfs_cache_tgt_iterator **tgt_it)
{ {
if (!*tgt_it) if (!*tgt_it)
...@@ -3052,6 +3051,7 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_ ...@@ -3052,6 +3051,7 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_
struct cifs_ses **ses, struct cifs_tcon **tcon) struct cifs_ses **ses, struct cifs_tcon **tcon)
{ {
int rc; int rc;
char *npath = NULL;
struct dfs_cache_tgt_list tgt_list = {0}; struct dfs_cache_tgt_list tgt_list = {0};
struct dfs_cache_tgt_iterator *tgt_it = NULL; struct dfs_cache_tgt_iterator *tgt_it = NULL;
struct smb3_fs_context tmp_ctx = {NULL}; struct smb3_fs_context tmp_ctx = {NULL};
...@@ -3059,11 +3059,15 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_ ...@@ -3059,11 +3059,15 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
return -EOPNOTSUPP; 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);
cifs_dbg(FYI, "%s: path=%s full_path=%s\n", __func__, npath, full_path);
rc = dfs_cache_noreq_find(path, NULL, &tgt_list); rc = dfs_cache_noreq_find(npath, NULL, &tgt_list);
if (rc) 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 * 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. * test connection against new DFS targets.
...@@ -3077,11 +3081,11 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_ ...@@ -3077,11 +3081,11 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_
char *fake_devname = NULL, *mdata = NULL; char *fake_devname = NULL, *mdata = NULL;
/* Get next DFS target server - if any */ /* 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) if (rc)
break; break;
rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref); rc = dfs_cache_get_tgt_referral(npath, tgt_it, &ref);
if (rc) if (rc)
break; break;
...@@ -3130,6 +3134,7 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_ ...@@ -3130,6 +3134,7 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_
} }
out: out:
kfree(npath);
smb3_cleanup_fs_context_contents(&tmp_ctx); smb3_cleanup_fs_context_contents(&tmp_ctx);
dfs_cache_free_tgts(&tgt_list); dfs_cache_free_tgts(&tgt_list);
return rc; return rc;
...@@ -3287,11 +3292,6 @@ static void set_root_ses(struct cifs_sb_info *cifs_sb, const uuid_t *mount_id, s ...@@ -3287,11 +3292,6 @@ static void set_root_ses(struct cifs_sb_info *cifs_sb, const uuid_t *mount_id, s
if (ses) { if (ses) {
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
ses->ses_count++; 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); spin_unlock(&cifs_tcp_ses_lock);
dfs_cache_add_refsrv_session(mount_id, ses); dfs_cache_add_refsrv_session(mount_id, ses);
} }
...@@ -3343,17 +3343,25 @@ static int next_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context ...@@ -3343,17 +3343,25 @@ static int next_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context
} }
/* Check if resolved targets can handle any DFS referrals */ /* 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; int rc;
struct dfs_info3_param ref = {0}; struct dfs_info3_param ref = {0};
cifs_dbg(FYI, "%s: ref_path=%s\n", __func__, ref_path);
if (is_tcon_dfs(tcon)) { if (is_tcon_dfs(tcon)) {
*ref_server = true; *ref_server = true;
} else { } else {
cifs_dbg(FYI, "%s: ref_path=%s\n", __func__, ref_path); char *npath;
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(ref_path, &ref, NULL); rc = dfs_cache_noreq_find(npath, &ref, NULL);
kfree(npath);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: dfs_cache_noreq_find: failed (rc=%d)\n", __func__, rc); cifs_dbg(VFS, "%s: dfs_cache_noreq_find: failed (rc=%d)\n", __func__, rc);
return rc; return rc;
...@@ -3443,7 +3451,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) ...@@ -3443,7 +3451,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
continue; continue;
/* Make sure that requests go through new root servers */ /* 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) if (rc)
break; break;
if (ref_server) if (ref_server)
...@@ -3460,7 +3468,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) ...@@ -3460,7 +3468,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
goto error; goto error;
kfree(ref_path); kfree(ref_path);
ref_path = NULL;
/* /*
* Store DFS full path in both superblock and tree connect structures. * Store DFS full path in both superblock and tree connect structures.
* *
...@@ -3469,15 +3476,25 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) ...@@ -3469,15 +3476,25 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
* links, the prefix path is included in both and may be changed during reconnect. See * links, the prefix path is included in both and may be changed during reconnect. See
* cifs_tree_connect(). * cifs_tree_connect().
*/ */
cifs_sb->origin_fullpath = kstrdup(full_path, GFP_KERNEL); ref_path = dfs_cache_canonical_path(full_path, cifs_sb->local_nls, cifs_remap(cifs_sb));
if (!cifs_sb->origin_fullpath) { 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; rc = -ENOMEM;
goto error; goto error;
} }
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
tcon->dfs_path = full_path; tcon->dfs_path = ref_path;
full_path = NULL; ref_path = NULL;
tcon->remap = cifs_remap(cifs_sb);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
/* /*
......
This diff is collapsed.
...@@ -24,31 +24,26 @@ struct dfs_cache_tgt_iterator { ...@@ -24,31 +24,26 @@ struct dfs_cache_tgt_iterator {
struct list_head it_list; struct list_head it_list;
}; };
extern int dfs_cache_init(void); int dfs_cache_init(void);
extern void dfs_cache_destroy(void); void dfs_cache_destroy(void);
extern const struct proc_ops dfscache_proc_ops; extern const struct proc_ops dfscache_proc_ops;
extern int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, const struct nls_table *cp,
const struct nls_table *nls_codepage, int remap, int remap, const char *path, struct dfs_info3_param *ref,
const char *path, struct dfs_info3_param *ref,
struct dfs_cache_tgt_list *tgt_list); struct dfs_cache_tgt_list *tgt_list);
extern int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref, int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
struct dfs_cache_tgt_list *tgt_list); struct dfs_cache_tgt_list *tgt_list);
extern int dfs_cache_update_tgthint(const unsigned int xid, int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
struct cifs_ses *ses, const struct nls_table *cp, int remap, const char *path,
const struct nls_table *nls_codepage,
int remap, const char *path,
const struct dfs_cache_tgt_iterator *it); const struct dfs_cache_tgt_iterator *it);
extern int int dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt_iterator *it);
dfs_cache_noreq_update_tgthint(const char *path, int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iterator *it,
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); struct dfs_info3_param *ref);
extern int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share,
char **share, char **prefix); char **prefix);
void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id); 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); 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 * static inline struct dfs_cache_tgt_iterator *
dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl, dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment