mirror of
https://github.com/torvalds/linux
synced 2024-09-20 02:57:25 +00:00
cifs: account for primary channel in the interface list
The refcounting of server interfaces should account for the primary channel too. Although this is not strictly necessary, doing so will account for the primary channel in DebugData. Cc: stable@vger.kernel.org Reviewed-by: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
a6d8fb54a5
commit
fa1d0508bd
|
@ -303,6 +303,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
|
||||||
struct cifs_server_iface *iface = NULL;
|
struct cifs_server_iface *iface = NULL;
|
||||||
struct cifs_server_iface *old_iface = NULL;
|
struct cifs_server_iface *old_iface = NULL;
|
||||||
struct cifs_server_iface *last_iface = NULL;
|
struct cifs_server_iface *last_iface = NULL;
|
||||||
|
struct sockaddr_storage ss;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
spin_lock(&ses->chan_lock);
|
spin_lock(&ses->chan_lock);
|
||||||
|
@ -321,6 +322,10 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
|
||||||
}
|
}
|
||||||
spin_unlock(&ses->chan_lock);
|
spin_unlock(&ses->chan_lock);
|
||||||
|
|
||||||
|
spin_lock(&server->srv_lock);
|
||||||
|
ss = server->dstaddr;
|
||||||
|
spin_unlock(&server->srv_lock);
|
||||||
|
|
||||||
spin_lock(&ses->iface_lock);
|
spin_lock(&ses->iface_lock);
|
||||||
if (!ses->iface_count) {
|
if (!ses->iface_count) {
|
||||||
spin_unlock(&ses->iface_lock);
|
spin_unlock(&ses->iface_lock);
|
||||||
|
@ -334,6 +339,16 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
|
||||||
|
|
||||||
/* then look for a new one */
|
/* then look for a new one */
|
||||||
list_for_each_entry(iface, &ses->iface_list, iface_head) {
|
list_for_each_entry(iface, &ses->iface_list, iface_head) {
|
||||||
|
if (!chan_index) {
|
||||||
|
/* if we're trying to get the updated iface for primary channel */
|
||||||
|
if (!cifs_match_ipaddr((struct sockaddr *) &ss,
|
||||||
|
(struct sockaddr *) &iface->sockaddr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
kref_get(&iface->refcount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* do not mix rdma and non-rdma interfaces */
|
/* do not mix rdma and non-rdma interfaces */
|
||||||
if (iface->rdma_capable != server->rdma)
|
if (iface->rdma_capable != server->rdma)
|
||||||
continue;
|
continue;
|
||||||
|
@ -360,6 +375,13 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
|
||||||
cifs_dbg(FYI, "unable to find a suitable iface\n");
|
cifs_dbg(FYI, "unable to find a suitable iface\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!chan_index && !iface) {
|
||||||
|
cifs_dbg(FYI, "unable to get the interface matching: %pIS\n",
|
||||||
|
&ss);
|
||||||
|
spin_unlock(&ses->iface_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* now drop the ref to the current iface */
|
/* now drop the ref to the current iface */
|
||||||
if (old_iface && iface) {
|
if (old_iface && iface) {
|
||||||
cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n",
|
cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n",
|
||||||
|
@ -382,6 +404,12 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
|
||||||
old_iface->weight_fulfilled--;
|
old_iface->weight_fulfilled--;
|
||||||
|
|
||||||
kref_put(&old_iface->refcount, release_iface);
|
kref_put(&old_iface->refcount, release_iface);
|
||||||
|
} else if (!chan_index) {
|
||||||
|
/* special case: update interface for primary channel */
|
||||||
|
cifs_dbg(FYI, "referencing primary channel iface: %pIS\n",
|
||||||
|
&iface->sockaddr);
|
||||||
|
iface->num_channels++;
|
||||||
|
iface->weight_fulfilled++;
|
||||||
} else {
|
} else {
|
||||||
WARN_ON(!iface);
|
WARN_ON(!iface);
|
||||||
cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr);
|
cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr);
|
||||||
|
|
|
@ -756,6 +756,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
|
||||||
unsigned int ret_data_len = 0;
|
unsigned int ret_data_len = 0;
|
||||||
struct network_interface_info_ioctl_rsp *out_buf = NULL;
|
struct network_interface_info_ioctl_rsp *out_buf = NULL;
|
||||||
struct cifs_ses *ses = tcon->ses;
|
struct cifs_ses *ses = tcon->ses;
|
||||||
|
struct TCP_Server_Info *pserver;
|
||||||
|
|
||||||
/* do not query too frequently */
|
/* do not query too frequently */
|
||||||
if (ses->iface_last_update &&
|
if (ses->iface_last_update &&
|
||||||
|
@ -780,6 +781,11 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
/* check if iface is still active */
|
||||||
|
pserver = ses->chans[0].server;
|
||||||
|
if (pserver && !cifs_chan_is_iface_active(ses, pserver))
|
||||||
|
cifs_chan_update_iface(ses, pserver);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(out_buf);
|
kfree(out_buf);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
Loading…
Reference in a new issue