Skip to content

Commit

Permalink
cifs: account for primary channel in the interface list
Browse files Browse the repository at this point in the history
[ Upstream commit fa1d050 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
sprasad-microsoft authored and gregkh committed Dec 3, 2023
1 parent 5488934 commit b24d42b
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
28 changes: 28 additions & 0 deletions fs/smb/client/sess.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
struct cifs_server_iface *iface = NULL;
struct cifs_server_iface *old_iface = NULL;
struct cifs_server_iface *last_iface = NULL;
struct sockaddr_storage ss;
int rc = 0;

spin_lock(&ses->chan_lock);
Expand All @@ -306,6 +307,10 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
}
spin_unlock(&ses->chan_lock);

spin_lock(&server->srv_lock);
ss = server->dstaddr;
spin_unlock(&server->srv_lock);

spin_lock(&ses->iface_lock);
if (!ses->iface_count) {
spin_unlock(&ses->iface_lock);
Expand All @@ -319,6 +324,16 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)

/* then look for a new one */
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 */
if (iface->rdma_capable != server->rdma)
continue;
Expand All @@ -345,6 +360,13 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
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 */
if (old_iface && iface) {
cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n",
Expand All @@ -367,6 +389,12 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
old_iface->weight_fulfilled--;

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 {
WARN_ON(!iface);
cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr);
Expand Down
6 changes: 6 additions & 0 deletions fs/smb/client/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
unsigned int ret_data_len = 0;
struct network_interface_info_ioctl_rsp *out_buf = NULL;
struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *pserver;

/* do not query too frequently */
if (ses->iface_last_update &&
Expand All @@ -776,6 +777,11 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
if (rc)
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:
kfree(out_buf);
return rc;
Expand Down

0 comments on commit b24d42b

Please sign in to comment.