Skip to content

Commit 3eca894

Browse files
committed
Merge tag '6.7-rc8-smb3-mchan-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: "Three important multichannel smb3 client fixes found in recent testing: - fix oops due to incorrect refcounting of interfaces after disabling multichannel - fix possible unrecoverable session state after disabling multichannel with active sessions - fix two places that were missing use of chan_lock" * tag '6.7-rc8-smb3-mchan-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: do not depend on release_iface for maintaining iface_list cifs: cifs_chan_is_iface_active should be called with chan_lock held cifs: after disabling multichannel, mark tcon for reconnect
2 parents 1f87478 + 09eeb07 commit 3eca894

File tree

3 files changed

+40
-22
lines changed

3 files changed

+40
-22
lines changed

fs/smb/client/cifsglob.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,6 @@ release_iface(struct kref *ref)
994994
struct cifs_server_iface *iface = container_of(ref,
995995
struct cifs_server_iface,
996996
refcount);
997-
list_del_init(&iface->iface_head);
998997
kfree(iface);
999998
}
1000999

fs/smb/client/connect.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -216,22 +216,29 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
216216
/* If server is a channel, select the primary channel */
217217
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
218218

219+
/*
220+
* if the server has been marked for termination, there is a
221+
* chance that the remaining channels all need reconnect. To be
222+
* on the safer side, mark the session and trees for reconnect
223+
* for this scenario. This might cause a few redundant session
224+
* setup and tree connect requests, but it is better than not doing
225+
* a tree connect when needed, and all following requests failing
226+
*/
227+
if (server->terminate) {
228+
mark_smb_session = true;
229+
server = pserver;
230+
}
219231

220232
spin_lock(&cifs_tcp_ses_lock);
221233
list_for_each_entry_safe(ses, nses, &pserver->smb_ses_list, smb_ses_list) {
222-
/*
223-
* if channel has been marked for termination, nothing to do
224-
* for the channel. in fact, we cannot find the channel for the
225-
* server. So safe to exit here
226-
*/
227-
if (server->terminate)
228-
break;
229-
230234
/* check if iface is still active */
231-
if (!cifs_chan_is_iface_active(ses, server))
235+
spin_lock(&ses->chan_lock);
236+
if (!cifs_chan_is_iface_active(ses, server)) {
237+
spin_unlock(&ses->chan_lock);
232238
cifs_chan_update_iface(ses, server);
239+
spin_lock(&ses->chan_lock);
240+
}
233241

234-
spin_lock(&ses->chan_lock);
235242
if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server)) {
236243
spin_unlock(&ses->chan_lock);
237244
continue;

fs/smb/client/smb2ops.c

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -595,16 +595,12 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
595595
}
596596

597597
/*
598-
* Go through iface_list and do kref_put to remove
599-
* any unused ifaces. ifaces in use will be removed
600-
* when the last user calls a kref_put on it
598+
* Go through iface_list and mark them as inactive
601599
*/
602600
list_for_each_entry_safe(iface, niface, &ses->iface_list,
603-
iface_head) {
601+
iface_head)
604602
iface->is_active = 0;
605-
kref_put(&iface->refcount, release_iface);
606-
ses->iface_count--;
607-
}
603+
608604
spin_unlock(&ses->iface_lock);
609605

610606
/*
@@ -678,10 +674,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
678674
iface_head) {
679675
ret = iface_cmp(iface, &tmp_iface);
680676
if (!ret) {
681-
/* just get a ref so that it doesn't get picked/freed */
682677
iface->is_active = 1;
683-
kref_get(&iface->refcount);
684-
ses->iface_count++;
685678
spin_unlock(&ses->iface_lock);
686679
goto next_iface;
687680
} else if (ret < 0) {
@@ -748,6 +741,20 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
748741
}
749742

750743
out:
744+
/*
745+
* Go through the list again and put the inactive entries
746+
*/
747+
spin_lock(&ses->iface_lock);
748+
list_for_each_entry_safe(iface, niface, &ses->iface_list,
749+
iface_head) {
750+
if (!iface->is_active) {
751+
list_del(&iface->iface_head);
752+
kref_put(&iface->refcount, release_iface);
753+
ses->iface_count--;
754+
}
755+
}
756+
spin_unlock(&ses->iface_lock);
757+
751758
return rc;
752759
}
753760

@@ -784,9 +791,14 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
784791
goto out;
785792

786793
/* check if iface is still active */
794+
spin_lock(&ses->chan_lock);
787795
pserver = ses->chans[0].server;
788-
if (pserver && !cifs_chan_is_iface_active(ses, pserver))
796+
if (pserver && !cifs_chan_is_iface_active(ses, pserver)) {
797+
spin_unlock(&ses->chan_lock);
789798
cifs_chan_update_iface(ses, pserver);
799+
spin_lock(&ses->chan_lock);
800+
}
801+
spin_unlock(&ses->chan_lock);
790802

791803
out:
792804
kfree(out_buf);

0 commit comments

Comments
 (0)