Skip to content

Commit 5752bf6

Browse files
sprasad-microsoftsmfrench
authored andcommitted
cifs: avoid parallel session setups on same channel
After allowing channels to reconnect in parallel, it now becomes important to take care that multiple processes do not call negotiate/session setup in parallel on the same channel. This change avoids that by marking a channel as "in_reconnect". During session setup if the channel in question has this flag set, we return immediately. Signed-off-by: Shyam Prasad N <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent dd3cd87 commit 5752bf6

File tree

5 files changed

+65
-7
lines changed

5 files changed

+65
-7
lines changed

fs/cifs/cifs_debug.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
419419
spin_lock(&ses->chan_lock);
420420
if (CIFS_CHAN_NEEDS_RECONNECT(ses, 0))
421421
seq_puts(m, "\tPrimary channel: DISCONNECTED ");
422+
if (CIFS_CHAN_IN_RECONNECT(ses, 0))
423+
seq_puts(m, "\t[RECONNECTING] ");
422424

423425
if (ses->chan_count > 1) {
424426
seq_printf(m, "\n\n\tExtra Channels: %zu ",
@@ -427,6 +429,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
427429
cifs_dump_channel(m, j, &ses->chans[j]);
428430
if (CIFS_CHAN_NEEDS_RECONNECT(ses, j))
429431
seq_puts(m, "\tDISCONNECTED ");
432+
if (CIFS_CHAN_IN_RECONNECT(ses, j))
433+
seq_puts(m, "\t[RECONNECTING] ");
430434
}
431435
}
432436
spin_unlock(&ses->chan_lock);

fs/cifs/cifsglob.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,7 @@ struct cifs_server_iface {
922922
};
923923

924924
struct cifs_chan {
925+
unsigned int in_reconnect : 1; /* if session setup in progress for this channel */
925926
struct TCP_Server_Info *server;
926927
__u8 signkey[SMB3_SIGN_KEY_SIZE];
927928
};
@@ -984,12 +985,16 @@ struct cifs_ses {
984985
#define CIFS_MAX_CHANNELS 16
985986
#define CIFS_ALL_CHANNELS_SET(ses) \
986987
((1UL << (ses)->chan_count) - 1)
988+
#define CIFS_ALL_CHANS_GOOD(ses) \
989+
(!(ses)->chans_need_reconnect)
987990
#define CIFS_ALL_CHANS_NEED_RECONNECT(ses) \
988991
((ses)->chans_need_reconnect == CIFS_ALL_CHANNELS_SET(ses))
989992
#define CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses) \
990993
((ses)->chans_need_reconnect = CIFS_ALL_CHANNELS_SET(ses))
991994
#define CIFS_CHAN_NEEDS_RECONNECT(ses, index) \
992995
test_bit((index), &(ses)->chans_need_reconnect)
996+
#define CIFS_CHAN_IN_RECONNECT(ses, index) \
997+
((ses)->chans[(index)].in_reconnect)
993998

994999
struct cifs_chan chans[CIFS_MAX_CHANNELS];
9951000
size_t chan_count;

fs/cifs/cifsproto.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,15 @@ unsigned int
619619
cifs_ses_get_chan_index(struct cifs_ses *ses,
620620
struct TCP_Server_Info *server);
621621
void
622+
cifs_chan_set_in_reconnect(struct cifs_ses *ses,
623+
struct TCP_Server_Info *server);
624+
void
625+
cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
626+
struct TCP_Server_Info *server);
627+
bool
628+
cifs_chan_in_reconnect(struct cifs_ses *ses,
629+
struct TCP_Server_Info *server);
630+
void
622631
cifs_chan_set_need_reconnect(struct cifs_ses *ses,
623632
struct TCP_Server_Info *server);
624633
void

fs/cifs/connect.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3995,17 +3995,27 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
39953995
int rc = -ENOSYS;
39963996
bool is_binding = false;
39973997

3998-
/* only send once per connect */
3999-
spin_lock(&ses->chan_lock);
4000-
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
4001-
spin_unlock(&ses->chan_lock);
40023998

40033999
spin_lock(&cifs_tcp_ses_lock);
4004-
if (ses->ses_status == SES_EXITING) {
4000+
if (ses->ses_status != SES_GOOD &&
4001+
ses->ses_status != SES_NEW &&
4002+
ses->ses_status != SES_NEED_RECON) {
40054003
spin_unlock(&cifs_tcp_ses_lock);
40064004
return 0;
40074005
}
40084006

4007+
/* only send once per connect */
4008+
spin_lock(&ses->chan_lock);
4009+
if (CIFS_ALL_CHANS_GOOD(ses) ||
4010+
cifs_chan_in_reconnect(ses, server)) {
4011+
spin_unlock(&ses->chan_lock);
4012+
spin_unlock(&cifs_tcp_ses_lock);
4013+
return 0;
4014+
}
4015+
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
4016+
cifs_chan_set_in_reconnect(ses, server);
4017+
spin_unlock(&ses->chan_lock);
4018+
40094019
if (!is_binding)
40104020
ses->ses_status = SES_IN_SETUP;
40114021
spin_unlock(&cifs_tcp_ses_lock);
@@ -4035,16 +4045,19 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
40354045
spin_lock(&cifs_tcp_ses_lock);
40364046
if (ses->ses_status == SES_IN_SETUP)
40374047
ses->ses_status = SES_NEED_RECON;
4048+
spin_lock(&ses->chan_lock);
4049+
cifs_chan_clear_in_reconnect(ses, server);
4050+
spin_unlock(&ses->chan_lock);
40384051
spin_unlock(&cifs_tcp_ses_lock);
40394052
} else {
40404053
spin_lock(&cifs_tcp_ses_lock);
40414054
if (ses->ses_status == SES_IN_SETUP)
40424055
ses->ses_status = SES_GOOD;
4043-
spin_unlock(&cifs_tcp_ses_lock);
4044-
40454056
spin_lock(&ses->chan_lock);
4057+
cifs_chan_clear_in_reconnect(ses, server);
40464058
cifs_chan_clear_need_reconnect(ses, server);
40474059
spin_unlock(&ses->chan_lock);
4060+
spin_unlock(&cifs_tcp_ses_lock);
40484061
}
40494062

40504063
return rc;

fs/cifs/sess.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,33 @@ cifs_ses_get_chan_index(struct cifs_ses *ses,
8585
return 0;
8686
}
8787

88+
void
89+
cifs_chan_set_in_reconnect(struct cifs_ses *ses,
90+
struct TCP_Server_Info *server)
91+
{
92+
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
93+
94+
ses->chans[chan_index].in_reconnect = true;
95+
}
96+
97+
void
98+
cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
99+
struct TCP_Server_Info *server)
100+
{
101+
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
102+
103+
ses->chans[chan_index].in_reconnect = false;
104+
}
105+
106+
bool
107+
cifs_chan_in_reconnect(struct cifs_ses *ses,
108+
struct TCP_Server_Info *server)
109+
{
110+
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
111+
112+
return CIFS_CHAN_IN_RECONNECT(ses, chan_index);
113+
}
114+
88115
void
89116
cifs_chan_set_need_reconnect(struct cifs_ses *ses,
90117
struct TCP_Server_Info *server)

0 commit comments

Comments
 (0)