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
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>
  • Loading branch information
Shyam Prasad N authored and Steve French committed Nov 9, 2023
1 parent a6d8fb5 commit fa1d050
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 @@ -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 *old_iface = NULL;
struct cifs_server_iface *last_iface = NULL;
struct sockaddr_storage ss;
int rc = 0;

spin_lock(&ses->chan_lock);
Expand All @@ -321,6 +322,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 @@ -334,6 +339,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 @@ -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");
}

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 @@ -382,6 +404,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 @@ -756,6 +756,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 @@ -780,6 +781,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 fa1d050

Please sign in to comment.