diff options
Diffstat (limited to 'fs/cifs/dfs.c')
-rw-r--r-- | fs/cifs/dfs.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/fs/cifs/dfs.c b/fs/cifs/dfs.c index 6505f1b20147..c8bda52fa096 100644 --- a/fs/cifs/dfs.c +++ b/fs/cifs/dfs.c @@ -99,18 +99,27 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path) return rc; } -static void set_root_ses(struct cifs_mount_ctx *mnt_ctx) +static int get_root_smb_session(struct cifs_mount_ctx *mnt_ctx) { struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; + struct dfs_root_ses *root_ses; struct cifs_ses *ses = mnt_ctx->ses; if (ses) { + root_ses = kmalloc(sizeof(*root_ses), GFP_KERNEL); + if (!root_ses) + return -ENOMEM; + + INIT_LIST_HEAD(&root_ses->list); + spin_lock(&cifs_tcp_ses_lock); ses->ses_count++; spin_unlock(&cifs_tcp_ses_lock); - dfs_cache_add_refsrv_session(&mnt_ctx->mount_id, ses); + root_ses->ses = ses; + list_add_tail(&root_ses->list, &mnt_ctx->dfs_ses_list); } - ctx->dfs_root_ses = mnt_ctx->ses; + ctx->dfs_root_ses = ses; + return 0; } static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, const char *full_path, @@ -118,7 +127,8 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co { struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; struct dfs_info3_param ref = {}; - int rc; + bool is_refsrv = false; + int rc, rc2; rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref); if (rc) @@ -133,8 +143,7 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co if (rc) goto out; - if (ref.flags & DFSREF_REFERRAL_SERVER) - set_root_ses(mnt_ctx); + is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER); rc = -EREMOTE; if (ref.flags & DFSREF_STORAGE_SERVER) { @@ -143,13 +152,17 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co goto out; /* some servers may not advertise referral capability under ref.flags */ - if (!(ref.flags & DFSREF_REFERRAL_SERVER) && - is_tcon_dfs(mnt_ctx->tcon)) - set_root_ses(mnt_ctx); + is_refsrv |= is_tcon_dfs(mnt_ctx->tcon); rc = cifs_is_path_remote(mnt_ctx); } + if (rc == -EREMOTE && is_refsrv) { + rc2 = get_root_smb_session(mnt_ctx); + if (rc2) + rc = rc2; + } + out: free_dfs_info_param(&ref); return rc; @@ -162,6 +175,7 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) char *ref_path = NULL, *full_path = NULL; struct dfs_cache_tgt_iterator *tit; struct TCP_Server_Info *server; + struct cifs_tcon *tcon; char *origin_fullpath = NULL; int num_links = 0; int rc; @@ -231,12 +245,22 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) if (!rc) { server = mnt_ctx->server; + tcon = mnt_ctx->tcon; mutex_lock(&server->refpath_lock); - server->origin_fullpath = origin_fullpath; - server->current_fullpath = server->leaf_fullpath; + if (!server->origin_fullpath) { + server->origin_fullpath = origin_fullpath; + server->current_fullpath = server->leaf_fullpath; + origin_fullpath = NULL; + } mutex_unlock(&server->refpath_lock); - origin_fullpath = NULL; + + if (list_empty(&tcon->dfs_ses_list)) { + list_replace_init(&mnt_ctx->dfs_ses_list, + &tcon->dfs_ses_list); + } else { + dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list); + } } out: @@ -277,7 +301,9 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs) } *isdfs = true; - set_root_ses(mnt_ctx); + rc = get_root_smb_session(mnt_ctx); + if (rc) + return rc; return __dfs_mount_share(mnt_ctx); } |