Skip to content

Commit f486ef8

Browse files
sprasad-microsoftsmfrench
authored andcommitted
cifs: use the chans_need_reconnect bitmap for reconnect status
We use the concept of "binding" when one of the secondary channel is in the process of connecting/reconnecting to the server. Till this binding process completes, and the channel is bound to an existing session, we redirect traffic from other established channels on the binding channel, effectively blocking all traffic till individual channels get reconnected. With my last set of commits, we can get rid of this binding serialization. We now have a bitmap of connection states for each channel. We will use this bitmap instead for tracking channel status. Having a bitmap also now enables us to keep the session alive, as long as even a single channel underneath is alive. Unfortunately, this also meant that we need to supply the tcp connection info for the channel during all negotiate and session setup functions. These changes have resulted in a slightly bigger code churn. However, I expect perf and robustness improvements in the mchan scenario after this change. Signed-off-by: Shyam Prasad N <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent d1a931c commit f486ef8

15 files changed

+236
-207
lines changed

fs/cifs/cifs_spnego.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ struct key_type cifs_spnego_key_type = {
8484

8585
/* get a key struct with a SPNEGO security blob, suitable for session setup */
8686
struct key *
87-
cifs_get_spnego_key(struct cifs_ses *sesInfo)
87+
cifs_get_spnego_key(struct cifs_ses *sesInfo,
88+
struct TCP_Server_Info *server)
8889
{
89-
struct TCP_Server_Info *server = cifs_ses_server(sesInfo);
9090
struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
9191
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
9292
char *description, *dp;

fs/cifs/cifs_spnego.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ struct cifs_spnego_msg {
2929

3030
#ifdef __KERNEL__
3131
extern struct key_type cifs_spnego_key_type;
32-
extern struct key *cifs_get_spnego_key(struct cifs_ses *sesInfo);
32+
extern struct key *cifs_get_spnego_key(struct cifs_ses *sesInfo,
33+
struct TCP_Server_Info *server);
3334
#endif /* KERNEL */
3435

3536
#endif /* _CIFS_SPNEGO_H */

fs/cifs/cifsglob.h

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,16 @@ struct smb_version_operations {
263263
/* check if we need to negotiate */
264264
bool (*need_neg)(struct TCP_Server_Info *);
265265
/* negotiate to the server */
266-
int (*negotiate)(const unsigned int, struct cifs_ses *);
266+
int (*negotiate)(const unsigned int xid,
267+
struct cifs_ses *ses,
268+
struct TCP_Server_Info *server);
267269
/* set negotiated write size */
268270
unsigned int (*negotiate_wsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx);
269271
/* set negotiated read size */
270272
unsigned int (*negotiate_rsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx);
271273
/* setup smb sessionn */
272274
int (*sess_setup)(const unsigned int, struct cifs_ses *,
275+
struct TCP_Server_Info *server,
273276
const struct nls_table *);
274277
/* close smb session */
275278
int (*logoff)(const unsigned int, struct cifs_ses *);
@@ -414,7 +417,8 @@ struct smb_version_operations {
414417
void (*set_lease_key)(struct inode *, struct cifs_fid *);
415418
/* generate new lease key */
416419
void (*new_lease_key)(struct cifs_fid *);
417-
int (*generate_signingkey)(struct cifs_ses *);
420+
int (*generate_signingkey)(struct cifs_ses *ses,
421+
struct TCP_Server_Info *server);
418422
int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *,
419423
bool allocate_crypto);
420424
int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
@@ -940,15 +944,12 @@ struct cifs_ses {
940944
enum securityEnum sectype; /* what security flavor was specified? */
941945
bool sign; /* is signing required? */
942946
bool domainAuto:1;
943-
bool binding:1; /* are we binding the session? */
944947
__u16 session_flags;
945948
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
946949
__u8 smb3encryptionkey[SMB3_ENC_DEC_KEY_SIZE];
947950
__u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE];
948951
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
949952

950-
__u8 binding_preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
951-
952953
/*
953954
* Network interfaces available on the server this session is
954955
* connected to.
@@ -976,7 +977,6 @@ struct cifs_ses {
976977
test_bit((index), &(ses)->chans_need_reconnect)
977978

978979
struct cifs_chan chans[CIFS_MAX_CHANNELS];
979-
struct cifs_chan *binding_chan;
980980
size_t chan_count;
981981
size_t chan_max;
982982
atomic_t chan_seq; /* round robin state */
@@ -985,42 +985,16 @@ struct cifs_ses {
985985
* chans_need_reconnect is a bitmap indicating which of the channels
986986
* under this smb session needs to be reconnected.
987987
* If not multichannel session, only one bit will be used.
988+
*
989+
* We will ask for sess and tcon reconnection only if all the
990+
* channels are marked for needing reconnection. This will
991+
* enable the sessions on top to continue to live till any
992+
* of the channels below are active.
988993
*/
989994
unsigned long chans_need_reconnect;
990995
/* ========= end: protected by chan_lock ======== */
991996
};
992997

993-
/*
994-
* When binding a new channel, we need to access the channel which isn't fully
995-
* established yet.
996-
*/
997-
998-
static inline
999-
struct cifs_chan *cifs_ses_binding_channel(struct cifs_ses *ses)
1000-
{
1001-
if (ses->binding)
1002-
return ses->binding_chan;
1003-
else
1004-
return NULL;
1005-
}
1006-
1007-
/*
1008-
* Returns the server pointer of the session. When binding a new
1009-
* channel this returns the last channel which isn't fully established
1010-
* yet.
1011-
*
1012-
* This function should be use for negprot/sess.setup codepaths. For
1013-
* the other requests see cifs_pick_channel().
1014-
*/
1015-
static inline
1016-
struct TCP_Server_Info *cifs_ses_server(struct cifs_ses *ses)
1017-
{
1018-
if (ses->binding)
1019-
return ses->binding_chan->server;
1020-
else
1021-
return ses->server;
1022-
}
1023-
1024998
static inline bool
1025999
cap_unix(struct cifs_ses *ses)
10261000
{

fs/cifs/cifsproto.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
164164
extern enum securityEnum select_sectype(struct TCP_Server_Info *server,
165165
enum securityEnum requested);
166166
extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
167+
struct TCP_Server_Info *server,
167168
const struct nls_table *nls_cp);
168169
extern struct timespec64 cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
169170
extern u64 cifs_UnixTimeToNT(struct timespec64);
@@ -293,11 +294,15 @@ extern int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon,
293294
const struct nls_table *nlsc);
294295

295296
extern int cifs_negotiate_protocol(const unsigned int xid,
296-
struct cifs_ses *ses);
297+
struct cifs_ses *ses,
298+
struct TCP_Server_Info *server);
297299
extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
300+
struct TCP_Server_Info *server,
298301
struct nls_table *nls_info);
299302
extern int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required);
300-
extern int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses);
303+
extern int CIFSSMBNegotiate(const unsigned int xid,
304+
struct cifs_ses *ses,
305+
struct TCP_Server_Info *server);
301306

302307
extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
303308
const char *tree, struct cifs_tcon *tcon,
@@ -504,8 +509,10 @@ extern int cifs_verify_signature(struct smb_rqst *rqst,
504509
extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
505510
extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
506511
extern int calc_seckey(struct cifs_ses *);
507-
extern int generate_smb30signingkey(struct cifs_ses *);
508-
extern int generate_smb311signingkey(struct cifs_ses *);
512+
extern int generate_smb30signingkey(struct cifs_ses *ses,
513+
struct TCP_Server_Info *server);
514+
extern int generate_smb311signingkey(struct cifs_ses *ses,
515+
struct TCP_Server_Info *server);
509516

510517
extern int CIFSSMBCopy(unsigned int xid,
511518
struct cifs_tcon *source_tcon,

fs/cifs/cifssmb.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
199199
spin_lock(&ses->chan_lock);
200200
if (!cifs_chan_needs_reconnect(ses, server)) {
201201
spin_unlock(&ses->chan_lock);
202-
/* this just means that we only need to tcon */
202+
203+
/* this means that we only need to tree connect */
203204
if (tcon->need_reconnect)
204205
goto skip_sess_setup;
205206

@@ -209,9 +210,9 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
209210
}
210211
spin_unlock(&ses->chan_lock);
211212

212-
rc = cifs_negotiate_protocol(0, ses);
213+
rc = cifs_negotiate_protocol(0, ses, server);
213214
if (!rc)
214-
rc = cifs_setup_session(0, ses, nls_codepage);
215+
rc = cifs_setup_session(0, ses, server, nls_codepage);
215216

216217
/* do we need to reconnect tcon? */
217218
if (rc || !tcon->need_reconnect) {
@@ -503,14 +504,15 @@ should_set_ext_sec_flag(enum securityEnum sectype)
503504
}
504505

505506
int
506-
CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
507+
CIFSSMBNegotiate(const unsigned int xid,
508+
struct cifs_ses *ses,
509+
struct TCP_Server_Info *server)
507510
{
508511
NEGOTIATE_REQ *pSMB;
509512
NEGOTIATE_RSP *pSMBr;
510513
int rc = 0;
511514
int bytes_returned;
512515
int i;
513-
struct TCP_Server_Info *server = ses->server;
514516
u16 count;
515517

516518
if (!server) {

fs/cifs/connect.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ static void cifs_resolve_server(struct work_struct *work)
169169
*/
170170
static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server)
171171
{
172+
unsigned int num_sessions = 0;
172173
struct cifs_ses *ses;
173174
struct cifs_tcon *tcon;
174175
struct mid_q_entry *mid, *nmid;
@@ -201,6 +202,8 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server
201202
if (!CIFS_ALL_CHANS_NEED_RECONNECT(ses))
202203
goto next_session;
203204

205+
num_sessions++;
206+
204207
list_for_each_entry(tcon, &ses->tcon_list, tcon_list)
205208
tcon->need_reconnect = true;
206209
if (ses->tcon_ipc)
@@ -211,6 +214,14 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server
211214
}
212215
spin_unlock(&cifs_tcp_ses_lock);
213216

217+
if (num_sessions == 0)
218+
return;
219+
/*
220+
* before reconnecting the tcp session, mark the smb session (uid)
221+
* and the tid bad so they are not used until reconnected
222+
*/
223+
cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect\n",
224+
__func__);
214225
/* do not want to be sending data on a socket we are freeing */
215226
cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
216227
mutex_lock(&server->srv_mutex);
@@ -2005,7 +2016,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
20052016
spin_unlock(&ses->chan_lock);
20062017
cifs_dbg(FYI, "Session needs reconnect\n");
20072018

2008-
rc = cifs_negotiate_protocol(xid, ses);
2019+
rc = cifs_negotiate_protocol(xid, ses, server);
20092020
if (rc) {
20102021
mutex_unlock(&ses->session_mutex);
20112022
/* problem -- put our ses reference */
@@ -2014,7 +2025,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
20142025
return ERR_PTR(rc);
20152026
}
20162027

2017-
rc = cifs_setup_session(xid, ses,
2028+
rc = cifs_setup_session(xid, ses, server,
20182029
ctx->local_nls);
20192030
if (rc) {
20202031
mutex_unlock(&ses->session_mutex);
@@ -2086,9 +2097,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
20862097
ses->chans_need_reconnect = 1;
20872098
spin_unlock(&ses->chan_lock);
20882099

2089-
rc = cifs_negotiate_protocol(xid, ses);
2100+
rc = cifs_negotiate_protocol(xid, ses, server);
20902101
if (!rc)
2091-
rc = cifs_setup_session(xid, ses, ctx->local_nls);
2102+
rc = cifs_setup_session(xid, ses, server, ctx->local_nls);
20922103

20932104
/* each channel uses a different signing key */
20942105
memcpy(ses->chans[0].signkey, ses->smb3signingkey,
@@ -3820,10 +3831,10 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
38203831
}
38213832

38223833
int
3823-
cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
3834+
cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
3835+
struct TCP_Server_Info *server)
38243836
{
38253837
int rc = 0;
3826-
struct TCP_Server_Info *server = cifs_ses_server(ses);
38273838

38283839
if (!server->ops->need_neg || !server->ops->negotiate)
38293840
return -ENOSYS;
@@ -3832,7 +3843,7 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
38323843
if (!server->ops->need_neg(server))
38333844
return 0;
38343845

3835-
rc = server->ops->negotiate(xid, ses);
3846+
rc = server->ops->negotiate(xid, ses, server);
38363847
if (rc == 0) {
38373848
spin_lock(&GlobalMid_Lock);
38383849
if (server->tcpStatus == CifsNeedNegotiate)
@@ -3847,12 +3858,17 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
38473858

38483859
int
38493860
cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
3861+
struct TCP_Server_Info *server,
38503862
struct nls_table *nls_info)
38513863
{
38523864
int rc = -ENOSYS;
3853-
struct TCP_Server_Info *server = cifs_ses_server(ses);
3865+
bool is_binding = false;
3866+
3867+
spin_lock(&ses->chan_lock);
3868+
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
3869+
spin_unlock(&ses->chan_lock);
38543870

3855-
if (!ses->binding) {
3871+
if (!is_binding) {
38563872
ses->capabilities = server->capabilities;
38573873
if (!linuxExtEnabled)
38583874
ses->capabilities &= (~server->vals->cap_unix);
@@ -3870,7 +3886,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
38703886
server->sec_mode, server->capabilities, server->timeAdj);
38713887

38723888
if (server->ops->sess_setup)
3873-
rc = server->ops->sess_setup(xid, ses, nls_info);
3889+
rc = server->ops->sess_setup(xid, ses, server, nls_info);
38743890

38753891
if (rc)
38763892
cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);

fs/cifs/ntlmssp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ typedef struct _AUTHENTICATE_MESSAGE {
121121
int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
122122
int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen,
123123
struct cifs_ses *ses,
124+
struct TCP_Server_Info *server,
124125
const struct nls_table *nls_cp);
125126
int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
126127
struct cifs_ses *ses,
128+
struct TCP_Server_Info *server,
127129
const struct nls_table *nls_cp);

0 commit comments

Comments
 (0)