Skip to content

Commit b54034a

Browse files
sprasad-microsoftSteve French
authored andcommitted
cifs: during reconnect, update interface if necessary
Going forward, the plan is to periodically query the server for it's interfaces (when multichannel is enabled). This change allows checking for inactive interfaces during reconnect, and reconnect to a new interface if necessary. Signed-off-by: Shyam Prasad N <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent aa45dad commit b54034a

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

fs/cifs/cifsproto.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,11 @@ cifs_chan_clear_need_reconnect(struct cifs_ses *ses,
636636
bool
637637
cifs_chan_needs_reconnect(struct cifs_ses *ses,
638638
struct TCP_Server_Info *server);
639+
bool
640+
cifs_chan_is_iface_active(struct cifs_ses *ses,
641+
struct TCP_Server_Info *server);
642+
int
643+
cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server);
639644

640645
void extract_unc_hostname(const char *unc, const char **h, size_t *len);
641646
int copy_path_name(char *dst, const char *src);

fs/cifs/connect.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
232232

233233
spin_lock(&cifs_tcp_ses_lock);
234234
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
235+
/* check if iface is still active */
236+
if (!cifs_chan_is_iface_active(ses, server))
237+
cifs_chan_update_iface(ses, server);
238+
235239
spin_lock(&ses->chan_lock);
236240
if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))
237241
goto next_session;

fs/cifs/sess.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,16 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses,
146146
return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);
147147
}
148148

149+
bool
150+
cifs_chan_is_iface_active(struct cifs_ses *ses,
151+
struct TCP_Server_Info *server)
152+
{
153+
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
154+
155+
return ses->chans[chan_index].iface &&
156+
ses->chans[chan_index].iface->is_active;
157+
}
158+
149159
/* returns number of channels added */
150160
int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
151161
{
@@ -244,6 +254,75 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
244254
return new_chan_count - old_chan_count;
245255
}
246256

257+
/*
258+
* update the iface for the channel if necessary.
259+
* will return 0 when iface is updated. 1 otherwise
260+
* Must be called with chan_lock held.
261+
*/
262+
int
263+
cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
264+
{
265+
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
266+
struct cifs_server_iface *iface = NULL;
267+
struct cifs_server_iface *old_iface = NULL;
268+
int rc = 0;
269+
270+
/* primary channel. This can never go away */
271+
if (!chan_index)
272+
return 0;
273+
274+
if (ses->chans[chan_index].iface) {
275+
old_iface = ses->chans[chan_index].iface;
276+
if (old_iface->is_active)
277+
return 1;
278+
}
279+
280+
spin_lock(&ses->iface_lock);
281+
282+
/* then look for a new one */
283+
list_for_each_entry(iface, &ses->iface_list, iface_head) {
284+
if (!iface->is_active ||
285+
(is_ses_using_iface(ses, iface) &&
286+
!iface->rss_capable)) {
287+
continue;
288+
}
289+
kref_get(&iface->refcount);
290+
}
291+
292+
if (!list_entry_is_head(iface, &ses->iface_list, iface_head)) {
293+
rc = 1;
294+
iface = NULL;
295+
cifs_dbg(FYI, "unable to find a suitable iface\n");
296+
}
297+
298+
ses->chans[chan_index].iface = iface;
299+
300+
/* now drop the ref to the current iface */
301+
if (old_iface && iface) {
302+
kref_put(&old_iface->refcount, release_iface);
303+
cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n",
304+
&old_iface->sockaddr,
305+
&iface->sockaddr);
306+
} else if (old_iface) {
307+
kref_put(&old_iface->refcount, release_iface);
308+
cifs_dbg(FYI, "releasing ref to iface: %pIS\n",
309+
&old_iface->sockaddr);
310+
} else {
311+
WARN_ON(!iface);
312+
cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr);
313+
}
314+
315+
spin_unlock(&ses->iface_lock);
316+
317+
/* No iface is found. if secondary chan, drop connection */
318+
if (!iface && CIFS_SERVER_IS_CHAN(server)) {
319+
cifs_put_tcp_session(server, false);
320+
ses->chans[chan_index].server = NULL;
321+
}
322+
323+
return rc;
324+
}
325+
247326
/*
248327
* If server is a channel of ses, return the corresponding enclosing
249328
* cifs_chan otherwise return NULL.

0 commit comments

Comments
 (0)