Skip to content

Commit 38e04b3

Browse files
committed
Merge tag '6.3-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs client fixes from Steve French: "Seven cifs/smb3 client fixes, all also for stable: - four DFS fixes - multichannel reconnect fix - fix smb1 stats for cancel command - fix for set file size error path" * tag '6.3-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: use DFS root session instead of tcon ses cifs: return DFS root session id in DebugData cifs: fix use-after-free bug in refresh_cache_worker() cifs: set DFS root session in cifs_get_smb_ses() cifs: generate signkey for the channel that's reconnecting cifs: Fix smb2_set_path_size() cifs: Move the in_send statistic to __smb_send_rqst()
2 parents 0ddc84d + 6284e46 commit 38e04b3

File tree

14 files changed

+118
-195
lines changed

14 files changed

+118
-195
lines changed

fs/cifs/cifs_debug.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
420420
from_kuid(&init_user_ns, ses->linux_uid),
421421
from_kuid(&init_user_ns, ses->cred_uid));
422422

423+
if (ses->dfs_root_ses) {
424+
seq_printf(m, "\n\tDFS root session id: 0x%llx",
425+
ses->dfs_root_ses->Suid);
426+
}
427+
423428
spin_lock(&ses->chan_lock);
424429
if (CIFS_CHAN_NEEDS_RECONNECT(ses, 0))
425430
seq_puts(m, "\tPrimary channel: DISCONNECTED ");

fs/cifs/cifs_dfs_ref.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
179179
tmp.source = full_path;
180180
tmp.leaf_fullpath = NULL;
181181
tmp.UNC = tmp.prepath = NULL;
182+
tmp.dfs_root_ses = NULL;
182183

183184
rc = smb3_fs_context_dup(ctx, &tmp);
184185
if (rc) {

fs/cifs/cifs_fs_sb.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ struct cifs_sb_info {
6161
/* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
6262
char *prepath;
6363

64-
/* randomly generated 128-bit number for indexing dfs mount groups in referral cache */
65-
uuid_t dfs_mount_id;
6664
/*
6765
* Indicate whether serverino option was turned off later
6866
* (cifs_autodisable_serverino) in order to match new mounts.

fs/cifs/cifsglob.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,7 @@ struct cifs_tcon {
12331233
/* BB add field for back pointer to sb struct(s)? */
12341234
#ifdef CONFIG_CIFS_DFS_UPCALL
12351235
struct list_head ulist; /* cache update list */
1236+
struct list_head dfs_ses_list;
12361237
#endif
12371238
struct delayed_work query_interfaces; /* query interfaces workqueue job */
12381239
};
@@ -1749,9 +1750,8 @@ struct cifs_mount_ctx {
17491750
struct TCP_Server_Info *server;
17501751
struct cifs_ses *ses;
17511752
struct cifs_tcon *tcon;
1752-
struct cifs_ses *root_ses;
1753-
uuid_t mount_id;
17541753
char *origin_fullpath, *leaf_fullpath;
1754+
struct list_head dfs_ses_list;
17551755
};
17561756

17571757
static inline void free_dfs_info_param(struct dfs_info3_param *param)

fs/cifs/connect.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,6 +2229,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
22292229
* need to lock before changing something in the session.
22302230
*/
22312231
spin_lock(&cifs_tcp_ses_lock);
2232+
ses->dfs_root_ses = ctx->dfs_root_ses;
22322233
list_add(&ses->smb_ses_list, &server->smb_ses_list);
22332234
spin_unlock(&cifs_tcp_ses_lock);
22342235

@@ -3407,7 +3408,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34073408
bool isdfs;
34083409
int rc;
34093410

3410-
uuid_gen(&mnt_ctx.mount_id);
3411+
INIT_LIST_HEAD(&mnt_ctx.dfs_ses_list);
3412+
34113413
rc = dfs_mount_share(&mnt_ctx, &isdfs);
34123414
if (rc)
34133415
goto error;
@@ -3427,7 +3429,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34273429
kfree(cifs_sb->prepath);
34283430
cifs_sb->prepath = ctx->prepath;
34293431
ctx->prepath = NULL;
3430-
uuid_copy(&cifs_sb->dfs_mount_id, &mnt_ctx.mount_id);
34313432

34323433
out:
34333434
cifs_try_adding_channels(cifs_sb, mnt_ctx.ses);
@@ -3439,7 +3440,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34393440
return rc;
34403441

34413442
error:
3442-
dfs_cache_put_refsrv_sessions(&mnt_ctx.mount_id);
3443+
dfs_put_root_smb_sessions(&mnt_ctx.dfs_ses_list);
34433444
kfree(mnt_ctx.origin_fullpath);
34443445
kfree(mnt_ctx.leaf_fullpath);
34453446
cifs_mount_put_conns(&mnt_ctx);
@@ -3637,9 +3638,6 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
36373638
spin_unlock(&cifs_sb->tlink_tree_lock);
36383639

36393640
kfree(cifs_sb->prepath);
3640-
#ifdef CONFIG_CIFS_DFS_UPCALL
3641-
dfs_cache_put_refsrv_sessions(&cifs_sb->dfs_mount_id);
3642-
#endif
36433641
call_rcu(&cifs_sb->rcu, delayed_free);
36443642
}
36453643

fs/cifs/dfs.c

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -95,33 +95,40 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path)
9595
ctx->leaf_fullpath = (char *)full_path;
9696
rc = cifs_mount_get_session(mnt_ctx);
9797
ctx->leaf_fullpath = NULL;
98-
if (!rc) {
99-
struct cifs_ses *ses = mnt_ctx->ses;
10098

101-
mutex_lock(&ses->session_mutex);
102-
ses->dfs_root_ses = mnt_ctx->root_ses;
103-
mutex_unlock(&ses->session_mutex);
104-
}
10599
return rc;
106100
}
107101

108-
static void set_root_ses(struct cifs_mount_ctx *mnt_ctx)
102+
static int get_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
109103
{
110-
if (mnt_ctx->ses) {
104+
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
105+
struct dfs_root_ses *root_ses;
106+
struct cifs_ses *ses = mnt_ctx->ses;
107+
108+
if (ses) {
109+
root_ses = kmalloc(sizeof(*root_ses), GFP_KERNEL);
110+
if (!root_ses)
111+
return -ENOMEM;
112+
113+
INIT_LIST_HEAD(&root_ses->list);
114+
111115
spin_lock(&cifs_tcp_ses_lock);
112-
mnt_ctx->ses->ses_count++;
116+
ses->ses_count++;
113117
spin_unlock(&cifs_tcp_ses_lock);
114-
dfs_cache_add_refsrv_session(&mnt_ctx->mount_id, mnt_ctx->ses);
118+
root_ses->ses = ses;
119+
list_add_tail(&root_ses->list, &mnt_ctx->dfs_ses_list);
115120
}
116-
mnt_ctx->root_ses = mnt_ctx->ses;
121+
ctx->dfs_root_ses = ses;
122+
return 0;
117123
}
118124

119125
static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, const char *full_path,
120126
const struct dfs_cache_tgt_iterator *tit)
121127
{
122128
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
123129
struct dfs_info3_param ref = {};
124-
int rc;
130+
bool is_refsrv = false;
131+
int rc, rc2;
125132

126133
rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref);
127134
if (rc)
@@ -136,8 +143,7 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co
136143
if (rc)
137144
goto out;
138145

139-
if (ref.flags & DFSREF_REFERRAL_SERVER)
140-
set_root_ses(mnt_ctx);
146+
is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER);
141147

142148
rc = -EREMOTE;
143149
if (ref.flags & DFSREF_STORAGE_SERVER) {
@@ -146,13 +152,17 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co
146152
goto out;
147153

148154
/* some servers may not advertise referral capability under ref.flags */
149-
if (!(ref.flags & DFSREF_REFERRAL_SERVER) &&
150-
is_tcon_dfs(mnt_ctx->tcon))
151-
set_root_ses(mnt_ctx);
155+
is_refsrv |= is_tcon_dfs(mnt_ctx->tcon);
152156

153157
rc = cifs_is_path_remote(mnt_ctx);
154158
}
155159

160+
if (rc == -EREMOTE && is_refsrv) {
161+
rc2 = get_root_smb_session(mnt_ctx);
162+
if (rc2)
163+
rc = rc2;
164+
}
165+
156166
out:
157167
free_dfs_info_param(&ref);
158168
return rc;
@@ -165,6 +175,7 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
165175
char *ref_path = NULL, *full_path = NULL;
166176
struct dfs_cache_tgt_iterator *tit;
167177
struct TCP_Server_Info *server;
178+
struct cifs_tcon *tcon;
168179
char *origin_fullpath = NULL;
169180
int num_links = 0;
170181
int rc;
@@ -234,12 +245,22 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
234245

235246
if (!rc) {
236247
server = mnt_ctx->server;
248+
tcon = mnt_ctx->tcon;
237249

238250
mutex_lock(&server->refpath_lock);
239-
server->origin_fullpath = origin_fullpath;
240-
server->current_fullpath = server->leaf_fullpath;
251+
if (!server->origin_fullpath) {
252+
server->origin_fullpath = origin_fullpath;
253+
server->current_fullpath = server->leaf_fullpath;
254+
origin_fullpath = NULL;
255+
}
241256
mutex_unlock(&server->refpath_lock);
242-
origin_fullpath = NULL;
257+
258+
if (list_empty(&tcon->dfs_ses_list)) {
259+
list_replace_init(&mnt_ctx->dfs_ses_list,
260+
&tcon->dfs_ses_list);
261+
} else {
262+
dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
263+
}
243264
}
244265

245266
out:
@@ -260,7 +281,7 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
260281
rc = get_session(mnt_ctx, NULL);
261282
if (rc)
262283
return rc;
263-
mnt_ctx->root_ses = mnt_ctx->ses;
284+
ctx->dfs_root_ses = mnt_ctx->ses;
264285
/*
265286
* If called with 'nodfs' mount option, then skip DFS resolving. Otherwise unconditionally
266287
* try to get an DFS referral (even cached) to determine whether it is an DFS mount.
@@ -280,7 +301,9 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
280301
}
281302

282303
*isdfs = true;
283-
set_root_ses(mnt_ctx);
304+
rc = get_root_smb_session(mnt_ctx);
305+
if (rc)
306+
return rc;
284307

285308
return __dfs_mount_share(mnt_ctx);
286309
}

fs/cifs/dfs.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
#include "fs_context.h"
1111
#include "cifs_unicode.h"
1212

13+
struct dfs_root_ses {
14+
struct list_head list;
15+
struct cifs_ses *ses;
16+
};
17+
1318
int dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref,
1419
struct smb3_fs_context *ctx);
1520
int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs);
@@ -22,9 +27,10 @@ static inline char *dfs_get_path(struct cifs_sb_info *cifs_sb, const char *path)
2227
static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *path,
2328
struct dfs_info3_param *ref, struct dfs_cache_tgt_list *tl)
2429
{
30+
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
2531
struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
2632

27-
return dfs_cache_find(mnt_ctx->xid, mnt_ctx->root_ses, cifs_sb->local_nls,
33+
return dfs_cache_find(mnt_ctx->xid, ctx->dfs_root_ses, cifs_sb->local_nls,
2834
cifs_remap(cifs_sb), path, ref, tl);
2935
}
3036

@@ -43,4 +49,15 @@ static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page)
4349
true);
4450
}
4551

52+
static inline void dfs_put_root_smb_sessions(struct list_head *head)
53+
{
54+
struct dfs_root_ses *root, *tmp;
55+
56+
list_for_each_entry_safe(root, tmp, head, list) {
57+
list_del_init(&root->list);
58+
cifs_put_smb_ses(root->ses);
59+
kfree(root);
60+
}
61+
}
62+
4663
#endif /* _CIFS_DFS_H */

0 commit comments

Comments
 (0)