[CIFS] Do not time out posix brl requests when using new posix setfileinfo
request and do not time out slow requests to a server that is still responding
well to other threads

Suggested by jra of Samba team

Signed-off-by: Steve French <sfrench@us.ibm.com>
(cherry picked from 89b57148115479eef074b8d3f86c4c86c96ac969 commit)
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index a61d17e..acb843b 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,9 @@
+Version 1.45
+------------
+Do not time out lockw calls when using posix extensions. Do not
+time out requests if server still responding reasonably fast
+on requests on other threads
+
 Version 1.44
 ------------
 Rewritten sessionsetup support, including support for legacy SMB
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index c28ede5..3cd7500 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -402,7 +402,6 @@
 };
 #endif
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
 {
 	struct cifs_sb_info *cifs_sb;
@@ -422,7 +421,7 @@
 		tcon->tidStatus = CifsExiting;
 	up(&tcon->tconSem);
 
-	/* cancel_brl_requests(tcon); */
+	/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
 	/* cancel_notify_requests(tcon); */
 	if(tcon->ses && tcon->ses->server)
 	{
@@ -438,7 +437,6 @@
 
 	return;
 }
-#endif	
 
 static int cifs_remount(struct super_block *sb, int *flags, char *data)
 {
@@ -457,9 +455,7 @@
    unless later we add lazy close of inodes or unless the kernel forgets to call
    us with the same number of releases (closes) as opens */
 	.show_options = cifs_show_options,
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 	.umount_begin   = cifs_umount_begin,
-#endif
 	.remount_fs = cifs_remount,
 };
 
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 8f75c6f..39ee8ef 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -100,5 +100,5 @@
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
 		       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.44"
+#define CIFS_VERSION   "1.45"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 6d7cf5f..39b43e6 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -158,7 +158,8 @@
 	/* 16th byte of RFC1001 workstation name is always null */
 	char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
 	__u32 sequence_number; /* needed for CIFS PDU signature */
-	char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; 
+	char mac_signing_key[CIFS_SESS_KEY_SIZE + 16];
+	unsigned long lstrp; /* when we got last response from this server */
 };
 
 /*
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 19678c5..c03c42e 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1484,6 +1484,7 @@
 	char *data_offset;
 	struct cifs_posix_lock *parm_data;
 	int rc = 0;
+	int timeout = 0;
 	int bytes_returned = 0;
 	__u16 params, param_offset, offset, byte_count, count;
 
@@ -1503,7 +1504,6 @@
 	pSMB->MaxSetupCount = 0;
 	pSMB->Reserved = 0;
 	pSMB->Flags = 0;
-	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
 	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
 	offset = param_offset + params;
@@ -1529,8 +1529,13 @@
 			(((char *) &pSMB->hdr.Protocol) + offset);
 
 	parm_data->lock_type = cpu_to_le16(lock_type);
-	if(waitFlag)
+	if(waitFlag) {
+		timeout = 3;  /* blocking operation, no timeout */
 		parm_data->lock_flags = cpu_to_le16(1);
+		pSMB->Timeout = cpu_to_le32(-1);
+	} else
+		pSMB->Timeout = 0;
+
 	parm_data->pid = cpu_to_le32(current->tgid);
 	parm_data->start = cpu_to_le64(pLockData->fl_start);
 	parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
@@ -1542,7 +1547,7 @@
 	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, timeout);
 	if (rc) {
 		cFYI(1, ("Send error in Posix Lock = %d", rc));
 	} else if (get_flag) {
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 876eb9e..c4aedcf 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -612,6 +612,10 @@
 #ifdef CONFIG_CIFS_STATS2
 				mid_entry->when_received = jiffies;
 #endif
+				/* so we do not time out requests to  server
+				which is still responding (since server could
+				be busy but not dead) */
+				server->lstrp = jiffies;
 				break;
 			}
 		}
@@ -1969,7 +1973,18 @@
 				}
 					
 				cFYI(1,("Negotiate caps 0x%x",(int)cap));
-
+#ifdef CONFIG_CIFS_DEBUG2
+				if(cap & CIFS_UNIX_FCNTL_CAP)
+					cFYI(1,("FCNTL cap"));
+				if(cap & CIFS_UNIX_EXTATTR_CAP)
+					cFYI(1,("EXTATTR cap"));
+				if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
+					cFYI(1,("POSIX path cap"));
+				if(cap & CIFS_UNIX_XATTR_CAP)
+					cFYI(1,("XATTR cap"));
+				if(cap & CIFS_UNIX_POSIX_ACL_CAP)
+					cFYI(1,("POSIX ACL cap"));
+#endif /* CIFS_DEBUG2 */
 				if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
 					cFYI(1,("setting capabilities failed"));
 				}
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 944d2b9..52e2e4c 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -644,8 +644,7 @@
 	account for negative length which we can not accept over the
 	wire */
 	if (IS_GETLK(cmd)) {
-		if(experimEnabled && 
-		   (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
+		if((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
 		   (CIFS_UNIX_FCNTL_CAP & 
 			le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
 			int posix_lock_type;
@@ -683,8 +682,7 @@
 		FreeXid(xid);
 		return rc;
 	}
-	if (experimEnabled &&
-		(cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
+	if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
 		(CIFS_UNIX_FCNTL_CAP &
 			 le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
 		int posix_lock_type;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 17ba329..95e23ca 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -444,8 +444,9 @@
 	if(timeout != MAX_SCHEDULE_TIMEOUT) {
 		timeout += jiffies;
 		wait_event(ses->server->response_q,
-			(!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
-			time_after(jiffies, timeout) || 
+			(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
+			(time_after(jiffies, timeout) &&
+				time_after(jiffies, ses->server->lstrp + HZ)) ||
 			((ses->server->tcpStatus != CifsGood) &&
 			 (ses->server->tcpStatus != CifsNew)));
 	} else {
@@ -710,9 +711,18 @@
 	/* No user interrupts in wait - wreaks havoc with performance */
 	if(timeout != MAX_SCHEDULE_TIMEOUT) {
 		timeout += jiffies;
+		/* although we prefer not to time out if the server is still
+		responding - we will time out if the server takes
+		more than 15 (or 45 or 180) seconds to respond to this request
+		and has not responded to any request from other threads
+		on this client within a second (note that it is not worth
+		grabbing the GlobalMid_Lock and slowing things down in this
+		wait event to more accurately check the lstrsp field on some 
+		arch since we are already in an error path that will retry */
 		wait_event(ses->server->response_q,
 			(!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
-			time_after(jiffies, timeout) || 
+			(time_after(jiffies, timeout) &&
+				time_after(jiffies, ses->server->lstrp + HZ)) ||
 			((ses->server->tcpStatus != CifsGood) &&
 			 (ses->server->tcpStatus != CifsNew)));
 	} else {