diff mbox

cifs: hard mount option behaviour implementation

Message ID 1275755825-6504-1-git-send-email-shirishpargaonkar@gmail.com
State New
Headers show

Commit Message

Shirish Pargaonkar June 5, 2010, 4:37 p.m. UTC
Add support for hard mount option by using -o hard.

Current cifs behaviour amounts to that of a soft mount.
If a response for a command does not arrive within a certain timeout,
server is considered non-responsive and a reconnect is attempted.
Commands/requests are returned with error for an app to decide.

This code change adds hard mount option behaviour.
A command waits in interruptible wait timing out every 60 seconds
to log a debug message about server not responding and going
back on interruptible wait queue for another 60 seconds.
Once response arrives, a debug messages is logged that server is
responding.
An user has an option to interrupt a program if a response has not
arrived for long enough for user to deem a dead server and retry
the program.
This takes care of unnecessary reconnects and subsequent retries
of numerous commands for invalidated file handles etc. when either
the server or client is stressed or slow. 

These commands such as negotiate, session setup, tree connect, 
logoff, non-blocking posix lock, and dfs referral are always soft.


From b1b0a7b1612dc3d865b4756dfddceeab4245a888 Mon Sep 17 00:00:00 2001
From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Date: Sat, 5 Jun 2010 10:01:06 -0500
Subject: [PATCH] add support for implementing hard mount option behaviour

Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
---
 fs/cifs/cifsproto.h |    7 ++-
 fs/cifs/cifssmb.c   |  126 +++++++++++++++++++++++++++-----------------------
 fs/cifs/connect.c   |    5 ++-
 fs/cifs/sess.c      |    2 +-
 fs/cifs/transport.c |   62 ++++++++++++++++++++++---
 5 files changed, 132 insertions(+), 70 deletions(-)

Comments

Jeff Layton June 6, 2010, 10:51 a.m. UTC | #1
On Sat,  5 Jun 2010 11:37:05 -0500
shirishpargaonkar@gmail.com wrote:

> Add support for hard mount option by using -o hard.
> 
> Current cifs behaviour amounts to that of a soft mount.
> If a response for a command does not arrive within a certain timeout,
> server is considered non-responsive and a reconnect is attempted.
> Commands/requests are returned with error for an app to decide.
> 
> This code change adds hard mount option behaviour.
> A command waits in interruptible wait timing out every 60 seconds
> to log a debug message about server not responding and going
> back on interruptible wait queue for another 60 seconds.
> Once response arrives, a debug messages is logged that server is
> responding.
> An user has an option to interrupt a program if a response has not
> arrived for long enough for user to deem a dead server and retry
> the program.
> This takes care of unnecessary reconnects and subsequent retries
> of numerous commands for invalidated file handles etc. when either
> the server or client is stressed or slow. 
> 
> These commands such as negotiate, session setup, tree connect, 
> logoff, non-blocking posix lock, and dfs referral are always soft.
> 
> 

Looks like a step in the right direction. I think this will help bring
better data integrity to CIFS. We really need to strive to minimize
reconnects since they are so costly and you lose things like file
locks, etc...

Comments inline below:

> From b1b0a7b1612dc3d865b4756dfddceeab4245a888 Mon Sep 17 00:00:00 2001
> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> Date: Sat, 5 Jun 2010 10:01:06 -0500
> Subject: [PATCH] add support for implementing hard mount option behaviour
> 
> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> ---
>  fs/cifs/cifsproto.h |    7 ++-
>  fs/cifs/cifssmb.c   |  126 +++++++++++++++++++++++++++-----------------------
>  fs/cifs/connect.c   |    5 ++-
>  fs/cifs/sess.c      |    2 +-
>  fs/cifs/transport.c |   62 ++++++++++++++++++++++---
>  5 files changed, 132 insertions(+), 70 deletions(-)
> 
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index fb1657e..7a475c5 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -63,12 +63,13 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
>  extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
>  			struct smb_hdr * /* input */ ,
>  			struct smb_hdr * /* out */ ,
> -			int * /* bytes returned */ , const int long_op);
> +			int * /* bytes returned */ , const int long_op, bool);
>  extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
> -			struct smb_hdr *in_buf, int flags);
> +			struct smb_hdr *in_buf, int flags, bool hard_mount);
>  extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
>  			struct kvec *, int /* nvec to send */,
> -			int * /* type of buf returned */ , const int flags);
> +			int * /* type of buf returned */ , const int flags,
> +			bool);
>  extern int SendReceiveBlockingLock(const unsigned int xid,
>  			struct cifsTconInfo *ptcon,
>  			struct smb_hdr *in_buf ,
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index c65c341..2634354 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -404,7 +404,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
>  	pSMB->ByteCount = cpu_to_le16(count);
>  
>  	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, false);
>  	if (rc != 0)
>  		goto neg_err_exit;
>  
> @@ -678,7 +678,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
>  	if (rc)
>  		return rc;
>  
> -	rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
> +	rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0, tcon->retry);


I know that this parameter predates your patch, but I'm not sure that
the "retry" option ought to hang off of the tcon. I think it should
hang off of the superblock instead. It ought to be possible for someone
to mount the same share with both hard and soft options simultaneously.

In fact, the default timeout for soft mounts ought to be tunable as well.
What may be best is to add a "call timeout" field to the superblock and
set that to '0' for hard mounts and then drop the "retry" parm on the
tcon.

>  	if (rc)
>  		cFYI(1, "Tree disconnect failed %d", rc);
>  
> @@ -725,7 +725,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
>  	pSMB->hdr.Uid = ses->Suid;
>  
>  	pSMB->AndXCommand = 0xFF;
> -	rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
> +	rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0, false);
>  session_already_dead:
>  	mutex_unlock(&ses->session_mutex);
>  
> @@ -799,7 +799,7 @@ PsxDelete:
>  	pSMB->hdr.smb_buf_length += byte_count;
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc)
>  		cFYI(1, "Posix delete returned %d", rc);
>  	cifs_buf_release(pSMB);
> @@ -845,7 +845,7 @@ DelFileRetry:
>  	pSMB->hdr.smb_buf_length += name_len + 1;
>  	pSMB->ByteCount = cpu_to_le16(name_len + 1);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	cifs_stats_inc(&tcon->num_deletes);
>  	if (rc)
>  		cFYI(1, "Error in RMFile = %d", rc);
> @@ -889,7 +889,7 @@ RmDirRetry:
>  	pSMB->hdr.smb_buf_length += name_len + 1;
>  	pSMB->ByteCount = cpu_to_le16(name_len + 1);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	cifs_stats_inc(&tcon->num_rmdirs);
>  	if (rc)
>  		cFYI(1, "Error in RMDir = %d", rc);
> @@ -932,7 +932,7 @@ MkDirRetry:
>  	pSMB->hdr.smb_buf_length += name_len + 1;
>  	pSMB->ByteCount = cpu_to_le16(name_len + 1);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	cifs_stats_inc(&tcon->num_mkdirs);
>  	if (rc)
>  		cFYI(1, "Error in Mkdir = %d", rc);
> @@ -1010,7 +1010,7 @@ PsxCreat:
>  	pSMB->hdr.smb_buf_length += byte_count;
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Posix create returned %d", rc);
>  		goto psx_create_err;
> @@ -1177,7 +1177,8 @@ OldOpenRetry:
>  	pSMB->ByteCount = cpu_to_le16(count);
>  	/* long_op set to 1 to allow for oplock break timeouts */
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
> +		(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP,
> +		tcon->retry);
>  	cifs_stats_inc(&tcon->num_opens);
>  	if (rc) {
>  		cFYI(1, "Error in Open = %d", rc);
> @@ -1290,7 +1291,8 @@ openRetry:
>  	pSMB->ByteCount = cpu_to_le16(count);
>  	/* long_op set to 1 to allow for oplock break timeouts */
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
> +		(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP,
> +		tcon->retry);
>  	cifs_stats_inc(&tcon->num_opens);
>  	if (rc) {
>  		cFYI(1, "Error in Open = %d", rc);
> @@ -1372,7 +1374,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
>  	iov[0].iov_base = (char *)pSMB;
>  	iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
>  	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
> -			 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
> +		 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR, tcon->retry);
>  	cifs_stats_inc(&tcon->num_reads);
>  	pSMBr = (READ_RSP *)iov[0].iov_base;
>  	if (rc) {
> @@ -1516,7 +1518,8 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
>  	}
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
> +		(struct smb_hdr *) pSMBr, &bytes_returned, long_op,
> +		tcon->retry);
>  	cifs_stats_inc(&tcon->num_writes);
>  	if (rc) {
>  		cFYI(1, "Send error in write = %d", rc);
> @@ -1608,7 +1611,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
>  
>  
>  	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
> -			  long_op);
> +			  long_op, tcon->retry);
>  	cifs_stats_inc(&tcon->num_writes);
>  	if (rc) {
>  		cFYI(1, "Send error Write2 = %d", rc);
> @@ -1699,7 +1702,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
>  		cifs_small_buf_release(pSMB);
>  	} else {
>  		rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
> -				      timeout);
> +				      timeout, tcon->retry);
>  		/* SMB buffer freed by function above */
>  	}
>  	cifs_stats_inc(&tcon->num_locks);
> @@ -1790,7 +1793,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
>  		iov[0].iov_base = (char *)pSMB;
>  		iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
>  		rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
> -				&resp_buf_type, timeout);
> +				&resp_buf_type, timeout, false);
>  		pSMB = NULL; /* request buf already freed by SendReceive2. Do
>  				not try to free it twice below on exit */
>  		pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
> @@ -1866,7 +1869,8 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
>  	pSMB->FileID = (__u16) smb_file_id;
>  	pSMB->LastWriteTime = 0xFFFFFFFF;
>  	pSMB->ByteCount = 0;
> -	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> +				tcon->retry);
>  	cifs_stats_inc(&tcon->num_closes);
>  	if (rc) {
>  		if (rc != -EINTR) {
> @@ -1895,7 +1899,8 @@ CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
>  
>  	pSMB->FileID = (__u16) smb_file_id;
>  	pSMB->ByteCount = 0;
> -	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> +				tcon->retry);
>  	cifs_stats_inc(&tcon->num_flushes);
>  	if (rc)
>  		cERROR(1, "Send error in Flush = %d", rc);
> @@ -1958,7 +1963,7 @@ renameRetry:
>  	pSMB->ByteCount = cpu_to_le16(count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	cifs_stats_inc(&tcon->num_renames);
>  	if (rc)
>  		cFYI(1, "Send error in rename = %d", rc);
> @@ -2037,7 +2042,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
>  	pSMB->hdr.smb_buf_length += byte_count;
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, pTcon->retry);
>  	cifs_stats_inc(&pTcon->num_t2renames);
>  	if (rc)
>  		cFYI(1, "Send error in Rename (by file handle) = %d", rc);
> @@ -2105,7 +2110,7 @@ copyRetry:
>  	pSMB->ByteCount = cpu_to_le16(count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in copy = %d with %d files copied",
>  			rc, le16_to_cpu(pSMBr->CopyCount));
> @@ -2194,7 +2199,7 @@ createSymLinkRetry:
>  	pSMB->hdr.smb_buf_length += byte_count;
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	cifs_stats_inc(&tcon->num_symlinks);
>  	if (rc)
>  		cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
> @@ -2280,7 +2285,7 @@ createHardLinkRetry:
>  	pSMB->hdr.smb_buf_length += byte_count;
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	cifs_stats_inc(&tcon->num_hardlinks);
>  	if (rc)
>  		cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
> @@ -2352,7 +2357,7 @@ winCreateHardLinkRetry:
>  	pSMB->ByteCount = cpu_to_le16(count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	cifs_stats_inc(&tcon->num_hardlinks);
>  	if (rc)
>  		cFYI(1, "Send error in hard link (NT rename) = %d", rc);
> @@ -2423,7 +2428,7 @@ querySymLinkRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
>  	} else {
> @@ -2586,7 +2591,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
>  	pSMB->ByteCount = 0;
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -2849,7 +2854,7 @@ queryAclRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	cifs_stats_inc(&tcon->num_acl_get);
>  	if (rc) {
>  		cFYI(1, "Send error in Query POSIX ACL = %d", rc);
> @@ -2942,7 +2947,7 @@ setAclRetry:
>  	pSMB->hdr.smb_buf_length += byte_count;
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc)
>  		cFYI(1, "Set POSIX ACL returned %d", rc);
>  
> @@ -3001,7 +3006,7 @@ GetExtAttrRetry:
>  	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "error %d in GetExtAttr", rc);
>  	} else {
> @@ -3070,7 +3075,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
>  	iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
>  
>  	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
> -			 CIFS_STD_OP);
> +			 CIFS_STD_OP, tcon->retry);
>  	cifs_stats_inc(&tcon->num_acl_get);
>  	if (rc) {
>  		cFYI(1, "Send error in QuerySecDesc = %d", rc);
> @@ -3182,7 +3187,7 @@ setCifsAclRetry:
>  		pSMB->hdr.smb_buf_length += byte_count;
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  
>  	cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
>  	if (rc)
> @@ -3234,7 +3239,7 @@ QInfRetry:
>  	pSMB->ByteCount = cpu_to_le16(name_len);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QueryInfo = %d", rc);
>  	} else if (pFinfo) {
> @@ -3308,7 +3313,7 @@ QFileInfoRetry:
>  	pSMB->hdr.smb_buf_length += byte_count;
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QPathInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -3396,7 +3401,7 @@ QPathInfoRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QPathInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -3476,7 +3481,7 @@ UnixQFileInfoRetry:
>  	pSMB->hdr.smb_buf_length += byte_count;
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QPathInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -3562,7 +3567,7 @@ UnixQPathInfoRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QPathInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -3676,7 +3681,7 @@ findFirstRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	cifs_stats_inc(&tcon->num_ffirst);
>  
>  	if (rc) {/* BB add logic to retry regular search if Unix search
> @@ -3805,7 +3810,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	cifs_stats_inc(&tcon->num_fnext);
>  	if (rc) {
>  		if (rc == -EBADF) {
> @@ -3894,7 +3899,8 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
>  
>  	pSMB->FileID = searchHandle;
>  	pSMB->ByteCount = 0;
> -	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> +				tcon->retry);
>  	if (rc)
>  		cERROR(1, "Send error in FindClose = %d", rc);
>  
> @@ -3967,7 +3973,7 @@ GetInodeNumberRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "error %d in QueryInternalInfo", rc);
>  	} else {
> @@ -4191,7 +4197,7 @@ getDFSRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, false);
>  	if (rc) {
>  		cFYI(1, "Send error in GetDFSRefer = %d", rc);
>  		goto GetDFSRefExit;
> @@ -4265,7 +4271,7 @@ oldQFSInfoRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QFSInfo = %d", rc);
>  	} else {                /* decode response */
> @@ -4344,7 +4350,7 @@ QFSInfoRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QFSInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -4424,7 +4430,7 @@ QFSAttributeRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -4495,7 +4501,7 @@ QFSDeviceRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -4564,7 +4570,7 @@ QFSUnixRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cERROR(1, "Send error in QFSUnixInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -4647,7 +4653,7 @@ SETFSUnixRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -4709,7 +4715,7 @@ QFSPosixRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QFSUnixInfo = %d", rc);
>  	} else {		/* decode response */
> @@ -4835,7 +4841,7 @@ SetEOFRetry:
>  	parm_data->FileSize = cpu_to_le64(size);
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc)
>  		cFYI(1, "SetPathInfo (file size) returned %d", rc);
>  
> @@ -4915,7 +4921,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
>  	pSMB->Reserved4 = 0;
>  	pSMB->hdr.smb_buf_length += byte_count;
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
> -	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> +				tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
>  	}
> @@ -4984,7 +4991,8 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
>  	pSMB->hdr.smb_buf_length += byte_count;
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
> -	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> +				tcon->retry);
>  	if (rc)
>  		cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
>  
> @@ -5043,7 +5051,8 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
>  	pSMB->hdr.smb_buf_length += byte_count;
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	*data_offset = delete_file ? 1 : 0;
> -	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> +				tcon->retry);
>  	if (rc)
>  		cFYI(1, "Send error in SetFileDisposition = %d", rc);
>  
> @@ -5117,7 +5126,7 @@ SetTimesRetry:
>  	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc)
>  		cFYI(1, "SetPathInfo (times) returned %d", rc);
>  
> @@ -5275,7 +5284,8 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
>  
>  	cifs_fill_unix_set_info(data_offset, args);
>  
> -	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> +				tcon->retry);
>  	if (rc)
>  		cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
>  
> @@ -5352,7 +5362,7 @@ setPermsRetry:
>  
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc)
>  		cFYI(1, "SetPathInfo (perms) returned %d", rc);
>  
> @@ -5404,8 +5414,8 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
>  	pSMB->ByteCount = 0;
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *)pSMBr, &bytes_returned,
> -			 CIFS_ASYNC_OP);
> +		(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_ASYNC_OP,
> +		tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Error in Notify = %d", rc);
>  	} else {
> @@ -5508,7 +5518,7 @@ QAllEAsRetry:
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc) {
>  		cFYI(1, "Send error in QueryAllEAs = %d", rc);
>  		goto QAllEAsOut;
> @@ -5720,7 +5730,7 @@ SetEARetry:
>  	pSMB->hdr.smb_buf_length += byte_count;
>  	pSMB->ByteCount = cpu_to_le16(byte_count);
>  	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> -			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> +		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>  	if (rc)
>  		cFYI(1, "SetPathInfo (EA) returned %d", rc);
>  
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 2208f06..7ddc602 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -1809,6 +1809,9 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
>  		}
>  	}
>  
> +	if (volume_info->retry)
> +		tcon->retry = volume_info->retry;
> +
>  	if (strchr(volume_info->UNC + 3, '\\') == NULL
>  	    && strchr(volume_info->UNC + 3, '/') == NULL) {
>  		cERROR(1, "Missing share name");
> @@ -2807,7 +2810,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
>  	pSMB->ByteCount = cpu_to_le16(count);
>  
>  	rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
> -			 CIFS_STD_OP);
> +			 CIFS_STD_OP, false);
>  
>  	/* above now done in SendReceive */
>  	if ((rc == 0) && (tcon != NULL)) {
> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
> index 7707389..ff0dfb7 100644
> --- a/fs/cifs/sess.c
> +++ b/fs/cifs/sess.c
> @@ -866,7 +866,7 @@ ssetup_ntlmssp_authenticate:
>  	BCC_LE(smb_buf) = cpu_to_le16(count);
>  
>  	rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
> -			  CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR);
> +		  CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR, false);
>  	/* SMB request buf freed in SendReceive2 */
>  
>  	cFYI(1, "ssetup rc from sendrecv2 is %d", rc);
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 82f78c4..0c7a07e 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -311,6 +311,44 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
>  	return 0;
>  }
>  
> +static int
> +wait_for_response_hard(struct cifsSesInfo *ses, struct mid_q_entry *midQ)
> +{
> +	int rc;
> +	bool cmdresp = true;
> +	unsigned long timeout = 60 * HZ;
> +	unsigned long curr_timeout;
> +
> +wait_again:
> +	curr_timeout = timeout + jiffies;
> +	rc = wait_event_interruptible_timeout(ses->server->response_q,
> +			(midQ->midState != MID_REQUEST_SUBMITTED), timeout);
> +
> +	if (rc < 0) {
> +		cFYI(1, "command 0x%x interrupted", midQ->command);
> +		return -1;
> +	}
> +	if (!time_before(jiffies, curr_timeout)) {
> +		cmdresp = false;
> +		cFYI(1, "server not responding...");
> +		goto wait_again;
> +	}
> +	spin_lock(&GlobalMid_Lock);
> +	if (midQ->midState != MID_REQUEST_SUBMITTED) {
> +		if (midQ->midState == MID_RESPONSE_RECEIVED) {
> +			if (!cmdresp)
> +				cFYI(1, "server is ok...");
> +			rc = 0;
> +		} else {
> +			cFYI(1, "command 0x%x aborted", midQ->command);
> +			rc = -1;
> +		}
> +	}
> +	spin_unlock(&GlobalMid_Lock);
> +	return rc;
> +}
> +

The cFYI's above could be a bit more descriptive. Which server isn't
responding here? That could be important information. Also maybe this
should be a cERROR printk so that administrators have some sort of clue
as to why the mount seems to be hung. Making those look similar to the
RPC timeout messages with NFS would also add some "consistency" to the
kernel's appearance too.

> +
>  static int wait_for_response(struct cifsSesInfo *ses,
>  			struct mid_q_entry *midQ,
>  			unsigned long timeout,
> @@ -367,7 +405,7 @@ static int wait_for_response(struct cifsSesInfo *ses,
>   */
>  int
>  SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
> -		struct smb_hdr *in_buf, int flags)
> +		struct smb_hdr *in_buf, int flags, bool hard_mount)
>  {
>  	int rc;
>  	struct kvec iov[1];
> @@ -376,7 +414,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
>  	iov[0].iov_base = (char *)in_buf;
>  	iov[0].iov_len = in_buf->smb_buf_length + 4;
>  	flags |= CIFS_NO_RESP;
> -	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
> +	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, hard_mount);
>  	cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
>  
>  	return rc;
> @@ -385,7 +423,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
>  int
>  SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
>  	     struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
> -	     const int flags)
> +	     const int flags, bool hard_mount)
>  {
>  	int rc = 0;
>  	int long_op;
> @@ -483,7 +521,12 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
>  	}
>  
>  	/* No user interrupts in wait - wreaks havoc with performance */
> -	wait_for_response(ses, midQ, timeout, 10 * HZ);
> +	if (hard_mount) {
> +		rc = wait_for_response_hard(ses, midQ);
> +		if (rc)
> +			goto out;
> +	} else
> +		wait_for_response(ses, midQ, timeout, 10 * HZ);

Maybe instead of the above, it may be better to embed whether this is a
hard or soft timeout in the mid queue entry itself. That is, add
another parameter? What may be best is to just put in a timeout
parameter in the mid queue entry and then set that to 0 for hard mounts.

>  
>  	spin_lock(&GlobalMid_Lock);
>  
> @@ -581,7 +624,7 @@ out:
>  int
>  SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
>  	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
> -	    int *pbytes_returned, const int long_op)
> +	    int *pbytes_returned, const int long_op, bool hard_mount)
>  {
>  	int rc = 0;
>  	unsigned int receive_len;
> @@ -675,7 +718,12 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
>  	}
>  
>  	/* No user interrupts in wait - wreaks havoc with performance */
> -	wait_for_response(ses, midQ, timeout, 10 * HZ);
> +	if (hard_mount) {
> +		rc = wait_for_response_hard(ses, midQ);
> +		if (rc)
> +			goto out;
> +	} else
> +		wait_for_response(ses, midQ, timeout, 10 * HZ);
>  
>  	spin_lock(&GlobalMid_Lock);
>  	if (midQ->resp_buf == NULL) {
> @@ -807,7 +855,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
>  	pSMB->hdr.Mid = GetNextMid(ses->server);
>  
>  	return SendReceive(xid, ses, in_buf, out_buf,
> -			&bytes_returned, CIFS_STD_OP);
> +			&bytes_returned, CIFS_STD_OP, tcon->retry);
>  }
>  
>  int
Shirish Pargaonkar June 7, 2010, 7:26 p.m. UTC | #2
On Sun, Jun 6, 2010 at 5:51 AM, Jeff Layton <jlayton@samba.org> wrote:
> On Sat,  5 Jun 2010 11:37:05 -0500
> shirishpargaonkar@gmail.com wrote:
>
>> Add support for hard mount option by using -o hard.
>>
>> Current cifs behaviour amounts to that of a soft mount.
>> If a response for a command does not arrive within a certain timeout,
>> server is considered non-responsive and a reconnect is attempted.
>> Commands/requests are returned with error for an app to decide.
>>
>> This code change adds hard mount option behaviour.
>> A command waits in interruptible wait timing out every 60 seconds
>> to log a debug message about server not responding and going
>> back on interruptible wait queue for another 60 seconds.
>> Once response arrives, a debug messages is logged that server is
>> responding.
>> An user has an option to interrupt a program if a response has not
>> arrived for long enough for user to deem a dead server and retry
>> the program.
>> This takes care of unnecessary reconnects and subsequent retries
>> of numerous commands for invalidated file handles etc. when either
>> the server or client is stressed or slow.
>>
>> These commands such as negotiate, session setup, tree connect,
>> logoff, non-blocking posix lock, and dfs referral are always soft.
>>
>>
>
> Looks like a step in the right direction. I think this will help bring
> better data integrity to CIFS. We really need to strive to minimize
> reconnects since they are so costly and you lose things like file
> locks, etc...
>
> Comments inline below:
>
>> From b1b0a7b1612dc3d865b4756dfddceeab4245a888 Mon Sep 17 00:00:00 2001
>> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
>> Date: Sat, 5 Jun 2010 10:01:06 -0500
>> Subject: [PATCH] add support for implementing hard mount option behaviour
>>
>> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
>> ---
>>  fs/cifs/cifsproto.h |    7 ++-
>>  fs/cifs/cifssmb.c   |  126 +++++++++++++++++++++++++++-----------------------
>>  fs/cifs/connect.c   |    5 ++-
>>  fs/cifs/sess.c      |    2 +-
>>  fs/cifs/transport.c |   62 ++++++++++++++++++++++---
>>  5 files changed, 132 insertions(+), 70 deletions(-)
>>
>> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
>> index fb1657e..7a475c5 100644
>> --- a/fs/cifs/cifsproto.h
>> +++ b/fs/cifs/cifsproto.h
>> @@ -63,12 +63,13 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
>>  extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
>>                       struct smb_hdr * /* input */ ,
>>                       struct smb_hdr * /* out */ ,
>> -                     int * /* bytes returned */ , const int long_op);
>> +                     int * /* bytes returned */ , const int long_op, bool);
>>  extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
>> -                     struct smb_hdr *in_buf, int flags);
>> +                     struct smb_hdr *in_buf, int flags, bool hard_mount);
>>  extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
>>                       struct kvec *, int /* nvec to send */,
>> -                     int * /* type of buf returned */ , const int flags);
>> +                     int * /* type of buf returned */ , const int flags,
>> +                     bool);
>>  extern int SendReceiveBlockingLock(const unsigned int xid,
>>                       struct cifsTconInfo *ptcon,
>>                       struct smb_hdr *in_buf ,
>> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
>> index c65c341..2634354 100644
>> --- a/fs/cifs/cifssmb.c
>> +++ b/fs/cifs/cifssmb.c
>> @@ -404,7 +404,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
>>       pSMB->ByteCount = cpu_to_le16(count);
>>
>>       rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, false);
>>       if (rc != 0)
>>               goto neg_err_exit;
>>
>> @@ -678,7 +678,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
>>       if (rc)
>>               return rc;
>>
>> -     rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
>> +     rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0, tcon->retry);
>
>
> I know that this parameter predates your patch, but I'm not sure that
> the "retry" option ought to hang off of the tcon. I think it should
> hang off of the superblock instead. It ought to be possible for someone
> to mount the same share with both hard and soft options simultaneously.
>
> In fact, the default timeout for soft mounts ought to be tunable as well.
> What may be best is to add a "call timeout" field to the superblock and
> set that to '0' for hard mounts and then drop the "retry" parm on the
> tcon.

I can do that.  Does that mean adding a new mount option like timeo
which does not apply to hard mounts but only to soft mounts and if one is not
specified for (default) soft mounts, come up with a default timeout value?
That means invalidating this existing logic (in fs/cifs/transport.c)?

        if (long_op == CIFS_STD_OP)
                timeout = 15 * HZ;
        /* wait for 15 seconds or until woken up due to response arriving or
           due to last connection to this server being unmounted */
        else if (long_op == CIFS_ASYNC_OP)
                goto out;
        else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
                timeout = 180 * HZ;
        else if (long_op == CIFS_LONG_OP)
                timeout = 45 * HZ; /* should be greater than
                        servers oplock break timeout (about 43 seconds) */
        else if (long_op == CIFS_BLOCKING_OP)
                timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
        else {
                cERROR(1, "unknown timeout flag %d", long_op);
                rc = -EIO;
                goto out;
        }

We do not really need a timeout value for hard mounts, the timeout
value used in hard mount
is only to wake up and log a message if response has not arrived.

>
>>       if (rc)
>>               cFYI(1, "Tree disconnect failed %d", rc);
>>
>> @@ -725,7 +725,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
>>       pSMB->hdr.Uid = ses->Suid;
>>
>>       pSMB->AndXCommand = 0xFF;
>> -     rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
>> +     rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0, false);
>>  session_already_dead:
>>       mutex_unlock(&ses->session_mutex);
>>
>> @@ -799,7 +799,7 @@ PsxDelete:
>>       pSMB->hdr.smb_buf_length += byte_count;
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc)
>>               cFYI(1, "Posix delete returned %d", rc);
>>       cifs_buf_release(pSMB);
>> @@ -845,7 +845,7 @@ DelFileRetry:
>>       pSMB->hdr.smb_buf_length += name_len + 1;
>>       pSMB->ByteCount = cpu_to_le16(name_len + 1);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       cifs_stats_inc(&tcon->num_deletes);
>>       if (rc)
>>               cFYI(1, "Error in RMFile = %d", rc);
>> @@ -889,7 +889,7 @@ RmDirRetry:
>>       pSMB->hdr.smb_buf_length += name_len + 1;
>>       pSMB->ByteCount = cpu_to_le16(name_len + 1);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       cifs_stats_inc(&tcon->num_rmdirs);
>>       if (rc)
>>               cFYI(1, "Error in RMDir = %d", rc);
>> @@ -932,7 +932,7 @@ MkDirRetry:
>>       pSMB->hdr.smb_buf_length += name_len + 1;
>>       pSMB->ByteCount = cpu_to_le16(name_len + 1);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       cifs_stats_inc(&tcon->num_mkdirs);
>>       if (rc)
>>               cFYI(1, "Error in Mkdir = %d", rc);
>> @@ -1010,7 +1010,7 @@ PsxCreat:
>>       pSMB->hdr.smb_buf_length += byte_count;
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Posix create returned %d", rc);
>>               goto psx_create_err;
>> @@ -1177,7 +1177,8 @@ OldOpenRetry:
>>       pSMB->ByteCount = cpu_to_le16(count);
>>       /* long_op set to 1 to allow for oplock break timeouts */
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                     (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
>> +             (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP,
>> +             tcon->retry);
>>       cifs_stats_inc(&tcon->num_opens);
>>       if (rc) {
>>               cFYI(1, "Error in Open = %d", rc);
>> @@ -1290,7 +1291,8 @@ openRetry:
>>       pSMB->ByteCount = cpu_to_le16(count);
>>       /* long_op set to 1 to allow for oplock break timeouts */
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                     (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
>> +             (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP,
>> +             tcon->retry);
>>       cifs_stats_inc(&tcon->num_opens);
>>       if (rc) {
>>               cFYI(1, "Error in Open = %d", rc);
>> @@ -1372,7 +1374,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
>>       iov[0].iov_base = (char *)pSMB;
>>       iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
>>       rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
>> -                      &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
>> +              &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR, tcon->retry);
>>       cifs_stats_inc(&tcon->num_reads);
>>       pSMBr = (READ_RSP *)iov[0].iov_base;
>>       if (rc) {
>> @@ -1516,7 +1518,8 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
>>       }
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
>> +             (struct smb_hdr *) pSMBr, &bytes_returned, long_op,
>> +             tcon->retry);
>>       cifs_stats_inc(&tcon->num_writes);
>>       if (rc) {
>>               cFYI(1, "Send error in write = %d", rc);
>> @@ -1608,7 +1611,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
>>
>>
>>       rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
>> -                       long_op);
>> +                       long_op, tcon->retry);
>>       cifs_stats_inc(&tcon->num_writes);
>>       if (rc) {
>>               cFYI(1, "Send error Write2 = %d", rc);
>> @@ -1699,7 +1702,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
>>               cifs_small_buf_release(pSMB);
>>       } else {
>>               rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
>> -                                   timeout);
>> +                                   timeout, tcon->retry);
>>               /* SMB buffer freed by function above */
>>       }
>>       cifs_stats_inc(&tcon->num_locks);
>> @@ -1790,7 +1793,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
>>               iov[0].iov_base = (char *)pSMB;
>>               iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
>>               rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
>> -                             &resp_buf_type, timeout);
>> +                             &resp_buf_type, timeout, false);
>>               pSMB = NULL; /* request buf already freed by SendReceive2. Do
>>                               not try to free it twice below on exit */
>>               pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
>> @@ -1866,7 +1869,8 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
>>       pSMB->FileID = (__u16) smb_file_id;
>>       pSMB->LastWriteTime = 0xFFFFFFFF;
>>       pSMB->ByteCount = 0;
>> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
>> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
>> +                             tcon->retry);
>>       cifs_stats_inc(&tcon->num_closes);
>>       if (rc) {
>>               if (rc != -EINTR) {
>> @@ -1895,7 +1899,8 @@ CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
>>
>>       pSMB->FileID = (__u16) smb_file_id;
>>       pSMB->ByteCount = 0;
>> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
>> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
>> +                             tcon->retry);
>>       cifs_stats_inc(&tcon->num_flushes);
>>       if (rc)
>>               cERROR(1, "Send error in Flush = %d", rc);
>> @@ -1958,7 +1963,7 @@ renameRetry:
>>       pSMB->ByteCount = cpu_to_le16(count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       cifs_stats_inc(&tcon->num_renames);
>>       if (rc)
>>               cFYI(1, "Send error in rename = %d", rc);
>> @@ -2037,7 +2042,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
>>       pSMB->hdr.smb_buf_length += byte_count;
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, pTcon->retry);
>>       cifs_stats_inc(&pTcon->num_t2renames);
>>       if (rc)
>>               cFYI(1, "Send error in Rename (by file handle) = %d", rc);
>> @@ -2105,7 +2110,7 @@ copyRetry:
>>       pSMB->ByteCount = cpu_to_le16(count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -             (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in copy = %d with %d files copied",
>>                       rc, le16_to_cpu(pSMBr->CopyCount));
>> @@ -2194,7 +2199,7 @@ createSymLinkRetry:
>>       pSMB->hdr.smb_buf_length += byte_count;
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       cifs_stats_inc(&tcon->num_symlinks);
>>       if (rc)
>>               cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
>> @@ -2280,7 +2285,7 @@ createHardLinkRetry:
>>       pSMB->hdr.smb_buf_length += byte_count;
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       cifs_stats_inc(&tcon->num_hardlinks);
>>       if (rc)
>>               cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
>> @@ -2352,7 +2357,7 @@ winCreateHardLinkRetry:
>>       pSMB->ByteCount = cpu_to_le16(count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       cifs_stats_inc(&tcon->num_hardlinks);
>>       if (rc)
>>               cFYI(1, "Send error in hard link (NT rename) = %d", rc);
>> @@ -2423,7 +2428,7 @@ querySymLinkRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
>>       } else {
>> @@ -2586,7 +2591,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
>>       pSMB->ByteCount = 0;
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -2849,7 +2854,7 @@ queryAclRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -             (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       cifs_stats_inc(&tcon->num_acl_get);
>>       if (rc) {
>>               cFYI(1, "Send error in Query POSIX ACL = %d", rc);
>> @@ -2942,7 +2947,7 @@ setAclRetry:
>>       pSMB->hdr.smb_buf_length += byte_count;
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc)
>>               cFYI(1, "Set POSIX ACL returned %d", rc);
>>
>> @@ -3001,7 +3006,7 @@ GetExtAttrRetry:
>>       pSMB->t2.ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "error %d in GetExtAttr", rc);
>>       } else {
>> @@ -3070,7 +3075,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
>>       iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
>>
>>       rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
>> -                      CIFS_STD_OP);
>> +                      CIFS_STD_OP, tcon->retry);
>>       cifs_stats_inc(&tcon->num_acl_get);
>>       if (rc) {
>>               cFYI(1, "Send error in QuerySecDesc = %d", rc);
>> @@ -3182,7 +3187,7 @@ setCifsAclRetry:
>>               pSMB->hdr.smb_buf_length += byte_count;
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -             (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>
>>       cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
>>       if (rc)
>> @@ -3234,7 +3239,7 @@ QInfRetry:
>>       pSMB->ByteCount = cpu_to_le16(name_len);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QueryInfo = %d", rc);
>>       } else if (pFinfo) {
>> @@ -3308,7 +3313,7 @@ QFileInfoRetry:
>>       pSMB->hdr.smb_buf_length += byte_count;
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QPathInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -3396,7 +3401,7 @@ QPathInfoRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QPathInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -3476,7 +3481,7 @@ UnixQFileInfoRetry:
>>       pSMB->hdr.smb_buf_length += byte_count;
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QPathInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -3562,7 +3567,7 @@ UnixQPathInfoRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QPathInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -3676,7 +3681,7 @@ findFirstRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       cifs_stats_inc(&tcon->num_ffirst);
>>
>>       if (rc) {/* BB add logic to retry regular search if Unix search
>> @@ -3805,7 +3810,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                     (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       cifs_stats_inc(&tcon->num_fnext);
>>       if (rc) {
>>               if (rc == -EBADF) {
>> @@ -3894,7 +3899,8 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
>>
>>       pSMB->FileID = searchHandle;
>>       pSMB->ByteCount = 0;
>> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
>> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
>> +                             tcon->retry);
>>       if (rc)
>>               cERROR(1, "Send error in FindClose = %d", rc);
>>
>> @@ -3967,7 +3973,7 @@ GetInodeNumberRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -             (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "error %d in QueryInternalInfo", rc);
>>       } else {
>> @@ -4191,7 +4197,7 @@ getDFSRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, false);
>>       if (rc) {
>>               cFYI(1, "Send error in GetDFSRefer = %d", rc);
>>               goto GetDFSRefExit;
>> @@ -4265,7 +4271,7 @@ oldQFSInfoRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -             (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QFSInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -4344,7 +4350,7 @@ QFSInfoRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QFSInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -4424,7 +4430,7 @@ QFSAttributeRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -4495,7 +4501,7 @@ QFSDeviceRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -4564,7 +4570,7 @@ QFSUnixRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cERROR(1, "Send error in QFSUnixInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -4647,7 +4653,7 @@ SETFSUnixRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -4709,7 +4715,7 @@ QFSPosixRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QFSUnixInfo = %d", rc);
>>       } else {                /* decode response */
>> @@ -4835,7 +4841,7 @@ SetEOFRetry:
>>       parm_data->FileSize = cpu_to_le64(size);
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc)
>>               cFYI(1, "SetPathInfo (file size) returned %d", rc);
>>
>> @@ -4915,7 +4921,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
>>       pSMB->Reserved4 = 0;
>>       pSMB->hdr.smb_buf_length += byte_count;
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
>> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
>> +                             tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
>>       }
>> @@ -4984,7 +4991,8 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
>>       pSMB->hdr.smb_buf_length += byte_count;
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
>> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
>> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
>> +                             tcon->retry);
>>       if (rc)
>>               cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
>>
>> @@ -5043,7 +5051,8 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
>>       pSMB->hdr.smb_buf_length += byte_count;
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       *data_offset = delete_file ? 1 : 0;
>> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
>> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
>> +                             tcon->retry);
>>       if (rc)
>>               cFYI(1, "Send error in SetFileDisposition = %d", rc);
>>
>> @@ -5117,7 +5126,7 @@ SetTimesRetry:
>>       memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc)
>>               cFYI(1, "SetPathInfo (times) returned %d", rc);
>>
>> @@ -5275,7 +5284,8 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
>>
>>       cifs_fill_unix_set_info(data_offset, args);
>>
>> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
>> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
>> +                             tcon->retry);
>>       if (rc)
>>               cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
>>
>> @@ -5352,7 +5362,7 @@ setPermsRetry:
>>
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc)
>>               cFYI(1, "SetPathInfo (perms) returned %d", rc);
>>
>> @@ -5404,8 +5414,8 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
>>       pSMB->ByteCount = 0;
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *)pSMBr, &bytes_returned,
>> -                      CIFS_ASYNC_OP);
>> +             (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_ASYNC_OP,
>> +             tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Error in Notify = %d", rc);
>>       } else {
>> @@ -5508,7 +5518,7 @@ QAllEAsRetry:
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc) {
>>               cFYI(1, "Send error in QueryAllEAs = %d", rc);
>>               goto QAllEAsOut;
>> @@ -5720,7 +5730,7 @@ SetEARetry:
>>       pSMB->hdr.smb_buf_length += byte_count;
>>       pSMB->ByteCount = cpu_to_le16(byte_count);
>>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
>> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
>> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
>>       if (rc)
>>               cFYI(1, "SetPathInfo (EA) returned %d", rc);
>>
>> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
>> index 2208f06..7ddc602 100644
>> --- a/fs/cifs/connect.c
>> +++ b/fs/cifs/connect.c
>> @@ -1809,6 +1809,9 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
>>               }
>>       }
>>
>> +     if (volume_info->retry)
>> +             tcon->retry = volume_info->retry;
>> +
>>       if (strchr(volume_info->UNC + 3, '\\') == NULL
>>           && strchr(volume_info->UNC + 3, '/') == NULL) {
>>               cERROR(1, "Missing share name");
>> @@ -2807,7 +2810,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
>>       pSMB->ByteCount = cpu_to_le16(count);
>>
>>       rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
>> -                      CIFS_STD_OP);
>> +                      CIFS_STD_OP, false);
>>
>>       /* above now done in SendReceive */
>>       if ((rc == 0) && (tcon != NULL)) {
>> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
>> index 7707389..ff0dfb7 100644
>> --- a/fs/cifs/sess.c
>> +++ b/fs/cifs/sess.c
>> @@ -866,7 +866,7 @@ ssetup_ntlmssp_authenticate:
>>       BCC_LE(smb_buf) = cpu_to_le16(count);
>>
>>       rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
>> -                       CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR);
>> +               CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR, false);
>>       /* SMB request buf freed in SendReceive2 */
>>
>>       cFYI(1, "ssetup rc from sendrecv2 is %d", rc);
>> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
>> index 82f78c4..0c7a07e 100644
>> --- a/fs/cifs/transport.c
>> +++ b/fs/cifs/transport.c
>> @@ -311,6 +311,44 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
>>       return 0;
>>  }
>>
>> +static int
>> +wait_for_response_hard(struct cifsSesInfo *ses, struct mid_q_entry *midQ)
>> +{
>> +     int rc;
>> +     bool cmdresp = true;
>> +     unsigned long timeout = 60 * HZ;
>> +     unsigned long curr_timeout;
>> +
>> +wait_again:
>> +     curr_timeout = timeout + jiffies;
>> +     rc = wait_event_interruptible_timeout(ses->server->response_q,
>> +                     (midQ->midState != MID_REQUEST_SUBMITTED), timeout);
>> +
>> +     if (rc < 0) {
>> +             cFYI(1, "command 0x%x interrupted", midQ->command);
>> +             return -1;
>> +     }
>> +     if (!time_before(jiffies, curr_timeout)) {
>> +             cmdresp = false;
>> +             cFYI(1, "server not responding...");
>> +             goto wait_again;
>> +     }
>> +     spin_lock(&GlobalMid_Lock);
>> +     if (midQ->midState != MID_REQUEST_SUBMITTED) {
>> +             if (midQ->midState == MID_RESPONSE_RECEIVED) {
>> +                     if (!cmdresp)
>> +                             cFYI(1, "server is ok...");
>> +                     rc = 0;
>> +             } else {
>> +                     cFYI(1, "command 0x%x aborted", midQ->command);
>> +                     rc = -1;
>> +             }
>> +     }
>> +     spin_unlock(&GlobalMid_Lock);
>> +     return rc;
>> +}
>> +
>
> The cFYI's above could be a bit more descriptive. Which server isn't
> responding here? That could be important information. Also maybe this
> should be a cERROR printk so that administrators have some sort of clue
> as to why the mount seems to be hung. Making those look similar to the
> RPC timeout messages with NFS would also add some "consistency" to the
> kernel's appearance too.

OK. I had the messages at error level but changed them back to debug level.
I have no problem going back, but such error messages can flood syslog buffer
if either server or client is slow for a long long time as observed in
some of the
test runs.  And there is no turning off these error messages.
If we have them at debug level, they are not logged until debugging in cifs is
turned on but can get lost in rest of the debug messages that also
start getting logged.
So I was not sure which option to exercise.

>
>> +
>>  static int wait_for_response(struct cifsSesInfo *ses,
>>                       struct mid_q_entry *midQ,
>>                       unsigned long timeout,
>> @@ -367,7 +405,7 @@ static int wait_for_response(struct cifsSesInfo *ses,
>>   */
>>  int
>>  SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
>> -             struct smb_hdr *in_buf, int flags)
>> +             struct smb_hdr *in_buf, int flags, bool hard_mount)
>>  {
>>       int rc;
>>       struct kvec iov[1];
>> @@ -376,7 +414,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
>>       iov[0].iov_base = (char *)in_buf;
>>       iov[0].iov_len = in_buf->smb_buf_length + 4;
>>       flags |= CIFS_NO_RESP;
>> -     rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
>> +     rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, hard_mount);
>>       cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
>>
>>       return rc;
>> @@ -385,7 +423,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
>>  int
>>  SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
>>            struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
>> -          const int flags)
>> +          const int flags, bool hard_mount)
>>  {
>>       int rc = 0;
>>       int long_op;
>> @@ -483,7 +521,12 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
>>       }
>>
>>       /* No user interrupts in wait - wreaks havoc with performance */
>> -     wait_for_response(ses, midQ, timeout, 10 * HZ);
>> +     if (hard_mount) {
>> +             rc = wait_for_response_hard(ses, midQ);
>> +             if (rc)
>> +                     goto out;
>> +     } else
>> +             wait_for_response(ses, midQ, timeout, 10 * HZ);
>
> Maybe instead of the above, it may be better to embed whether this is a
> hard or soft timeout in the mid queue entry itself. That is, add
> another parameter? What may be best is to just put in a timeout
> parameter in the mid queue entry and then set that to 0 for hard mounts.

I thought about that but instead opted for registering whether hard or soft
mount in tcon info struct because with that option in mid entry, we would not
be able to override a hard mount option.  Some of the commands should
remain soft such as unmount so deciding whether to override hard mount
option at command level made sense to me.

>
>>
>>       spin_lock(&GlobalMid_Lock);
>>
>> @@ -581,7 +624,7 @@ out:
>>  int
>>  SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
>>           struct smb_hdr *in_buf, struct smb_hdr *out_buf,
>> -         int *pbytes_returned, const int long_op)
>> +         int *pbytes_returned, const int long_op, bool hard_mount)
>>  {
>>       int rc = 0;
>>       unsigned int receive_len;
>> @@ -675,7 +718,12 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
>>       }
>>
>>       /* No user interrupts in wait - wreaks havoc with performance */
>> -     wait_for_response(ses, midQ, timeout, 10 * HZ);
>> +     if (hard_mount) {
>> +             rc = wait_for_response_hard(ses, midQ);
>> +             if (rc)
>> +                     goto out;
>> +     } else
>> +             wait_for_response(ses, midQ, timeout, 10 * HZ);
>>
>>       spin_lock(&GlobalMid_Lock);
>>       if (midQ->resp_buf == NULL) {
>> @@ -807,7 +855,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
>>       pSMB->hdr.Mid = GetNextMid(ses->server);
>>
>>       return SendReceive(xid, ses, in_buf, out_buf,
>> -                     &bytes_returned, CIFS_STD_OP);
>> +                     &bytes_returned, CIFS_STD_OP, tcon->retry);
>>  }
>>
>>  int
>
>
>
> --
> Jeff Layton <jlayton@samba.org>
>
Jeff Layton June 7, 2010, 7:55 p.m. UTC | #3
On Mon, 7 Jun 2010 14:26:50 -0500
Shirish Pargaonkar <shirishpargaonkar@gmail.com> wrote:

> On Sun, Jun 6, 2010 at 5:51 AM, Jeff Layton <jlayton@samba.org> wrote:
> > On Sat,  5 Jun 2010 11:37:05 -0500
> > shirishpargaonkar@gmail.com wrote:
> >
> >> Add support for hard mount option by using -o hard.
> >>
> >> Current cifs behaviour amounts to that of a soft mount.
> >> If a response for a command does not arrive within a certain timeout,
> >> server is considered non-responsive and a reconnect is attempted.
> >> Commands/requests are returned with error for an app to decide.
> >>
> >> This code change adds hard mount option behaviour.
> >> A command waits in interruptible wait timing out every 60 seconds
> >> to log a debug message about server not responding and going
> >> back on interruptible wait queue for another 60 seconds.
> >> Once response arrives, a debug messages is logged that server is
> >> responding.
> >> An user has an option to interrupt a program if a response has not
> >> arrived for long enough for user to deem a dead server and retry
> >> the program.
> >> This takes care of unnecessary reconnects and subsequent retries
> >> of numerous commands for invalidated file handles etc. when either
> >> the server or client is stressed or slow.
> >>
> >> These commands such as negotiate, session setup, tree connect,
> >> logoff, non-blocking posix lock, and dfs referral are always soft.
> >>
> >>
> >
> > Looks like a step in the right direction. I think this will help bring
> > better data integrity to CIFS. We really need to strive to minimize
> > reconnects since they are so costly and you lose things like file
> > locks, etc...
> >
> > Comments inline below:
> >
> >> From b1b0a7b1612dc3d865b4756dfddceeab4245a888 Mon Sep 17 00:00:00 2001
> >> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> >> Date: Sat, 5 Jun 2010 10:01:06 -0500
> >> Subject: [PATCH] add support for implementing hard mount option behaviour
> >>
> >> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> >> ---
> >>  fs/cifs/cifsproto.h |    7 ++-
> >>  fs/cifs/cifssmb.c   |  126 +++++++++++++++++++++++++++-----------------------
> >>  fs/cifs/connect.c   |    5 ++-
> >>  fs/cifs/sess.c      |    2 +-
> >>  fs/cifs/transport.c |   62 ++++++++++++++++++++++---
> >>  5 files changed, 132 insertions(+), 70 deletions(-)
> >>
> >> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> >> index fb1657e..7a475c5 100644
> >> --- a/fs/cifs/cifsproto.h
> >> +++ b/fs/cifs/cifsproto.h
> >> @@ -63,12 +63,13 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
> >>  extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
> >>                       struct smb_hdr * /* input */ ,
> >>                       struct smb_hdr * /* out */ ,
> >> -                     int * /* bytes returned */ , const int long_op);
> >> +                     int * /* bytes returned */ , const int long_op, bool);
> >>  extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
> >> -                     struct smb_hdr *in_buf, int flags);
> >> +                     struct smb_hdr *in_buf, int flags, bool hard_mount);
> >>  extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
> >>                       struct kvec *, int /* nvec to send */,
> >> -                     int * /* type of buf returned */ , const int flags);
> >> +                     int * /* type of buf returned */ , const int flags,
> >> +                     bool);
> >>  extern int SendReceiveBlockingLock(const unsigned int xid,
> >>                       struct cifsTconInfo *ptcon,
> >>                       struct smb_hdr *in_buf ,
> >> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> >> index c65c341..2634354 100644
> >> --- a/fs/cifs/cifssmb.c
> >> +++ b/fs/cifs/cifssmb.c
> >> @@ -404,7 +404,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
> >>       pSMB->ByteCount = cpu_to_le16(count);
> >>
> >>       rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, false);
> >>       if (rc != 0)
> >>               goto neg_err_exit;
> >>
> >> @@ -678,7 +678,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
> >>       if (rc)
> >>               return rc;
> >>
> >> -     rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
> >> +     rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0, tcon->retry);
> >
> >
> > I know that this parameter predates your patch, but I'm not sure that
> > the "retry" option ought to hang off of the tcon. I think it should
> > hang off of the superblock instead. It ought to be possible for someone
> > to mount the same share with both hard and soft options simultaneously.
> >
> > In fact, the default timeout for soft mounts ought to be tunable as well.
> > What may be best is to add a "call timeout" field to the superblock and
> > set that to '0' for hard mounts and then drop the "retry" parm on the
> > tcon.
> 
> I can do that.  Does that mean adding a new mount option like timeo
> which does not apply to hard mounts but only to soft mounts and if one is not
> specified for (default) soft mounts, come up with a default timeout value?

I think so, yes. "timeo" would be a good choice. There will clearly be
a difference though from how this parm works with NFS. SMB is not RPC,
so we don't really need to retransmit like RPC does.

> That means invalidating this existing logic (in fs/cifs/transport.c)?
> 
>         if (long_op == CIFS_STD_OP)
>                 timeout = 15 * HZ;
>         /* wait for 15 seconds or until woken up due to response arriving or
>            due to last connection to this server being unmounted */
>         else if (long_op == CIFS_ASYNC_OP)
>                 goto out;
>         else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
>                 timeout = 180 * HZ;
>         else if (long_op == CIFS_LONG_OP)
>                 timeout = 45 * HZ; /* should be greater than
>                         servers oplock break timeout (about 43 seconds) */
>         else if (long_op == CIFS_BLOCKING_OP)
>                 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
>         else {
>                 cERROR(1, "unknown timeout flag %d", long_op);
>                 rc = -EIO;
>                 goto out;
>         }
> 
> We do not really need a timeout value for hard mounts, the timeout
> value used in hard mount
> is only to wake up and log a message if response has not arrived.
> 

Yes, probably so.

It may be worthwhile to step back from the existing code and give this
a hard rethink from first principles.

What's the real purpose in having timeouts at all? Once the server has
ACK'ed the TCP packet we know that it has been received. It seems
really silly to break the connection at that point just because it gets
bogged down while servicing the request.

We ought to be going to great lengths to *avoid* breaking the
connection whenever possible as so much of the state is tied up with
the state of the socket.

> >
> >>       if (rc)
> >>               cFYI(1, "Tree disconnect failed %d", rc);
> >>
> >> @@ -725,7 +725,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
> >>       pSMB->hdr.Uid = ses->Suid;
> >>
> >>       pSMB->AndXCommand = 0xFF;
> >> -     rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
> >> +     rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0, false);
> >>  session_already_dead:
> >>       mutex_unlock(&ses->session_mutex);
> >>
> >> @@ -799,7 +799,7 @@ PsxDelete:
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc)
> >>               cFYI(1, "Posix delete returned %d", rc);
> >>       cifs_buf_release(pSMB);
> >> @@ -845,7 +845,7 @@ DelFileRetry:
> >>       pSMB->hdr.smb_buf_length += name_len + 1;
> >>       pSMB->ByteCount = cpu_to_le16(name_len + 1);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_deletes);
> >>       if (rc)
> >>               cFYI(1, "Error in RMFile = %d", rc);
> >> @@ -889,7 +889,7 @@ RmDirRetry:
> >>       pSMB->hdr.smb_buf_length += name_len + 1;
> >>       pSMB->ByteCount = cpu_to_le16(name_len + 1);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_rmdirs);
> >>       if (rc)
> >>               cFYI(1, "Error in RMDir = %d", rc);
> >> @@ -932,7 +932,7 @@ MkDirRetry:
> >>       pSMB->hdr.smb_buf_length += name_len + 1;
> >>       pSMB->ByteCount = cpu_to_le16(name_len + 1);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_mkdirs);
> >>       if (rc)
> >>               cFYI(1, "Error in Mkdir = %d", rc);
> >> @@ -1010,7 +1010,7 @@ PsxCreat:
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Posix create returned %d", rc);
> >>               goto psx_create_err;
> >> @@ -1177,7 +1177,8 @@ OldOpenRetry:
> >>       pSMB->ByteCount = cpu_to_le16(count);
> >>       /* long_op set to 1 to allow for oplock break timeouts */
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                     (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
> >> +             (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP,
> >> +             tcon->retry);
> >>       cifs_stats_inc(&tcon->num_opens);
> >>       if (rc) {
> >>               cFYI(1, "Error in Open = %d", rc);
> >> @@ -1290,7 +1291,8 @@ openRetry:
> >>       pSMB->ByteCount = cpu_to_le16(count);
> >>       /* long_op set to 1 to allow for oplock break timeouts */
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                     (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
> >> +             (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP,
> >> +             tcon->retry);
> >>       cifs_stats_inc(&tcon->num_opens);
> >>       if (rc) {
> >>               cFYI(1, "Error in Open = %d", rc);
> >> @@ -1372,7 +1374,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
> >>       iov[0].iov_base = (char *)pSMB;
> >>       iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
> >>       rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
> >> -                      &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
> >> +              &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_reads);
> >>       pSMBr = (READ_RSP *)iov[0].iov_base;
> >>       if (rc) {
> >> @@ -1516,7 +1518,8 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
> >>       }
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
> >> +             (struct smb_hdr *) pSMBr, &bytes_returned, long_op,
> >> +             tcon->retry);
> >>       cifs_stats_inc(&tcon->num_writes);
> >>       if (rc) {
> >>               cFYI(1, "Send error in write = %d", rc);
> >> @@ -1608,7 +1611,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
> >>
> >>
> >>       rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
> >> -                       long_op);
> >> +                       long_op, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_writes);
> >>       if (rc) {
> >>               cFYI(1, "Send error Write2 = %d", rc);
> >> @@ -1699,7 +1702,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
> >>               cifs_small_buf_release(pSMB);
> >>       } else {
> >>               rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
> >> -                                   timeout);
> >> +                                   timeout, tcon->retry);
> >>               /* SMB buffer freed by function above */
> >>       }
> >>       cifs_stats_inc(&tcon->num_locks);
> >> @@ -1790,7 +1793,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
> >>               iov[0].iov_base = (char *)pSMB;
> >>               iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
> >>               rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
> >> -                             &resp_buf_type, timeout);
> >> +                             &resp_buf_type, timeout, false);
> >>               pSMB = NULL; /* request buf already freed by SendReceive2. Do
> >>                               not try to free it twice below on exit */
> >>               pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
> >> @@ -1866,7 +1869,8 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
> >>       pSMB->FileID = (__u16) smb_file_id;
> >>       pSMB->LastWriteTime = 0xFFFFFFFF;
> >>       pSMB->ByteCount = 0;
> >> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> >> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> >> +                             tcon->retry);
> >>       cifs_stats_inc(&tcon->num_closes);
> >>       if (rc) {
> >>               if (rc != -EINTR) {
> >> @@ -1895,7 +1899,8 @@ CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
> >>
> >>       pSMB->FileID = (__u16) smb_file_id;
> >>       pSMB->ByteCount = 0;
> >> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> >> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> >> +                             tcon->retry);
> >>       cifs_stats_inc(&tcon->num_flushes);
> >>       if (rc)
> >>               cERROR(1, "Send error in Flush = %d", rc);
> >> @@ -1958,7 +1963,7 @@ renameRetry:
> >>       pSMB->ByteCount = cpu_to_le16(count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_renames);
> >>       if (rc)
> >>               cFYI(1, "Send error in rename = %d", rc);
> >> @@ -2037,7 +2042,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, pTcon->retry);
> >>       cifs_stats_inc(&pTcon->num_t2renames);
> >>       if (rc)
> >>               cFYI(1, "Send error in Rename (by file handle) = %d", rc);
> >> @@ -2105,7 +2110,7 @@ copyRetry:
> >>       pSMB->ByteCount = cpu_to_le16(count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -             (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in copy = %d with %d files copied",
> >>                       rc, le16_to_cpu(pSMBr->CopyCount));
> >> @@ -2194,7 +2199,7 @@ createSymLinkRetry:
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_symlinks);
> >>       if (rc)
> >>               cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
> >> @@ -2280,7 +2285,7 @@ createHardLinkRetry:
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_hardlinks);
> >>       if (rc)
> >>               cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
> >> @@ -2352,7 +2357,7 @@ winCreateHardLinkRetry:
> >>       pSMB->ByteCount = cpu_to_le16(count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_hardlinks);
> >>       if (rc)
> >>               cFYI(1, "Send error in hard link (NT rename) = %d", rc);
> >> @@ -2423,7 +2428,7 @@ querySymLinkRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
> >>       } else {
> >> @@ -2586,7 +2591,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
> >>       pSMB->ByteCount = 0;
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -2849,7 +2854,7 @@ queryAclRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -             (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_acl_get);
> >>       if (rc) {
> >>               cFYI(1, "Send error in Query POSIX ACL = %d", rc);
> >> @@ -2942,7 +2947,7 @@ setAclRetry:
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc)
> >>               cFYI(1, "Set POSIX ACL returned %d", rc);
> >>
> >> @@ -3001,7 +3006,7 @@ GetExtAttrRetry:
> >>       pSMB->t2.ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "error %d in GetExtAttr", rc);
> >>       } else {
> >> @@ -3070,7 +3075,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
> >>       iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
> >>
> >>       rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
> >> -                      CIFS_STD_OP);
> >> +                      CIFS_STD_OP, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_acl_get);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QuerySecDesc = %d", rc);
> >> @@ -3182,7 +3187,7 @@ setCifsAclRetry:
> >>               pSMB->hdr.smb_buf_length += byte_count;
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -             (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>
> >>       cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
> >>       if (rc)
> >> @@ -3234,7 +3239,7 @@ QInfRetry:
> >>       pSMB->ByteCount = cpu_to_le16(name_len);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QueryInfo = %d", rc);
> >>       } else if (pFinfo) {
> >> @@ -3308,7 +3313,7 @@ QFileInfoRetry:
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QPathInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -3396,7 +3401,7 @@ QPathInfoRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QPathInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -3476,7 +3481,7 @@ UnixQFileInfoRetry:
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QPathInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -3562,7 +3567,7 @@ UnixQPathInfoRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QPathInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -3676,7 +3681,7 @@ findFirstRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_ffirst);
> >>
> >>       if (rc) {/* BB add logic to retry regular search if Unix search
> >> @@ -3805,7 +3810,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                     (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       cifs_stats_inc(&tcon->num_fnext);
> >>       if (rc) {
> >>               if (rc == -EBADF) {
> >> @@ -3894,7 +3899,8 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
> >>
> >>       pSMB->FileID = searchHandle;
> >>       pSMB->ByteCount = 0;
> >> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> >> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> >> +                             tcon->retry);
> >>       if (rc)
> >>               cERROR(1, "Send error in FindClose = %d", rc);
> >>
> >> @@ -3967,7 +3973,7 @@ GetInodeNumberRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -             (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "error %d in QueryInternalInfo", rc);
> >>       } else {
> >> @@ -4191,7 +4197,7 @@ getDFSRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, false);
> >>       if (rc) {
> >>               cFYI(1, "Send error in GetDFSRefer = %d", rc);
> >>               goto GetDFSRefExit;
> >> @@ -4265,7 +4271,7 @@ oldQFSInfoRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -             (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +             (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QFSInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -4344,7 +4350,7 @@ QFSInfoRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QFSInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -4424,7 +4430,7 @@ QFSAttributeRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -4495,7 +4501,7 @@ QFSDeviceRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -4564,7 +4570,7 @@ QFSUnixRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cERROR(1, "Send error in QFSUnixInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -4647,7 +4653,7 @@ SETFSUnixRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -4709,7 +4715,7 @@ QFSPosixRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QFSUnixInfo = %d", rc);
> >>       } else {                /* decode response */
> >> @@ -4835,7 +4841,7 @@ SetEOFRetry:
> >>       parm_data->FileSize = cpu_to_le64(size);
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc)
> >>               cFYI(1, "SetPathInfo (file size) returned %d", rc);
> >>
> >> @@ -4915,7 +4921,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
> >>       pSMB->Reserved4 = 0;
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> >> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> >> +                             tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
> >>       }
> >> @@ -4984,7 +4991,8 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
> >> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> >> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> >> +                             tcon->retry);
> >>       if (rc)
> >>               cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
> >>
> >> @@ -5043,7 +5051,8 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       *data_offset = delete_file ? 1 : 0;
> >> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> >> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> >> +                             tcon->retry);
> >>       if (rc)
> >>               cFYI(1, "Send error in SetFileDisposition = %d", rc);
> >>
> >> @@ -5117,7 +5126,7 @@ SetTimesRetry:
> >>       memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc)
> >>               cFYI(1, "SetPathInfo (times) returned %d", rc);
> >>
> >> @@ -5275,7 +5284,8 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
> >>
> >>       cifs_fill_unix_set_info(data_offset, args);
> >>
> >> -     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> >> +     rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
> >> +                             tcon->retry);
> >>       if (rc)
> >>               cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
> >>
> >> @@ -5352,7 +5362,7 @@ setPermsRetry:
> >>
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc)
> >>               cFYI(1, "SetPathInfo (perms) returned %d", rc);
> >>
> >> @@ -5404,8 +5414,8 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
> >>       pSMB->ByteCount = 0;
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *)pSMBr, &bytes_returned,
> >> -                      CIFS_ASYNC_OP);
> >> +             (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_ASYNC_OP,
> >> +             tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Error in Notify = %d", rc);
> >>       } else {
> >> @@ -5508,7 +5518,7 @@ QAllEAsRetry:
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc) {
> >>               cFYI(1, "Send error in QueryAllEAs = %d", rc);
> >>               goto QAllEAsOut;
> >> @@ -5720,7 +5730,7 @@ SetEARetry:
> >>       pSMB->hdr.smb_buf_length += byte_count;
> >>       pSMB->ByteCount = cpu_to_le16(byte_count);
> >>       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
> >> -                      (struct smb_hdr *) pSMBr, &bytes_returned, 0);
> >> +              (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
> >>       if (rc)
> >>               cFYI(1, "SetPathInfo (EA) returned %d", rc);
> >>
> >> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> >> index 2208f06..7ddc602 100644
> >> --- a/fs/cifs/connect.c
> >> +++ b/fs/cifs/connect.c
> >> @@ -1809,6 +1809,9 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
> >>               }
> >>       }
> >>
> >> +     if (volume_info->retry)
> >> +             tcon->retry = volume_info->retry;
> >> +
> >>       if (strchr(volume_info->UNC + 3, '\\') == NULL
> >>           && strchr(volume_info->UNC + 3, '/') == NULL) {
> >>               cERROR(1, "Missing share name");
> >> @@ -2807,7 +2810,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
> >>       pSMB->ByteCount = cpu_to_le16(count);
> >>
> >>       rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
> >> -                      CIFS_STD_OP);
> >> +                      CIFS_STD_OP, false);
> >>
> >>       /* above now done in SendReceive */
> >>       if ((rc == 0) && (tcon != NULL)) {
> >> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
> >> index 7707389..ff0dfb7 100644
> >> --- a/fs/cifs/sess.c
> >> +++ b/fs/cifs/sess.c
> >> @@ -866,7 +866,7 @@ ssetup_ntlmssp_authenticate:
> >>       BCC_LE(smb_buf) = cpu_to_le16(count);
> >>
> >>       rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
> >> -                       CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR);
> >> +               CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR, false);
> >>       /* SMB request buf freed in SendReceive2 */
> >>
> >>       cFYI(1, "ssetup rc from sendrecv2 is %d", rc);
> >> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> >> index 82f78c4..0c7a07e 100644
> >> --- a/fs/cifs/transport.c
> >> +++ b/fs/cifs/transport.c
> >> @@ -311,6 +311,44 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
> >>       return 0;
> >>  }
> >>
> >> +static int
> >> +wait_for_response_hard(struct cifsSesInfo *ses, struct mid_q_entry *midQ)
> >> +{
> >> +     int rc;
> >> +     bool cmdresp = true;
> >> +     unsigned long timeout = 60 * HZ;
> >> +     unsigned long curr_timeout;
> >> +
> >> +wait_again:
> >> +     curr_timeout = timeout + jiffies;
> >> +     rc = wait_event_interruptible_timeout(ses->server->response_q,
> >> +                     (midQ->midState != MID_REQUEST_SUBMITTED), timeout);
> >> +
> >> +     if (rc < 0) {
> >> +             cFYI(1, "command 0x%x interrupted", midQ->command);
> >> +             return -1;
> >> +     }
> >> +     if (!time_before(jiffies, curr_timeout)) {
> >> +             cmdresp = false;
> >> +             cFYI(1, "server not responding...");
> >> +             goto wait_again;
> >> +     }
> >> +     spin_lock(&GlobalMid_Lock);
> >> +     if (midQ->midState != MID_REQUEST_SUBMITTED) {
> >> +             if (midQ->midState == MID_RESPONSE_RECEIVED) {
> >> +                     if (!cmdresp)
> >> +                             cFYI(1, "server is ok...");
> >> +                     rc = 0;
> >> +             } else {
> >> +                     cFYI(1, "command 0x%x aborted", midQ->command);
> >> +                     rc = -1;
> >> +             }
> >> +     }
> >> +     spin_unlock(&GlobalMid_Lock);
> >> +     return rc;
> >> +}
> >> +
> >
> > The cFYI's above could be a bit more descriptive. Which server isn't
> > responding here? That could be important information. Also maybe this
> > should be a cERROR printk so that administrators have some sort of clue
> > as to why the mount seems to be hung. Making those look similar to the
> > RPC timeout messages with NFS would also add some "consistency" to the
> > kernel's appearance too.
> 
> OK. I had the messages at error level but changed them back to debug level.
> I have no problem going back, but such error messages can flood syslog buffer
> if either server or client is slow for a long long time as observed in
> some of the
> test runs.  And there is no turning off these error messages.
> If we have them at debug level, they are not logged until debugging in cifs is
> turned on but can get lost in rest of the debug messages that also
> start getting logged.
> So I was not sure which option to exercise.
> 
> >


They should be appropriately ratelimited. You don't want to spam syslog
with tons of these per second, but one per-minute per-server or so
seems reasonable to me.

It might be best to attempt to emulate the format of and the frequency
at which the NFS/RPC code spews these sorts of messages. 

> >> +
> >>  static int wait_for_response(struct cifsSesInfo *ses,
> >>                       struct mid_q_entry *midQ,
> >>                       unsigned long timeout,
> >> @@ -367,7 +405,7 @@ static int wait_for_response(struct cifsSesInfo *ses,
> >>   */
> >>  int
> >>  SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
> >> -             struct smb_hdr *in_buf, int flags)
> >> +             struct smb_hdr *in_buf, int flags, bool hard_mount)
> >>  {
> >>       int rc;
> >>       struct kvec iov[1];
> >> @@ -376,7 +414,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
> >>       iov[0].iov_base = (char *)in_buf;
> >>       iov[0].iov_len = in_buf->smb_buf_length + 4;
> >>       flags |= CIFS_NO_RESP;
> >> -     rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
> >> +     rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, hard_mount);
> >>       cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
> >>
> >>       return rc;
> >> @@ -385,7 +423,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
> >>  int
> >>  SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
> >>            struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
> >> -          const int flags)
> >> +          const int flags, bool hard_mount)
> >>  {
> >>       int rc = 0;
> >>       int long_op;
> >> @@ -483,7 +521,12 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
> >>       }
> >>
> >>       /* No user interrupts in wait - wreaks havoc with performance */
> >> -     wait_for_response(ses, midQ, timeout, 10 * HZ);
> >> +     if (hard_mount) {
> >> +             rc = wait_for_response_hard(ses, midQ);
> >> +             if (rc)
> >> +                     goto out;
> >> +     } else
> >> +             wait_for_response(ses, midQ, timeout, 10 * HZ);
> >
> > Maybe instead of the above, it may be better to embed whether this is a
> > hard or soft timeout in the mid queue entry itself. That is, add
> > another parameter? What may be best is to just put in a timeout
> > parameter in the mid queue entry and then set that to 0 for hard mounts.
> 
> I thought about that but instead opted for registering whether hard or soft
> mount in tcon info struct because with that option in mid entry, we would not
> be able to override a hard mount option.  Some of the commands should
> remain soft such as unmount so deciding whether to override hard mount
> option at command level made sense to me.
> 

Override with -o remount you mean? Hmmm, ok I can probably buy that. It
might be reasonable to allow someone to flip a mount between soft and
hard mounts and expect that to apply to existing in-flight SMB's.

> >
> >>
> >>       spin_lock(&GlobalMid_Lock);
> >>
> >> @@ -581,7 +624,7 @@ out:
> >>  int
> >>  SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
> >>           struct smb_hdr *in_buf, struct smb_hdr *out_buf,
> >> -         int *pbytes_returned, const int long_op)
> >> +         int *pbytes_returned, const int long_op, bool hard_mount)
> >>  {
> >>       int rc = 0;
> >>       unsigned int receive_len;
> >> @@ -675,7 +718,12 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
> >>       }
> >>
> >>       /* No user interrupts in wait - wreaks havoc with performance */
> >> -     wait_for_response(ses, midQ, timeout, 10 * HZ);
> >> +     if (hard_mount) {
> >> +             rc = wait_for_response_hard(ses, midQ);
> >> +             if (rc)
> >> +                     goto out;
> >> +     } else
> >> +             wait_for_response(ses, midQ, timeout, 10 * HZ);
> >>
> >>       spin_lock(&GlobalMid_Lock);
> >>       if (midQ->resp_buf == NULL) {
> >> @@ -807,7 +855,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
> >>       pSMB->hdr.Mid = GetNextMid(ses->server);
> >>
> >>       return SendReceive(xid, ses, in_buf, out_buf,
> >> -                     &bytes_returned, CIFS_STD_OP);
> >> +                     &bytes_returned, CIFS_STD_OP, tcon->retry);
> >>  }
> >>
> >>  int
> >
> >
> >
diff mbox

Patch

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index fb1657e..7a475c5 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -63,12 +63,13 @@  extern char *cifs_compose_mount_options(const char *sb_mountdata,
 extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
 			struct smb_hdr * /* input */ ,
 			struct smb_hdr * /* out */ ,
-			int * /* bytes returned */ , const int long_op);
+			int * /* bytes returned */ , const int long_op, bool);
 extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
-			struct smb_hdr *in_buf, int flags);
+			struct smb_hdr *in_buf, int flags, bool hard_mount);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
 			struct kvec *, int /* nvec to send */,
-			int * /* type of buf returned */ , const int flags);
+			int * /* type of buf returned */ , const int flags,
+			bool);
 extern int SendReceiveBlockingLock(const unsigned int xid,
 			struct cifsTconInfo *ptcon,
 			struct smb_hdr *in_buf ,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index c65c341..2634354 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -404,7 +404,7 @@  CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 	pSMB->ByteCount = cpu_to_le16(count);
 
 	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, false);
 	if (rc != 0)
 		goto neg_err_exit;
 
@@ -678,7 +678,7 @@  CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
 	if (rc)
 		return rc;
 
-	rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0, tcon->retry);
 	if (rc)
 		cFYI(1, "Tree disconnect failed %d", rc);
 
@@ -725,7 +725,7 @@  CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
 	pSMB->hdr.Uid = ses->Suid;
 
 	pSMB->AndXCommand = 0xFF;
-	rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0, false);
 session_already_dead:
 	mutex_unlock(&ses->session_mutex);
 
@@ -799,7 +799,7 @@  PsxDelete:
 	pSMB->hdr.smb_buf_length += byte_count;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc)
 		cFYI(1, "Posix delete returned %d", rc);
 	cifs_buf_release(pSMB);
@@ -845,7 +845,7 @@  DelFileRetry:
 	pSMB->hdr.smb_buf_length += name_len + 1;
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	cifs_stats_inc(&tcon->num_deletes);
 	if (rc)
 		cFYI(1, "Error in RMFile = %d", rc);
@@ -889,7 +889,7 @@  RmDirRetry:
 	pSMB->hdr.smb_buf_length += name_len + 1;
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	cifs_stats_inc(&tcon->num_rmdirs);
 	if (rc)
 		cFYI(1, "Error in RMDir = %d", rc);
@@ -932,7 +932,7 @@  MkDirRetry:
 	pSMB->hdr.smb_buf_length += name_len + 1;
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	cifs_stats_inc(&tcon->num_mkdirs);
 	if (rc)
 		cFYI(1, "Error in Mkdir = %d", rc);
@@ -1010,7 +1010,7 @@  PsxCreat:
 	pSMB->hdr.smb_buf_length += byte_count;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Posix create returned %d", rc);
 		goto psx_create_err;
@@ -1177,7 +1177,8 @@  OldOpenRetry:
 	pSMB->ByteCount = cpu_to_le16(count);
 	/* long_op set to 1 to allow for oplock break timeouts */
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
+		(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP,
+		tcon->retry);
 	cifs_stats_inc(&tcon->num_opens);
 	if (rc) {
 		cFYI(1, "Error in Open = %d", rc);
@@ -1290,7 +1291,8 @@  openRetry:
 	pSMB->ByteCount = cpu_to_le16(count);
 	/* long_op set to 1 to allow for oplock break timeouts */
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
+		(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP,
+		tcon->retry);
 	cifs_stats_inc(&tcon->num_opens);
 	if (rc) {
 		cFYI(1, "Error in Open = %d", rc);
@@ -1372,7 +1374,7 @@  CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
 	iov[0].iov_base = (char *)pSMB;
 	iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
 	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
-			 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
+		 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR, tcon->retry);
 	cifs_stats_inc(&tcon->num_reads);
 	pSMBr = (READ_RSP *)iov[0].iov_base;
 	if (rc) {
@@ -1516,7 +1518,8 @@  CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 	}
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
+		(struct smb_hdr *) pSMBr, &bytes_returned, long_op,
+		tcon->retry);
 	cifs_stats_inc(&tcon->num_writes);
 	if (rc) {
 		cFYI(1, "Send error in write = %d", rc);
@@ -1608,7 +1611,7 @@  CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 
 
 	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
-			  long_op);
+			  long_op, tcon->retry);
 	cifs_stats_inc(&tcon->num_writes);
 	if (rc) {
 		cFYI(1, "Send error Write2 = %d", rc);
@@ -1699,7 +1702,7 @@  CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 		cifs_small_buf_release(pSMB);
 	} else {
 		rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
-				      timeout);
+				      timeout, tcon->retry);
 		/* SMB buffer freed by function above */
 	}
 	cifs_stats_inc(&tcon->num_locks);
@@ -1790,7 +1793,7 @@  CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
 		iov[0].iov_base = (char *)pSMB;
 		iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
 		rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
-				&resp_buf_type, timeout);
+				&resp_buf_type, timeout, false);
 		pSMB = NULL; /* request buf already freed by SendReceive2. Do
 				not try to free it twice below on exit */
 		pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
@@ -1866,7 +1869,8 @@  CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 	pSMB->FileID = (__u16) smb_file_id;
 	pSMB->LastWriteTime = 0xFFFFFFFF;
 	pSMB->ByteCount = 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
+				tcon->retry);
 	cifs_stats_inc(&tcon->num_closes);
 	if (rc) {
 		if (rc != -EINTR) {
@@ -1895,7 +1899,8 @@  CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 
 	pSMB->FileID = (__u16) smb_file_id;
 	pSMB->ByteCount = 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
+				tcon->retry);
 	cifs_stats_inc(&tcon->num_flushes);
 	if (rc)
 		cERROR(1, "Send error in Flush = %d", rc);
@@ -1958,7 +1963,7 @@  renameRetry:
 	pSMB->ByteCount = cpu_to_le16(count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	cifs_stats_inc(&tcon->num_renames);
 	if (rc)
 		cFYI(1, "Send error in rename = %d", rc);
@@ -2037,7 +2042,7 @@  int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
 	pSMB->hdr.smb_buf_length += byte_count;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, pTcon->retry);
 	cifs_stats_inc(&pTcon->num_t2renames);
 	if (rc)
 		cFYI(1, "Send error in Rename (by file handle) = %d", rc);
@@ -2105,7 +2110,7 @@  copyRetry:
 	pSMB->ByteCount = cpu_to_le16(count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in copy = %d with %d files copied",
 			rc, le16_to_cpu(pSMBr->CopyCount));
@@ -2194,7 +2199,7 @@  createSymLinkRetry:
 	pSMB->hdr.smb_buf_length += byte_count;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	cifs_stats_inc(&tcon->num_symlinks);
 	if (rc)
 		cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
@@ -2280,7 +2285,7 @@  createHardLinkRetry:
 	pSMB->hdr.smb_buf_length += byte_count;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	cifs_stats_inc(&tcon->num_hardlinks);
 	if (rc)
 		cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
@@ -2352,7 +2357,7 @@  winCreateHardLinkRetry:
 	pSMB->ByteCount = cpu_to_le16(count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	cifs_stats_inc(&tcon->num_hardlinks);
 	if (rc)
 		cFYI(1, "Send error in hard link (NT rename) = %d", rc);
@@ -2423,7 +2428,7 @@  querySymLinkRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
 	} else {
@@ -2586,7 +2591,7 @@  CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
 	pSMB->ByteCount = 0;
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
 	} else {		/* decode response */
@@ -2849,7 +2854,7 @@  queryAclRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	cifs_stats_inc(&tcon->num_acl_get);
 	if (rc) {
 		cFYI(1, "Send error in Query POSIX ACL = %d", rc);
@@ -2942,7 +2947,7 @@  setAclRetry:
 	pSMB->hdr.smb_buf_length += byte_count;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc)
 		cFYI(1, "Set POSIX ACL returned %d", rc);
 
@@ -3001,7 +3006,7 @@  GetExtAttrRetry:
 	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "error %d in GetExtAttr", rc);
 	} else {
@@ -3070,7 +3075,7 @@  CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
 	iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
 
 	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
-			 CIFS_STD_OP);
+			 CIFS_STD_OP, tcon->retry);
 	cifs_stats_inc(&tcon->num_acl_get);
 	if (rc) {
 		cFYI(1, "Send error in QuerySecDesc = %d", rc);
@@ -3182,7 +3187,7 @@  setCifsAclRetry:
 		pSMB->hdr.smb_buf_length += byte_count;
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 
 	cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
 	if (rc)
@@ -3234,7 +3239,7 @@  QInfRetry:
 	pSMB->ByteCount = cpu_to_le16(name_len);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QueryInfo = %d", rc);
 	} else if (pFinfo) {
@@ -3308,7 +3313,7 @@  QFileInfoRetry:
 	pSMB->hdr.smb_buf_length += byte_count;
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QPathInfo = %d", rc);
 	} else {		/* decode response */
@@ -3396,7 +3401,7 @@  QPathInfoRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QPathInfo = %d", rc);
 	} else {		/* decode response */
@@ -3476,7 +3481,7 @@  UnixQFileInfoRetry:
 	pSMB->hdr.smb_buf_length += byte_count;
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QPathInfo = %d", rc);
 	} else {		/* decode response */
@@ -3562,7 +3567,7 @@  UnixQPathInfoRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QPathInfo = %d", rc);
 	} else {		/* decode response */
@@ -3676,7 +3681,7 @@  findFirstRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	cifs_stats_inc(&tcon->num_ffirst);
 
 	if (rc) {/* BB add logic to retry regular search if Unix search
@@ -3805,7 +3810,7 @@  int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	cifs_stats_inc(&tcon->num_fnext);
 	if (rc) {
 		if (rc == -EBADF) {
@@ -3894,7 +3899,8 @@  CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
 
 	pSMB->FileID = searchHandle;
 	pSMB->ByteCount = 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
+				tcon->retry);
 	if (rc)
 		cERROR(1, "Send error in FindClose = %d", rc);
 
@@ -3967,7 +3973,7 @@  GetInodeNumberRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "error %d in QueryInternalInfo", rc);
 	} else {
@@ -4191,7 +4197,7 @@  getDFSRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, false);
 	if (rc) {
 		cFYI(1, "Send error in GetDFSRefer = %d", rc);
 		goto GetDFSRefExit;
@@ -4265,7 +4271,7 @@  oldQFSInfoRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QFSInfo = %d", rc);
 	} else {                /* decode response */
@@ -4344,7 +4350,7 @@  QFSInfoRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QFSInfo = %d", rc);
 	} else {		/* decode response */
@@ -4424,7 +4430,7 @@  QFSAttributeRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
 	} else {		/* decode response */
@@ -4495,7 +4501,7 @@  QFSDeviceRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
 	} else {		/* decode response */
@@ -4564,7 +4570,7 @@  QFSUnixRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cERROR(1, "Send error in QFSUnixInfo = %d", rc);
 	} else {		/* decode response */
@@ -4647,7 +4653,7 @@  SETFSUnixRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
 	} else {		/* decode response */
@@ -4709,7 +4715,7 @@  QFSPosixRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QFSUnixInfo = %d", rc);
 	} else {		/* decode response */
@@ -4835,7 +4841,7 @@  SetEOFRetry:
 	parm_data->FileSize = cpu_to_le64(size);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc)
 		cFYI(1, "SetPathInfo (file size) returned %d", rc);
 
@@ -4915,7 +4921,8 @@  CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
 	pSMB->Reserved4 = 0;
 	pSMB->hdr.smb_buf_length += byte_count;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
+				tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
 	}
@@ -4984,7 +4991,8 @@  CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
 	pSMB->hdr.smb_buf_length += byte_count;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
+				tcon->retry);
 	if (rc)
 		cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
 
@@ -5043,7 +5051,8 @@  CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
 	pSMB->hdr.smb_buf_length += byte_count;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	*data_offset = delete_file ? 1 : 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
+				tcon->retry);
 	if (rc)
 		cFYI(1, "Send error in SetFileDisposition = %d", rc);
 
@@ -5117,7 +5126,7 @@  SetTimesRetry:
 	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc)
 		cFYI(1, "SetPathInfo (times) returned %d", rc);
 
@@ -5275,7 +5284,8 @@  CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
 
 	cifs_fill_unix_set_info(data_offset, args);
 
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0,
+				tcon->retry);
 	if (rc)
 		cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
 
@@ -5352,7 +5362,7 @@  setPermsRetry:
 
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc)
 		cFYI(1, "SetPathInfo (perms) returned %d", rc);
 
@@ -5404,8 +5414,8 @@  int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
 	pSMB->ByteCount = 0;
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *)pSMBr, &bytes_returned,
-			 CIFS_ASYNC_OP);
+		(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_ASYNC_OP,
+		tcon->retry);
 	if (rc) {
 		cFYI(1, "Error in Notify = %d", rc);
 	} else {
@@ -5508,7 +5518,7 @@  QAllEAsRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc) {
 		cFYI(1, "Send error in QueryAllEAs = %d", rc);
 		goto QAllEAsOut;
@@ -5720,7 +5730,7 @@  SetEARetry:
 	pSMB->hdr.smb_buf_length += byte_count;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+		 (struct smb_hdr *) pSMBr, &bytes_returned, 0, tcon->retry);
 	if (rc)
 		cFYI(1, "SetPathInfo (EA) returned %d", rc);
 
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 2208f06..7ddc602 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1809,6 +1809,9 @@  cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
 		}
 	}
 
+	if (volume_info->retry)
+		tcon->retry = volume_info->retry;
+
 	if (strchr(volume_info->UNC + 3, '\\') == NULL
 	    && strchr(volume_info->UNC + 3, '/') == NULL) {
 		cERROR(1, "Missing share name");
@@ -2807,7 +2810,7 @@  CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 	pSMB->ByteCount = cpu_to_le16(count);
 
 	rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
-			 CIFS_STD_OP);
+			 CIFS_STD_OP, false);
 
 	/* above now done in SendReceive */
 	if ((rc == 0) && (tcon != NULL)) {
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 7707389..ff0dfb7 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -866,7 +866,7 @@  ssetup_ntlmssp_authenticate:
 	BCC_LE(smb_buf) = cpu_to_le16(count);
 
 	rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
-			  CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR);
+		  CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR, false);
 	/* SMB request buf freed in SendReceive2 */
 
 	cFYI(1, "ssetup rc from sendrecv2 is %d", rc);
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 82f78c4..0c7a07e 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -311,6 +311,44 @@  static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
 	return 0;
 }
 
+static int
+wait_for_response_hard(struct cifsSesInfo *ses, struct mid_q_entry *midQ)
+{
+	int rc;
+	bool cmdresp = true;
+	unsigned long timeout = 60 * HZ;
+	unsigned long curr_timeout;
+
+wait_again:
+	curr_timeout = timeout + jiffies;
+	rc = wait_event_interruptible_timeout(ses->server->response_q,
+			(midQ->midState != MID_REQUEST_SUBMITTED), timeout);
+
+	if (rc < 0) {
+		cFYI(1, "command 0x%x interrupted", midQ->command);
+		return -1;
+	}
+	if (!time_before(jiffies, curr_timeout)) {
+		cmdresp = false;
+		cFYI(1, "server not responding...");
+		goto wait_again;
+	}
+	spin_lock(&GlobalMid_Lock);
+	if (midQ->midState != MID_REQUEST_SUBMITTED) {
+		if (midQ->midState == MID_RESPONSE_RECEIVED) {
+			if (!cmdresp)
+				cFYI(1, "server is ok...");
+			rc = 0;
+		} else {
+			cFYI(1, "command 0x%x aborted", midQ->command);
+			rc = -1;
+		}
+	}
+	spin_unlock(&GlobalMid_Lock);
+	return rc;
+}
+
+
 static int wait_for_response(struct cifsSesInfo *ses,
 			struct mid_q_entry *midQ,
 			unsigned long timeout,
@@ -367,7 +405,7 @@  static int wait_for_response(struct cifsSesInfo *ses,
  */
 int
 SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
-		struct smb_hdr *in_buf, int flags)
+		struct smb_hdr *in_buf, int flags, bool hard_mount)
 {
 	int rc;
 	struct kvec iov[1];
@@ -376,7 +414,7 @@  SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
 	iov[0].iov_base = (char *)in_buf;
 	iov[0].iov_len = in_buf->smb_buf_length + 4;
 	flags |= CIFS_NO_RESP;
-	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
+	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, hard_mount);
 	cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
 
 	return rc;
@@ -385,7 +423,7 @@  SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
 int
 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 	     struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
-	     const int flags)
+	     const int flags, bool hard_mount)
 {
 	int rc = 0;
 	int long_op;
@@ -483,7 +521,12 @@  SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 	}
 
 	/* No user interrupts in wait - wreaks havoc with performance */
-	wait_for_response(ses, midQ, timeout, 10 * HZ);
+	if (hard_mount) {
+		rc = wait_for_response_hard(ses, midQ);
+		if (rc)
+			goto out;
+	} else
+		wait_for_response(ses, midQ, timeout, 10 * HZ);
 
 	spin_lock(&GlobalMid_Lock);
 
@@ -581,7 +624,7 @@  out:
 int
 SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
-	    int *pbytes_returned, const int long_op)
+	    int *pbytes_returned, const int long_op, bool hard_mount)
 {
 	int rc = 0;
 	unsigned int receive_len;
@@ -675,7 +718,12 @@  SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 	}
 
 	/* No user interrupts in wait - wreaks havoc with performance */
-	wait_for_response(ses, midQ, timeout, 10 * HZ);
+	if (hard_mount) {
+		rc = wait_for_response_hard(ses, midQ);
+		if (rc)
+			goto out;
+	} else
+		wait_for_response(ses, midQ, timeout, 10 * HZ);
 
 	spin_lock(&GlobalMid_Lock);
 	if (midQ->resp_buf == NULL) {
@@ -807,7 +855,7 @@  send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
 	pSMB->hdr.Mid = GetNextMid(ses->server);
 
 	return SendReceive(xid, ses, in_buf, out_buf,
-			&bytes_returned, CIFS_STD_OP);
+			&bytes_returned, CIFS_STD_OP, tcon->retry);
 }
 
 int