Commit 7643dbd9 authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French
Browse files

smb: client: don't retry IO on failed negprotos with soft mounts



If @server->tcpStatus is set to CifsNeedReconnect after acquiring
@ses->session_mutex in smb2_reconnect() or cifs_reconnect_tcon(), it
means that a concurrent thread failed to negotiate, in which case the
server is no longer responding to any SMB requests, so there is no
point making the caller retry the IO by returning -EAGAIN.

Fix this by returning -EHOSTDOWN to the callers on soft mounts.

Cc: David Howells <dhowells@redhat.com>
Reported-by: default avatarJay Shin <jaeshin@redhat.com>
Signed-off-by: default avatarPaulo Alcantara (Red Hat) <pc@manguebit.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 4701f33a
Loading
Loading
Loading
Loading
+27 −19
Original line number Diff line number Diff line
@@ -114,19 +114,23 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)

	mutex_lock(&ses->session_mutex);
	/*
	 * Recheck after acquire mutex. If another thread is negotiating
	 * and the server never sends an answer the socket will be closed
	 * and tcpStatus set to reconnect.
	 * Handle the case where a concurrent thread failed to negotiate or
	 * killed a channel.
	 */
	spin_lock(&server->srv_lock);
	if (server->tcpStatus == CifsNeedReconnect) {
	switch (server->tcpStatus) {
	case CifsExiting:
		spin_unlock(&server->srv_lock);
		mutex_unlock(&ses->session_mutex);

		if (tcon->retry)
		return -EHOSTDOWN;
	case CifsNeedReconnect:
		spin_unlock(&server->srv_lock);
		mutex_unlock(&ses->session_mutex);
		if (!tcon->retry)
			return -EHOSTDOWN;
		goto again;
		rc = -EHOSTDOWN;
		goto out;
	default:
		break;
	}
	spin_unlock(&server->srv_lock);

@@ -152,7 +156,12 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
	spin_unlock(&ses->ses_lock);

	rc = cifs_negotiate_protocol(0, ses, server);
	if (!rc) {
	if (rc) {
		mutex_unlock(&ses->session_mutex);
		if (!tcon->retry)
			return -EHOSTDOWN;
		goto again;
	}
	rc = cifs_setup_session(0, ses, server, ses->local_nls);
	if ((rc == -EACCES) || (rc == -EHOSTDOWN) || (rc == -EKEYREVOKED)) {
		/*
@@ -162,7 +171,6 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
		if (ses->password2)
			swap(ses->password2, ses->password);
	}
	}

	/* do we need to reconnect tcon? */
	if (rc || !tcon->need_reconnect) {
+42 −54
Original line number Diff line number Diff line
@@ -300,32 +300,23 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,

	mutex_lock(&ses->session_mutex);
	/*
	 * if this is called by delayed work, and the channel has been disabled
	 * in parallel, the delayed work can continue to execute in parallel
	 * there's a chance that this channel may not exist anymore
	 * Handle the case where a concurrent thread failed to negotiate or
	 * killed a channel.
	 */
	spin_lock(&server->srv_lock);
	if (server->tcpStatus == CifsExiting) {
	switch (server->tcpStatus) {
	case CifsExiting:
		spin_unlock(&server->srv_lock);
		mutex_unlock(&ses->session_mutex);
		rc = -EHOSTDOWN;
		goto out;
	}

	/*
	 * Recheck after acquire mutex. If another thread is negotiating
	 * and the server never sends an answer the socket will be closed
	 * and tcpStatus set to reconnect.
	 */
	if (server->tcpStatus == CifsNeedReconnect) {
		return -EHOSTDOWN;
	case CifsNeedReconnect:
		spin_unlock(&server->srv_lock);
		mutex_unlock(&ses->session_mutex);

		if (tcon->retry)
		if (!tcon->retry)
			return -EHOSTDOWN;
		goto again;

		rc = -EHOSTDOWN;
		goto out;
	default:
		break;
	}
	spin_unlock(&server->srv_lock);

@@ -350,7 +341,12 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
	spin_unlock(&ses->ses_lock);

	rc = cifs_negotiate_protocol(0, ses, server);
	if (!rc) {
	if (rc) {
		mutex_unlock(&ses->session_mutex);
		if (!tcon->retry)
			return -EHOSTDOWN;
		goto again;
	}
	/*
	 * if server stopped supporting multichannel
	 * and the first channel reconnected, disable all the others.
@@ -376,17 +372,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
		if (ses->password2)
			swap(ses->password2, ses->password);
	}

		if ((rc == -EACCES) && !tcon->retry) {
			mutex_unlock(&ses->session_mutex);
			rc = -EHOSTDOWN;
			goto failed;
		} else if (rc) {
			mutex_unlock(&ses->session_mutex);
			goto out;
		}
	} else {
	if (rc) {
		mutex_unlock(&ses->session_mutex);
		if (rc == -EACCES && !tcon->retry)
			return -EHOSTDOWN;
		goto out;
	}

@@ -490,7 +479,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
	case SMB2_IOCTL:
		rc = -EAGAIN;
	}
failed:
	return rc;
}