Skip to content

Commit 0c51cc6

Browse files
sprasad-microsoftSteve French
authored andcommitted
cifs: handle cases where a channel is closed
So far, SMB multichannel could only scale up, but not scale down the number of channels. In this series of patch, we now allow the client to deal with the case of multichannel disabled on the server when the share is mounted. With that change, we now need the ability to scale down the channels. This change allows the client to deal with cases of missing channels more gracefully. Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 1bc081b commit 0c51cc6

File tree

6 files changed

+43
-7
lines changed

6 files changed

+43
-7
lines changed

fs/smb/client/cifs_debug.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
136136
{
137137
struct TCP_Server_Info *server = chan->server;
138138

139+
if (!server) {
140+
seq_printf(m, "\n\n\t\tChannel: %d DISABLED", i+1);
141+
return;
142+
}
143+
139144
seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
140145
"\n\t\tNumber of credits: %d,%d,%d Dialect 0x%x"
141146
"\n\t\tTCP status: %d Instance: %d"

fs/smb/client/cifsglob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,7 @@ struct cifs_ses {
10501050
spinlock_t chan_lock;
10511051
/* ========= begin: protected by chan_lock ======== */
10521052
#define CIFS_MAX_CHANNELS 16
1053+
#define CIFS_INVAL_CHAN_INDEX (-1)
10531054
#define CIFS_ALL_CHANNELS_SET(ses) \
10541055
((1UL << (ses)->chan_count) - 1)
10551056
#define CIFS_ALL_CHANS_GOOD(ses) \

fs/smb/client/cifsproto.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ bool is_server_using_iface(struct TCP_Server_Info *server,
616616
bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);
617617
void cifs_ses_mark_for_reconnect(struct cifs_ses *ses);
618618

619-
unsigned int
619+
int
620620
cifs_ses_get_chan_index(struct cifs_ses *ses,
621621
struct TCP_Server_Info *server);
622622
void

fs/smb/client/connect.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,12 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
173173
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
174174
spin_lock(&ses->chan_lock);
175175
for (i = 0; i < ses->chan_count; i++) {
176+
if (!ses->chans[i].server)
177+
continue;
178+
176179
spin_lock(&ses->chans[i].server->srv_lock);
177-
ses->chans[i].server->tcpStatus = CifsNeedReconnect;
180+
if (ses->chans[i].server->tcpStatus != CifsExiting)
181+
ses->chans[i].server->tcpStatus = CifsNeedReconnect;
178182
spin_unlock(&ses->chans[i].server->srv_lock);
179183
}
180184
spin_unlock(&ses->chan_lock);

fs/smb/client/sess.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
6969

7070
/* channel helper functions. assumed that chan_lock is held by caller. */
7171

72-
unsigned int
72+
int
7373
cifs_ses_get_chan_index(struct cifs_ses *ses,
7474
struct TCP_Server_Info *server)
7575
{
@@ -85,14 +85,17 @@ cifs_ses_get_chan_index(struct cifs_ses *ses,
8585
cifs_dbg(VFS, "unable to get chan index for server: 0x%llx",
8686
server->conn_id);
8787
WARN_ON(1);
88-
return 0;
88+
return CIFS_INVAL_CHAN_INDEX;
8989
}
9090

9191
void
9292
cifs_chan_set_in_reconnect(struct cifs_ses *ses,
9393
struct TCP_Server_Info *server)
9494
{
95-
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
95+
int chan_index = cifs_ses_get_chan_index(ses, server);
96+
97+
if (chan_index == CIFS_INVAL_CHAN_INDEX)
98+
return;
9699

97100
ses->chans[chan_index].in_reconnect = true;
98101
}
@@ -102,6 +105,8 @@ cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
102105
struct TCP_Server_Info *server)
103106
{
104107
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
108+
if (chan_index == CIFS_INVAL_CHAN_INDEX)
109+
return;
105110

106111
ses->chans[chan_index].in_reconnect = false;
107112
}
@@ -111,6 +116,8 @@ cifs_chan_in_reconnect(struct cifs_ses *ses,
111116
struct TCP_Server_Info *server)
112117
{
113118
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
119+
if (chan_index == CIFS_INVAL_CHAN_INDEX)
120+
return true; /* err on the safer side */
114121

115122
return CIFS_CHAN_IN_RECONNECT(ses, chan_index);
116123
}
@@ -120,6 +127,8 @@ cifs_chan_set_need_reconnect(struct cifs_ses *ses,
120127
struct TCP_Server_Info *server)
121128
{
122129
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
130+
if (chan_index == CIFS_INVAL_CHAN_INDEX)
131+
return;
123132

124133
set_bit(chan_index, &ses->chans_need_reconnect);
125134
cifs_dbg(FYI, "Set reconnect bitmask for chan %u; now 0x%lx\n",
@@ -131,6 +140,8 @@ cifs_chan_clear_need_reconnect(struct cifs_ses *ses,
131140
struct TCP_Server_Info *server)
132141
{
133142
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
143+
if (chan_index == CIFS_INVAL_CHAN_INDEX)
144+
return;
134145

135146
clear_bit(chan_index, &ses->chans_need_reconnect);
136147
cifs_dbg(FYI, "Cleared reconnect bitmask for chan %u; now 0x%lx\n",
@@ -142,6 +153,8 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses,
142153
struct TCP_Server_Info *server)
143154
{
144155
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
156+
if (chan_index == CIFS_INVAL_CHAN_INDEX)
157+
return true; /* err on the safer side */
145158

146159
return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);
147160
}
@@ -151,6 +164,8 @@ cifs_chan_is_iface_active(struct cifs_ses *ses,
151164
struct TCP_Server_Info *server)
152165
{
153166
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
167+
if (chan_index == CIFS_INVAL_CHAN_INDEX)
168+
return true; /* err on the safer side */
154169

155170
return ses->chans[chan_index].iface &&
156171
ses->chans[chan_index].iface->is_active;
@@ -269,7 +284,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
269284

270285
spin_lock(&ses->chan_lock);
271286
chan_index = cifs_ses_get_chan_index(ses, server);
272-
if (!chan_index) {
287+
if (chan_index == CIFS_INVAL_CHAN_INDEX) {
273288
spin_unlock(&ses->chan_lock);
274289
return 0;
275290
}
@@ -319,6 +334,11 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
319334

320335
spin_lock(&ses->chan_lock);
321336
chan_index = cifs_ses_get_chan_index(ses, server);
337+
if (chan_index == CIFS_INVAL_CHAN_INDEX) {
338+
spin_unlock(&ses->chan_lock);
339+
return 0;
340+
}
341+
322342
ses->chans[chan_index].iface = iface;
323343

324344
/* No iface is found. if secondary chan, drop connection */

fs/smb/client/smb2transport.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,13 @@ generate_smb3signingkey(struct cifs_ses *ses,
413413
ses->ses_status == SES_GOOD);
414414

415415
chan_index = cifs_ses_get_chan_index(ses, server);
416-
/* TODO: introduce ref counting for channels when the can be freed */
416+
if (chan_index == CIFS_INVAL_CHAN_INDEX) {
417+
spin_unlock(&ses->chan_lock);
418+
spin_unlock(&ses->ses_lock);
419+
420+
return -EINVAL;
421+
}
422+
417423
spin_unlock(&ses->chan_lock);
418424
spin_unlock(&ses->ses_lock);
419425

0 commit comments

Comments
 (0)