Commit fa1d0508 authored by Shyam Prasad N's avatar Shyam Prasad N Committed by Steve French
Browse files

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: default avatarPaulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: default avatarShyam Prasad N <sprasad@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent a6d8fb54
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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);
@@ -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;
@@ -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",
@@ -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);
+6 −0
Original line number Diff line number Diff line
@@ -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 &&
@@ -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;