From 36358c21423d58dde90aedde2b8517192c4092f4 Mon Sep 17 00:00:00 2001
From: Alexey Dobriyan <adobriyan@mail.ru>
Date: Thu, 2 Jun 2005 20:01:16 -0500
Subject: [CIFS] fs/cifs/netmisc.c: fix sparse warning

Signed-off-by: Steve French <sfrench@us.ibm.com>
Signed-off-by: Alexey Dobriyan <adobriyan@mail.ru>
Signed-off-by: Domen Puncer <domen@coderock.org>
---
 fs/cifs/netmisc.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index a92af41d4411..873b812c0f40 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -133,7 +133,6 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
 int
 cifs_inet_pton(int address_family, char *cp,void *dst)
 {
-	struct in_addr address;
 	int value;
 	int digit;
 	int i;
@@ -190,8 +189,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst)
 	if (value > addr_class_max[end - bytes])
 		return 0;
 
-	address.s_addr = *((__be32 *) bytes) | htonl(value);
-	*((__be32 *)dst) = address.s_addr;
+	*((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
 	return 1; /* success */
 }
 
-- 
cgit v1.2.3


From d6e04ae64c6b06ef76a5d4fb49106b393b7fa50a Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 13 Jun 2005 13:24:43 -0500
Subject: [CIFS] CIFS writepage improvements - eliminate double copy

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifsproto.h |   6 +-
 fs/cifs/cifssmb.c   |  57 +++++++++-----
 fs/cifs/file.c      |  21 ++++-
 fs/cifs/transport.c | 223 ++++++++++++++++++++++++++++++++++++++++------------
 4 files changed, 231 insertions(+), 76 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index ea239dea571e..b43ac9230eab 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -47,6 +47,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
 			struct smb_hdr * /* input */ ,
 			struct smb_hdr * /* out */ ,
 			int * /* bytes returned */ , const int long_op);
+extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
+			struct smb_hdr * /* input */ , int hdr_len,
+			const char * /* SMB data to send */ , int data_len,
+			int * /* bytes returned */ , const int long_op);
 extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
 extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
 extern int is_valid_oplock_break(struct smb_hdr *smb);
@@ -222,7 +226,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 			const int netfid, const unsigned int count,
 			const __u64 offset, unsigned int *nbytes, 
-			const char __user *buf,const int long_op);
+			const char *buf,const int long_op);
 extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName, __u64 * inode_number,
 			const struct nls_table *nls_codepage, 
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 3c628bf667a5..b4f7b9859e3b 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -951,56 +951,69 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 }
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
+int
+CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 	     const int netfid, const unsigned int count,
-	     const __u64 offset, unsigned int *nbytes, const char __user *buf,
+	     const __u64 offset, unsigned int *nbytes, const char *buf,
 	     const int long_op)
 {
 	int rc = -EACCES;
 	WRITE_REQ *pSMB = NULL;
-	WRITE_RSP *pSMBr = NULL;
-	/*int bytes_returned;*/
-	unsigned bytes_sent;
+	int bytes_returned;
+	int smb_hdr_len;
+	__u32 bytes_sent;
 	__u16 byte_count;
 
+	cERROR(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
 	rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
-    
 	if (rc)
 		return rc;
-	
-	pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
-
 	/* tcon and ses pointer are checked in smb_init */
 	if (tcon->ses->server == NULL)
 		return -ECONNABORTED;
 
-	pSMB->AndXCommand = 0xFF; /* none */
+	pSMB->AndXCommand = 0xFF;	/* none */
 	pSMB->Fid = netfid;
 	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
 	pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
 	pSMB->Reserved = 0xFFFFFFFF;
 	pSMB->WriteMode = 0;
 	pSMB->Remaining = 0;
-	bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
+
+	/* Can increase buffer size if buffer is big enough in some cases - ie 
+	can send more if LARGE_WRITE_X capability returned by the server and if
+	our buffer is big enough or if we convert to iovecs on socket writes
+	and eliminate the copy to the CIFS buffer */
+	if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
+		bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
+	} else {
+		bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
+			 & ~0xFF;
+	}
+
 	if (bytes_sent > count)
 		bytes_sent = count;
-	pSMB->DataLengthHigh = 0;
 	pSMB->DataOffset =
 	    cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
 
-	byte_count = bytes_sent + 1 /* pad */ ;
-	pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
-	pSMB->DataLengthHigh = 0;
-	pSMB->hdr.smb_buf_length += byte_count;
+	byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
+	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
+	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
+	smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
+	pSMB->hdr.smb_buf_length += bytes_sent+1;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
-/*	rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */  /* BB fixme BB */
+	rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
+			  buf, bytes_sent, &bytes_returned, long_op);
 	if (rc) {
-		cFYI(1, ("Send error in write2 (large write) = %d", rc));
+		cFYI(1, ("Send error in write = %d", rc));
 		*nbytes = 0;
-	} else
-		*nbytes = le16_to_cpu(pSMBr->Count);
+	} else {
+		WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
+		*nbytes = le16_to_cpu(pSMBr->CountHigh);
+		*nbytes = (*nbytes) << 16;
+		*nbytes += le16_to_cpu(pSMBr->Count);
+	}
 
 	cifs_small_buf_release(pSMB);
 
@@ -1009,6 +1022,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 
 	return rc;
 }
+
+
 #endif /* CIFS_EXPERIMENTAL */
 
 int
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index dde2d251fc3d..ca74c1151be9 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -791,9 +791,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 
 	pTcon = cifs_sb->tcon;
 
-	/* cFYI(1,
-	   (" write %d bytes to offset %lld of %s", write_size,
-	   *poffset, file->f_dentry->d_name.name)); */
+	cFYI(1,(" write %d bytes to offset %lld of %s", write_size,
+	   *poffset, file->f_dentry->d_name.name)); /* BB removeme BB */
 
 	if (file->private_data == NULL)
 		return -EBADF;
@@ -846,7 +845,21 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 				if (rc != 0)
 					break;
 			}
-
+#ifdef CIFS_EXPERIMENTAL
+			/* BB FIXME We can not sign across two buffers yet */
+			cERROR(1,("checking signing")); /* BB removeme BB */
+			if(pTcon->ses->server->secMode & 
+			   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED) == 0)
+				rc = CIFSSMBWrite2(xid, pTcon,
+						open_file->netfid,
+						min_t(const int, cifs_sb->wsize,
+						    write_size - total_written),
+						*poffset, &bytes_written,
+						write_data + total_written, 
+						long_op);
+			} else
+			/* BB FIXME fixup indentation of line below */
+#endif			
 			rc = CIFSSMBWrite(xid, pTcon,
 				 open_file->netfid,
 				 min_t(const int, cifs_sb->wsize, 
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 0046c219833d..04f4af07fdd4 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -49,7 +49,8 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
 		return NULL;
 	}
 	
-	temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS);
+	temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
+						    SLAB_KERNEL | SLAB_NOFS);
 	if (temp == NULL)
 		return temp;
 	else {
@@ -179,27 +180,24 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
 	return rc;
 }
 
-#ifdef CIFS_EXPERIMENTAL
-/* BB finish off this function, adding support for writing set of pages as iovec */
-/* and also adding support for operations that need to parse the response smb    */
-
-int
-smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
-	 unsigned int smb_buf_length, struct kvec * write_vector 
-	  /* page list */, struct sockaddr *sin)
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+static int
+smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
+	 unsigned int smb_hdr_length, const char * data, unsigned int datalen,
+	 struct sockaddr *sin)
 {
 	int rc = 0;
 	int i = 0;
 	struct msghdr smb_msg;
-	number_of_pages += 1; /* account for SMB header */
-	struct kvec * piov  = kmalloc(number_of_pages * sizeof(struct kvec));
-	unsigned len = smb_buf_length + 4;
-
+	struct kvec iov[2];
+	unsigned len = smb_hdr_length + 4;
+	
 	if(ssocket == NULL)
 		return -ENOTSOCK; /* BB eventually add reconnect code here */
-	iov.iov_base = smb_buffer;
-	iov.iov_len = len;
-
+	iov[0].iov_base = smb_buffer;
+	iov[0].iov_len = len;
+	iov[1].iov_base = data;
+	iov[2].iov_len = datalen;
 	smb_msg.msg_name = sin;
 	smb_msg.msg_namelen = sizeof (struct sockaddr);
 	smb_msg.msg_control = NULL;
@@ -212,12 +210,11 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
 	   Flags2 is converted in SendReceive */
 
 	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
-	cFYI(1, ("Sending smb of length %d ", smb_buf_length));
+	cFYI(1, ("Sending smb of length %d ", len + datalen));
 	dump_smb(smb_buffer, len);
 
-	while (len > 0) {
-		rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, 
-				    len);
+	while (len + datalen > 0) {
+		rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len);
 		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
 			i++;
 			if(i > 60) {
@@ -232,9 +229,22 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
 		}
 		if (rc < 0) 
 			break;
-		iov.iov_base += rc;
-		iov.iov_len -= rc;
-		len -= rc;
+		if(iov[0].iov_len > 0) {
+			if(rc >= len) {
+				iov[0].iov_len = 0;
+				rc -= len;
+			} else {  /* some of hdr was not sent */
+				len -= rc;
+				iov[0].iov_len -= rc;
+				iov[0].iov_base += rc;
+				continue;
+			}
+		}
+		if((iov[0].iov_len == 0) && (rc > 0)){
+			iov[1].iov_base += rc;
+			iov[1].iov_len -= rc;
+			datalen -= rc;
+		}
 	}
 
 	if (rc < 0) {
@@ -246,14 +256,15 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
 	return rc;
 }
 
-
 int
-CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
-	    struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op)
+SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
+	     struct smb_hdr *in_buf, int hdrlen, const char * data,
+	     int datalen, int *pbytes_returned, const int long_op)
 {
 	int rc = 0;
-	unsigned long timeout = 15 * HZ;
-	struct mid_q_entry *midQ = NULL;
+	unsigned int receive_len;
+	unsigned long timeout;
+	struct mid_q_entry *midQ;
 
 	if (ses == NULL) {
 		cERROR(1,("Null smb session"));
@@ -263,14 +274,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
 		cERROR(1,("Null tcp session"));
 		return -EIO;
 	}
-	if(pbytes_returned == NULL)
-		return -EIO;
-	else
-		*pbytes_returned = 0;
 
-  
-
-	if(ses->server->tcpStatus == CIFS_EXITING)
+	if(ses->server->tcpStatus == CifsExiting)
 		return -ENOENT;
 
 	/* Ensure that we do not send more than 50 overlapping requests 
@@ -282,7 +287,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
 	} else {
 		spin_lock(&GlobalMid_Lock); 
 		while(1) {        
-			if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){
+			if(atomic_read(&ses->server->inFlight) >= 
+					cifs_max_pending){
 				spin_unlock(&GlobalMid_Lock);
 				wait_event(ses->server->request_q,
 					atomic_read(&ses->server->inFlight)
@@ -314,17 +320,17 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
 
 	if (ses->server->tcpStatus == CifsExiting) {
 		rc = -ENOENT;
-		goto cifs_out_label;
+		goto out_unlock2;
 	} else if (ses->server->tcpStatus == CifsNeedReconnect) {
 		cFYI(1,("tcp session dead - return to caller to retry"));
 		rc = -EAGAIN;
-		goto cifs_out_label;
+		goto out_unlock2;
 	} else if (ses->status != CifsGood) {
 		/* check if SMB session is bad because we are setting it up */
 		if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
 			(in_buf->Command != SMB_COM_NEGOTIATE)) {
 			rc = -EAGAIN;
-			goto cifs_out_label;
+			goto out_unlock2;
 		} /* else ok - we are setting up session */
 	}
 	midQ = AllocMidQEntry(in_buf, ses);
@@ -352,13 +358,12 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
 		return -EIO;
 	}
 
-	/* BB can we sign efficiently in this path? */
-	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
+/* BB FIXME */
+/* 	rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
-/*	rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
-		       piovec, 
-		       (struct sockaddr *) &(ses->server->addr.sockAddr));*/
+	rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen,
+		      (struct sockaddr *) &(ses->server->addr.sockAddr));
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
 		up(&ses->server->tcpSem);
@@ -370,19 +375,137 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
 		return rc;
 	} else
 		up(&ses->server->tcpSem);
-cifs_out_label:
-	if(midQ)
-	        DeleteMidQEntry(midQ);
-                                                                                                                           
+	if (long_op == -1)
+		goto cifs_no_response_exit2;
+	else if (long_op == 2) /* writes past end of file can take loong time */
+		timeout = 300 * HZ;
+	else if (long_op == 1)
+		timeout = 45 * HZ; /* should be greater than 
+			servers oplock break timeout (about 43 seconds) */
+	else if (long_op > 2) {
+		timeout = MAX_SCHEDULE_TIMEOUT;
+	} else
+		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 */
+	if (signal_pending(current)) {
+		/* if signal pending do not hold up user for full smb timeout
+		but we still give response a change to complete */
+		timeout = 2 * HZ;
+	}   
+
+	/* No user interrupts in wait - wreaks havoc with performance */
+	if(timeout != MAX_SCHEDULE_TIMEOUT) {
+		timeout += jiffies;
+		wait_event(ses->server->response_q,
+			(!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
+			time_after(jiffies, timeout) || 
+			((ses->server->tcpStatus != CifsGood) &&
+			 (ses->server->tcpStatus != CifsNew)));
+	} else {
+		wait_event(ses->server->response_q,
+			(!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
+			((ses->server->tcpStatus != CifsGood) &&
+			 (ses->server->tcpStatus != CifsNew)));
+	}
+
+	spin_lock(&GlobalMid_Lock);
+	if (midQ->resp_buf) {
+		spin_unlock(&GlobalMid_Lock);
+		receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
+	} else {
+		cERROR(1,("No response buffer"));
+		if(midQ->midState == MID_REQUEST_SUBMITTED) {
+			if(ses->server->tcpStatus == CifsExiting)
+				rc = -EHOSTDOWN;
+			else {
+				ses->server->tcpStatus = CifsNeedReconnect;
+				midQ->midState = MID_RETRY_NEEDED;
+			}
+		}
+
+		if (rc != -EHOSTDOWN) {
+			if(midQ->midState == MID_RETRY_NEEDED) {
+				rc = -EAGAIN;
+				cFYI(1,("marking request for retry"));
+			} else {
+				rc = -EIO;
+			}
+		}
+		spin_unlock(&GlobalMid_Lock);
+		DeleteMidQEntry(midQ);
+		/* If not lock req, update # of requests on wire to server */
+		if(long_op < 3) {
+			atomic_dec(&ses->server->inFlight); 
+			wake_up(&ses->server->request_q);
+		}
+		return rc;
+	}
+  
+	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
+		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
+			receive_len, xid));
+		rc = -EIO;
+	} else {		/* rcvd frame is ok */
+
+		if (midQ->resp_buf && 
+			(midQ->midState == MID_RESPONSE_RECEIVED)) {
+			in_buf->smb_buf_length = receive_len;
+			/* BB verify that length would not overrun small buf */
+			memcpy((char *)in_buf + 4,
+			       (char *)midQ->resp_buf + 4,
+			       receive_len);
+
+			dump_smb(in_buf, 80);
+			/* convert the length into a more usable form */
+			if((receive_len > 24) &&
+			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+					SECMODE_SIGN_ENABLED))) {
+				rc = cifs_verify_signature(in_buf,
+						ses->server->mac_signing_key,
+						midQ->sequence_number+1);
+				if(rc) {
+					cERROR(1,("Unexpected SMB signature"));
+					/* BB FIXME add code to kill session */
+				}
+			}
+
+			*pbytes_returned = in_buf->smb_buf_length;
+
+			/* BB special case reconnect tid and uid here? */
+			rc = map_smb_to_linux_error(in_buf);
+
+			/* convert ByteCount if necessary */
+			if (receive_len >=
+			    sizeof (struct smb_hdr) -
+			    4 /* do not count RFC1001 header */  +
+			    (2 * in_buf->WordCount) + 2 /* bcc */ )
+				BCC(in_buf) = le16_to_cpu(BCC(in_buf));
+		} else {
+			rc = -EIO;
+			cFYI(1,("Bad MID state? "));
+		}
+	}
+cifs_no_response_exit2:
+	DeleteMidQEntry(midQ);
+
 	if(long_op < 3) {
-		atomic_dec(&ses->server->inFlight);
+		atomic_dec(&ses->server->inFlight); 
 		wake_up(&ses->server->request_q);
 	}
 
 	return rc;
-}
 
+out_unlock2:
+	up(&ses->server->tcpSem);
+	/* If not lock req, update # of requests on wire to server */
+	if(long_op < 3) {
+		atomic_dec(&ses->server->inFlight); 
+		wake_up(&ses->server->request_q);
+	}
 
+	return rc;
+}
 #endif /* CIFS_EXPERIMENTAL */
 
 int
-- 
cgit v1.2.3


From dfb7533b5f157ac7135da23883e80d895227d965 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 22 Jun 2005 17:13:47 -0700
Subject: [CIFS] Add stats for findfirst, findnext, findclose

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifsglob.h |  3 +++
 fs/cifs/cifssmb.c  | 13 ++++++++++++-
 fs/cifs/readdir.c  | 16 ++++++++++------
 3 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 81babab265e1..4ed9c13fff55 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -219,6 +219,9 @@ struct cifsTconInfo {
 	atomic_t num_rmdirs;
 	atomic_t num_renames;
 	atomic_t num_t2renames;
+	atomic_t num_ffirst;
+	atomic_t num_fnext;
+	atomic_t num_fclose;
 	__u64    bytes_read;
 	__u64    bytes_written;
 	spinlock_t stat_lock;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 3c628bf667a5..b31158a2643d 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2396,7 +2396,9 @@ findUniqueRetry:
 	if (rc) {
 		cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
 	} else {		/* decode response */
-
+#ifdef CONFIG_CIFS_STATS
+		atomic_inc(&tcon->num_ffirst);
+#endif
 		/* BB fill in */
 	}
 
@@ -2509,6 +2511,9 @@ findFirstRetry:
 		if (rc == -EAGAIN)
 			goto findFirstRetry;
 	} else { /* decode response */
+#ifdef CONFIG_CIFS_STATS
+		atomic_inc(&tcon->num_ffirst);
+#endif
 		/* BB remember to free buffer if error BB */
 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 		if(rc == 0) {
@@ -2622,6 +2627,9 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 		} else
 			cFYI(1, ("FindNext returned = %d", rc));
 	} else {                /* decode response */
+#ifdef CONFIG_CIFS_STATS
+		atomic_inc(&tcon->num_fnext);
+#endif
 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 		
 		if(rc == 0) {
@@ -2691,6 +2699,9 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
 	if (rc) {
 		cERROR(1, ("Send error in FindClose = %d", rc));
 	}
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_fclose);
+#endif
 	cifs_small_buf_release(pSMB);
 
 	/* Since session is dead, search handle closed on server already */
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 22557716f9af..487221eeddb7 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -190,8 +190,9 @@ static void fill_in_inode(struct inode *tmp_inode,
 		tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
 		if(isNewInode)
-			return; /* No sense invalidating pages for new inode since we
-					   have not started caching readahead file data yet */
+			return; /* No sense invalidating pages for new inode
+				   since have not started caching readahead file
+				   data yet */
 
 		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
 			(local_size == tmp_inode->i_size)) {
@@ -536,7 +537,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 	while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 
 	      (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
 	 	cFYI(1,("calling findnext2"));
-		rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf);
+		rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, 
+				  &cifsFile->srch_inf);
 		if(rc)
 			return -ENOENT;
 	}
@@ -555,7 +557,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 		cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 
 		current_entry = cifsFile->srch_inf.srch_entries_start;
 		for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
-			/* go entry to next entry figuring out which we need to start with */
+			/* go entry by entry figuring out which is first */
 			/* if( . or ..)
 				skip */
 			rc = cifs_entry_is_dot(current_entry,cifsFile);
@@ -721,7 +723,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
 			      (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
 	}
 	
-	rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type);
+	rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
+		     tmp_inode->i_ino,obj_type);
 	if(rc) {
 		cFYI(1,("filldir rc = %d",rc));
 	}
@@ -906,7 +909,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 				cifs_save_resume_key(current_entry,cifsFile);
 				break;
 			} else 
-				current_entry = nxt_dir_entry(current_entry,end_of_smb);
+				current_entry = nxt_dir_entry(current_entry,
+							      end_of_smb);
 		}
 		kfree(tmp_buf);
 		break;
-- 
cgit v1.2.3


From ac67055ef2378ea95c34b593ddf9d0a0737a240a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 22 Jun 2005 17:26:35 -0700
Subject: [CIFS] POSIX extensions, SetFSInfo added

Signed-off-by: Steve French@sfrench@us.ibm.com
Signed-off-by: Jeremy Allison (jra@samba.org)
---
 fs/cifs/cifs_fs_sb.h |  1 +
 fs/cifs/cifsglob.h   |  7 +++++
 fs/cifs/cifspdu.h    | 46 +++++++++++++++++++++++++++++++
 fs/cifs/cifsproto.h  |  7 +++--
 fs/cifs/cifssmb.c    | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/cifs/connect.c    | 20 ++++++++++++++
 fs/cifs/dir.c        | 10 +++----
 fs/cifs/fcntl.c      |  2 +-
 fs/cifs/file.c       |  4 +--
 fs/cifs/inode.c      | 14 +++++-----
 fs/cifs/link.c       | 15 +++++-----
 fs/cifs/readdir.c    |  4 +--
 fs/cifs/xattr.c      |  8 +++---
 13 files changed, 182 insertions(+), 33 deletions(-)

diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index ec00d61d5308..5dc5fe6b486d 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -24,6 +24,7 @@
 #define CIFS_MOUNT_DIRECT_IO    8 /* do not write nor read through page cache */
 #define CIFS_MOUNT_NO_XATTR  0x10 /* if set - disable xattr support */
 #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
+#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */
 
 struct cifs_sb_info {
 	struct cifsTconInfo *tcon;	/* primary mount */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 4ed9c13fff55..d3773e57acf9 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -309,6 +309,13 @@ CIFS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
+static inline const char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
+{
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+		return '/';
+	else
+		return '\\';
+}
 
 /* one of these for every pending CIFS request to the server */
 struct mid_q_entry {
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index aede6a813167..84d37f8e986e 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -59,6 +59,7 @@
 #define TRANS2_FIND_FIRST             0x01
 #define TRANS2_FIND_NEXT              0x02
 #define TRANS2_QUERY_FS_INFORMATION   0x03
+#define TRANS2_SET_FS_INFORMATION     0x04
 #define TRANS2_QUERY_PATH_INFORMATION 0x05
 #define TRANS2_SET_PATH_INFORMATION   0x06
 #define TRANS2_QUERY_FILE_INFORMATION 0x07
@@ -1411,6 +1412,43 @@ typedef struct smb_com_transaction_qfsi_rsp {
 	__u8 Pad;		/* may be three bytes *//* followed by data area */
 } TRANSACTION2_QFSI_RSP;
 
+
+/* SETFSInfo Levels */
+#define SMB_SET_CIFS_UNIX_INFO    0x200
+typedef struct smb_com_transaction2_setfsi_req {
+	struct smb_hdr hdr;	/* wct = 15 */
+	__le16 TotalParameterCount;
+	__le16 TotalDataCount;
+	__le16 MaxParameterCount;
+	__le16 MaxDataCount;
+	__u8 MaxSetupCount;
+	__u8 Reserved;
+	__le16 Flags;
+	__le32 Timeout;
+	__u16 Reserved2;
+	__le16 ParameterCount;	/* 4 */
+	__le16 ParameterOffset;
+	__le16 DataCount;	/* 12 */
+	__le16 DataOffset;
+	__u8 SetupCount;	/* one */
+	__u8 Reserved3;
+	__le16 SubCommand;	/* TRANS2_SET_FS_INFORMATION */
+	__le16 ByteCount;
+	__u8 Pad;
+	__u16 FileNum;		/* Parameters start. */
+	__le16 InformationLevel;/* Parameters end. */
+	__le16 ClientUnixMajor; /* Data start. */
+	__le16 ClientUnixMinor;
+	__le64 ClientUnixCap;   /* Data end */
+} TRANSACTION2_SETFSI_REQ;
+
+typedef struct smb_com_transaction2_setfsi_rsp {
+	struct smb_hdr hdr;	/* wct = 10 */
+	struct trans2_resp t2;
+	__u16 ByteCount;
+} TRANSACTION2_SETFSI_RSP;
+
+
 typedef struct smb_com_transaction2_get_dfs_refer_req {
 	struct smb_hdr hdr;	/* wct = 15 */
 	__le16 TotalParameterCount;
@@ -1551,12 +1589,20 @@ typedef struct {
 	__le16 MinorVersionNumber;
 	__le64 Capability;
 } FILE_SYSTEM_UNIX_INFO;	/* Unix extensions info, level 0x200 */
+
+/* Version numbers for CIFS UNIX major and minor. */
+#define CIFS_UNIX_MAJOR_VERSION 1
+#define CIFS_UNIX_MINOR_VERSION 0
+
 /* Linux/Unix extensions capability flags */
 #define CIFS_UNIX_FCNTL_CAP             0x00000001 /* support for fcntl locks */
 #define CIFS_UNIX_POSIX_ACL_CAP         0x00000002 /* support getfacl/setfacl */
 #define CIFS_UNIX_XATTR_CAP             0x00000004 /* support new namespace   */
 #define CIFS_UNIX_EXTATTR_CAP           0x00000008 /* support chattr/chflag   */
+#define CIFS_UNIX_POSIX_PATHNAMES_CAP   0x00000010 /* Use POSIX pathnames on the wire. */
+
 #define CIFS_POSIX_EXTENSIONS           0x00000010 /* support for new QFSInfo */
+
 typedef struct {
 	/* For undefined recommended transfer size return -1 in that field */
 	__le32 OptimalTransferSize;  /* bsize on some os, iosize on other os */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index ea239dea571e..db2adf0b206c 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -40,7 +40,7 @@ extern unsigned int _GetXid(void);
 extern void _FreeXid(unsigned int);
 #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid));
 #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));}
-extern char *build_path_from_dentry(struct dentry *);
+extern char *build_path_from_dentry(struct dentry *, const struct cifs_sb_info *cifs_sb);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 extern void renew_parental_timestamps(struct dentry *direntry);
 extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
@@ -89,7 +89,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 
 extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
             const char *searchName, const struct nls_table *nls_codepage,
-            __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map);
+            __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep);
 
 extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
             __u16 searchHandle, struct cifs_search_info * psrch_inf);
@@ -125,6 +125,9 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 			int remap);
 extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
 			struct kstatfs *FSData);
+extern int CIFSSMBSETFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
+			__u64 cap);
+
 extern int CIFSSMBQFSAttributeInfo(const int xid,
 			struct cifsTconInfo *tcon);
 extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index b31158a2643d..81c9d3f393f5 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2416,7 +2416,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
 	      const char *searchName, 
 	      const struct nls_table *nls_codepage,
 	      __u16 *	pnetfid,
-	      struct cifs_search_info * psrch_inf, int remap)
+	      struct cifs_search_info * psrch_inf, int remap, const char dirsep)
 {
 /* level 257 SMB_ */
 	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -2443,7 +2443,7 @@ findFirstRetry:
 		it got remapped to 0xF03A as if it were part of the
 		directory name instead of a wildcard */
 		name_len *= 2;
-		pSMB->FileName[name_len] = '\\';
+		pSMB->FileName[name_len] = dirsep;
 		pSMB->FileName[name_len+1] = 0;
 		pSMB->FileName[name_len+2] = '*';
 		pSMB->FileName[name_len+3] = 0;
@@ -2457,7 +2457,7 @@ findFirstRetry:
 		if(name_len > buffersize-header)
 			free buffer exit; BB */
 		strncpy(pSMB->FileName, searchName, name_len);
-		pSMB->FileName[name_len] = '\\';
+		pSMB->FileName[name_len] = dirsep;
 		pSMB->FileName[name_len+1] = '*';
 		pSMB->FileName[name_len+2] = 0;
 		name_len += 3;
@@ -3265,6 +3265,77 @@ QFSUnixRetry:
 	return rc;
 }
 
+int
+CIFSSMBSETFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
+{
+/* level 0x200  SMB_SET_CIFS_UNIX_INFO */
+	TRANSACTION2_SETFSI_REQ *pSMB = NULL;
+	TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, param_offset, offset, byte_count;
+
+	cFYI(1, ("In SETFSUnixInfo"));
+SETFSUnixRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 4;	/* 2 bytes zero followed by info level. */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
+	offset = param_offset + params;
+
+	pSMB->MaxParameterCount = cpu_to_le16(4);
+	pSMB->MaxDataCount = cpu_to_le16(100);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
+	byte_count = 1 /* pad */ + params + 12;
+
+	pSMB->DataCount = cpu_to_le16(12);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+
+	/* Params. */
+	pSMB->FileNum = 0;
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
+
+	/* Data. */
+	pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
+	pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
+	pSMB->ClientUnixCap = cpu_to_le64(cap);
+
+	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);
+	if (rc) {
+		cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+		if (rc) {
+			rc = -EIO;	/* bad smb */
+		}
+	}
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto SETFSUnixRetry;
+
+	return rc;
+}
+
+
 
 int
 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index e568cc47a7f9..bef5d6f30975 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -74,6 +74,7 @@ struct smb_vol {
 	unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
 	unsigned direct_io:1;
 	unsigned remap:1;   /* set to remap seven reserved chars in filenames */
+	unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
 	unsigned int rsize;
 	unsigned int wsize;
 	unsigned int sockopt;
@@ -745,6 +746,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 	/* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
 	vol->rw = TRUE;
 
+	/* default is always to request posix paths. */
+	vol->posix_paths = 1;
+
 	if (!options)
 		return 1;
 
@@ -1023,6 +1027,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 			vol->remap = 1;
 		} else if (strnicmp(data, "nomapchars", 10) == 0) {
 			vol->remap = 0;
+		} else if (strnicmp(data, "posixpaths", 10) == 0) {
+			vol->posix_paths = 1;
+		} else if (strnicmp(data, "noposixpaths", 12) == 0) {
+			vol->posix_paths = 0;
 		} else if (strnicmp(data, "setuids", 7) == 0) {
 			vol->setuids = 1;
 		} else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -1679,6 +1687,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
 		if(volume_info.no_xattr)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
+
 		if(volume_info.direct_io) {
 			cERROR(1,("mounting share using direct i/o"));
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
@@ -1781,6 +1790,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 						cFYI(1,("server negotiated posix acl support"));
 						sb->s_flags |= MS_POSIXACL;
 				}
+
+				/* Try and negotiate POSIX pathnames if we can. */
+				if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
+				    le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+					if (!CIFSSMBSETFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP, 0))  {
+						cFYI(1,("negotiated posix pathnames support"));
+						cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
+					} else {
+						cFYI(1,("posix pathnames support requested but not supported"));
+					}
+				}
 			}
 		}
 	}
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 3f3538d4a1fa..9360d8fb9ef7 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -43,7 +43,7 @@ renew_parental_timestamps(struct dentry *direntry)
 
 /* Note: caller must free return buffer */
 char *
-build_path_from_dentry(struct dentry *direntry)
+build_path_from_dentry(struct dentry *direntry, const struct cifs_sb_info *cifs_sb)
 {
 	struct dentry *temp;
 	int namelen = 0;
@@ -74,7 +74,7 @@ cifs_bp_rename_retry:
 		if (namelen < 0) {
 			break;
 		} else {
-			full_path[namelen] = '\\';
+			full_path[namelen] = CIFS_DIR_SEP(cifs_sb);
 			strncpy(full_path + namelen + 1, temp->d_name.name,
 				temp->d_name.len);
 			cFYI(0, (" name: %s ", full_path + namelen));
@@ -138,7 +138,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 	pTcon = cifs_sb->tcon;
 
 	down(&direntry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&direntry->d_sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
@@ -299,7 +299,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
 	pTcon = cifs_sb->tcon;
 
 	down(&direntry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&direntry->d_sb->s_vfs_rename_sem);
 	if(full_path == NULL)
 		rc = -ENOMEM;
@@ -360,7 +360,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
 	/* can not grab the rename sem here since it would
 	deadlock in the cases (beginning of sys_rename itself)
 	in which we already have the sb rename sem */
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	if(full_path == NULL) {
 		FreeXid(xid);
 		return ERR_PTR(-ENOMEM);
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
index 7d2a9202c39a..d47ce7f49dc3 100644
--- a/fs/cifs/fcntl.c
+++ b/fs/cifs/fcntl.c
@@ -83,7 +83,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
 	pTcon = cifs_sb->tcon;
 
 	down(&file->f_dentry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(file->f_dentry);
+	full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
 	up(&file->f_dentry->d_sb->s_vfs_rename_sem);
 
 	if(full_path == NULL) {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 30ab70ce5547..8dd11fecaaca 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -196,7 +196,7 @@ int cifs_open(struct inode *inode, struct file *file)
 	}
 
 	down(&inode->i_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(file->f_dentry);
+	full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
 	up(&inode->i_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
@@ -359,7 +359,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
    those that already have the rename sem can end up causing writepage
    to get called and if the server was down that means we end up here,
    and we can never tell if the caller already has the rename_sem */
-	full_path = build_path_from_dentry(file->f_dentry);
+	full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
 	if (full_path == NULL) {
 		up(&pCifsFile->fh_sem);
 		FreeXid(xid);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 8d336a900255..95354da606d6 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -412,7 +412,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
 	/* Unlink can be called from rename so we can not grab the sem here
 	   since we deadlock otherwise */
 /*	down(&direntry->d_sb->s_vfs_rename_sem);*/
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 /*	up(&direntry->d_sb->s_vfs_rename_sem);*/
 	if (full_path == NULL) {
 		FreeXid(xid);
@@ -556,7 +556,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 	pTcon = cifs_sb->tcon;
 
 	down(&inode->i_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&inode->i_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
@@ -627,7 +627,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 	pTcon = cifs_sb->tcon;
 
 	down(&inode->i_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&inode->i_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
@@ -680,8 +680,8 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
 
 	/* we already  have the rename sem so we do not need to grab it again
 	   here to protect the path integrity */
-	fromName = build_path_from_dentry(source_direntry);
-	toName = build_path_from_dentry(target_direntry);
+	fromName = build_path_from_dentry(source_direntry, cifs_sb_source);
+	toName = build_path_from_dentry(target_direntry, cifs_sb_target);
 	if ((fromName == NULL) || (toName == NULL)) {
 		rc = -ENOMEM;
 		goto cifs_rename_exit;
@@ -797,7 +797,7 @@ int cifs_revalidate(struct dentry *direntry)
 
 	/* can not safely grab the rename sem here if rename calls revalidate
 	   since that would deadlock */
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
@@ -946,7 +946,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 	pTcon = cifs_sb->tcon;
 
 	down(&direntry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&direntry->d_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index bde0fabfece0..214aa816f669 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -49,8 +49,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
    BB note DFS case in future though (when we may have to check) */
 
 	down(&inode->i_sb->s_vfs_rename_sem);
-	fromName = build_path_from_dentry(old_file);
-	toName = build_path_from_dentry(direntry);
+	fromName = build_path_from_dentry(old_file, cifs_sb_target);
+	toName = build_path_from_dentry(direntry, cifs_sb_target);
 	up(&inode->i_sb->s_vfs_rename_sem);
 	if((fromName == NULL) || (toName == NULL)) {
 		rc = -ENOMEM;
@@ -105,16 +105,17 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 
 	xid = GetXid();
 
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
 	down(&direntry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&direntry->d_sb->s_vfs_rename_sem);
 
 	if (!full_path)
 		goto out_no_free;
 
 	cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
-	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb->tcon;
 	target_path = kmalloc(PATH_MAX, GFP_KERNEL);
 	if (!target_path) {
 		target_path = ERR_PTR(-ENOMEM);
@@ -167,7 +168,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
 	pTcon = cifs_sb->tcon;
 
 	down(&inode->i_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&inode->i_sb->s_vfs_rename_sem);
 
 	if(full_path == NULL) {
@@ -233,7 +234,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
 /* BB would it be safe against deadlock to grab this sem 
       even though rename itself grabs the sem and calls lookup? */
 /*       down(&inode->i_sb->s_vfs_rename_sem);*/
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 /*       up(&inode->i_sb->s_vfs_rename_sem);*/
 
 	if(full_path == NULL) {
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 487221eeddb7..42310281871c 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -354,7 +354,7 @@ static int initiate_cifs_search(const int xid, struct file *file)
 		return -EINVAL;
 
 	down(&file->f_dentry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(file->f_dentry);
+	full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
 	up(&file->f_dentry->d_sb->s_vfs_rename_sem);
 
 	if(full_path == NULL) {
@@ -375,7 +375,7 @@ ffirst_retry:
 
 	rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
 		&cifsFile->netfid, &cifsFile->srch_inf,
-		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
 	if(rc == 0)
 		cifsFile->invalidHandle = FALSE;
 	if((rc == -EOPNOTSUPP) && 
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index c1e02eff1d25..f4fc8ddebba7 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -63,7 +63,7 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name)
 	pTcon = cifs_sb->tcon;
                                                                                      
 	down(&sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
@@ -118,7 +118,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
 	pTcon = cifs_sb->tcon;
 
 	down(&sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
@@ -227,7 +227,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
 	pTcon = cifs_sb->tcon;
 
 	down(&sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
@@ -328,7 +328,7 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
 	pTcon = cifs_sb->tcon;
 
 	down(&sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry);
+	full_path = build_path_from_dentry(direntry, cifs_sb);
 	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
-- 
cgit v1.2.3


From 45abc6ee2b916a235d6824a41225177bd6e5e24f Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 23 Jun 2005 13:42:03 -0500
Subject: [CIFS] Fix typo in POSIX SetFSInfo call

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifsproto.h | 2 +-
 fs/cifs/cifssmb.c   | 2 +-
 fs/cifs/connect.c   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c7b220206ce0..66eaa6b40373 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -129,7 +129,7 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 			int remap);
 extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
 			struct kstatfs *FSData);
-extern int CIFSSMBSETFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
 			__u64 cap);
 
 extern int CIFSSMBQFSAttributeInfo(const int xid,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 7d14f2414812..f3dfae7788fd 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3281,7 +3281,7 @@ QFSUnixRetry:
 }
 
 int
-CIFSSMBSETFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
+CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
 {
 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
 	TRANSACTION2_SETFSI_REQ *pSMB = NULL;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index bef5d6f30975..f6d2a7974fc1 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1794,7 +1794,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 				/* Try and negotiate POSIX pathnames if we can. */
 				if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
 				    le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-					if (!CIFSSMBSETFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP, 0))  {
+					if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP))  {
 						cFYI(1,("negotiated posix pathnames support"));
 						cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
 					} else {
-- 
cgit v1.2.3


From 0c0ff09329dafb165c0d9ac08965ddc0615020b1 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 23 Jun 2005 19:31:17 -0500
Subject: [CIFS] Performance improvement, finish up adding CIFSSMBWrite2

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifs_debug.c | 10 ++++++++--
 fs/cifs/cifssmb.c    |  2 +-
 fs/cifs/file.c       |  7 +++----
 fs/cifs/transport.c  |  6 ++++--
 4 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 4061e43471c1..838171328076 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -283,6 +283,12 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
 			atomic_read(&tcon->num_t2renames));
 		buf += item_length;
 		length += item_length;
+		item_length = sprintf(buf,"\nFindFirst: %d FNext %d FClose %d",
+			atomic_read(&tcon->num_ffirst),
+			atomic_read(&tcon->num_fnext),
+			atomic_read(&tcon->num_fclose));
+		buf += item_length;
+		length += item_length;
 	}
 	read_unlock(&GlobalSMBSeslock);
 
@@ -360,7 +366,7 @@ cifs_proc_init(void)
 	if (pde)
 		pde->write_proc = oplockEnabled_write;
 
-	pde = create_proc_read_entry("ReenableOldCifsReaddirCode", 0, proc_fs_cifs,
+	pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs,
 				quotaEnabled_read, NULL);
 	if (pde)
 		pde->write_proc = quotaEnabled_write;
@@ -419,7 +425,7 @@ cifs_proc_clean(void)
 	remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
 	remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
 	remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
-	remove_proc_entry("ReenableOldCifsReaddirCode",proc_fs_cifs);
+	remove_proc_entry("Experimental",proc_fs_cifs);
 	remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
 	remove_proc_entry("cifs", proc_root_fs);
 }
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f3dfae7788fd..56d79fd90679 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -964,7 +964,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 	__u32 bytes_sent;
 	__u16 byte_count;
 
-	cERROR(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
+	cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
 	rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
 	if (rc)
 		return rc;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index f55c0c7aeeb0..ddb25a0a63d5 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -845,11 +845,10 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 				if (rc != 0)
 					break;
 			}
-#ifdef CIFS_EXPERIMENTAL
+#ifdef CONFIG_CIFS_EXPERIMENTAL
 			/* BB FIXME We can not sign across two buffers yet */
-			cERROR(1,("checking signing")); /* BB removeme BB */
-			if(pTcon->ses->server->secMode & 
-			   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED) == 0)
+			if((experimEnabled) && ((pTcon->ses->server->secMode & 
+			 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) {
 				rc = CIFSSMBWrite2(xid, pTcon,
 						open_file->netfid,
 						min_t(const int, cifs_sb->wsize,
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 04f4af07fdd4..496a2738bbe3 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -197,7 +197,7 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
 	iov[0].iov_base = smb_buffer;
 	iov[0].iov_len = len;
 	iov[1].iov_base = data;
-	iov[2].iov_len = datalen;
+	iov[1].iov_len = datalen;
 	smb_msg.msg_name = sin;
 	smb_msg.msg_namelen = sizeof (struct sockaddr);
 	smb_msg.msg_control = NULL;
@@ -210,7 +210,8 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
 	   Flags2 is converted in SendReceive */
 
 	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
-	cFYI(1, ("Sending smb of length %d ", len + datalen));
+	cFYI(1, ("Sending smb:  hdrlen %d datalen %d",
+		 smb_hdr_length,datalen));
 	dump_smb(smb_buffer, len);
 
 	while (len + datalen > 0) {
@@ -233,6 +234,7 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
 			if(rc >= len) {
 				iov[0].iov_len = 0;
 				rc -= len;
+				len = 0;
 			} else {  /* some of hdr was not sent */
 				len -= rc;
 				iov[0].iov_len -= rc;
-- 
cgit v1.2.3


From d7245c2ccf14cde2023273c1ec246732d96e2c27 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 14 Jul 2005 18:25:12 -0500
Subject: [CIFS] Add compat with SFU (part 1) This should help the case of
 creating fifos and other special files to servers which do not support the
 Unix extensions.

Signed-off-by: Steve French (sfrench@us.ibm.com)

Thanks to Martin Koeppe for his suggestions and good analysis
---
 fs/cifs/cifs_fs_sb.h |  1 +
 fs/cifs/connect.c    |  7 +++++++
 fs/cifs/dir.c        | 12 +++++++++++-
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 5dc5fe6b486d..6b93587c490e 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -25,6 +25,7 @@
 #define CIFS_MOUNT_NO_XATTR  0x10 /* if set - disable xattr support */
 #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
 #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */
+#define CIFS_MOUNT_UNX_EMUL    0x80 /* Network compat with SFUnix emulation */
 
 struct cifs_sb_info {
 	struct cifsTconInfo *tcon;	/* primary mount */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f6d2a7974fc1..36f78596c81a 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -75,6 +75,7 @@ struct smb_vol {
 	unsigned direct_io:1;
 	unsigned remap:1;   /* set to remap seven reserved chars in filenames */
 	unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
+	unsigned sfu_emul:1;
 	unsigned int rsize;
 	unsigned int wsize;
 	unsigned int sockopt;
@@ -1027,6 +1028,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 			vol->remap = 1;
 		} else if (strnicmp(data, "nomapchars", 10) == 0) {
 			vol->remap = 0;
+                } else if (strnicmp(data, "sfu", 3) == 0) {
+                        vol->sfu_emul = 1;
+                } else if (strnicmp(data, "nosfu", 5) == 0) {
+                        vol->sfu_emul = 0;
 		} else if (strnicmp(data, "posixpaths", 10) == 0) {
 			vol->posix_paths = 1;
 		} else if (strnicmp(data, "noposixpaths", 12) == 0) {
@@ -1687,6 +1692,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
 		if(volume_info.no_xattr)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
+		if(volume_info.sfu_emul)
+			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
 
 		if(volume_info.direct_io) {
 			cERROR(1,("mounting share using direct i/o"));
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 9360d8fb9ef7..0d5e27fec92b 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -209,7 +209,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			}
 		else {
-			/* BB implement via Windows security descriptors */
+			/* BB implement mode setting via Windows security descriptors */
 			/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
 			/* could set r/o dos attribute if mode & 0222 == 0 */
 		}
@@ -326,6 +326,16 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
 			if(rc == 0)
 				d_instantiate(direntry, newinode);
 		}
+	} else {
+		if((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 
+			(special_file(mode))) {
+
+			cFYI(1,("sfu compat create special file"));
+			/*	Attributes = cpu_to_le32(ATTR_SYSTEM); 
+				rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, ...); */
+
+			/* add code here to set EAs */
+		}
 	}
 
 	kfree(full_path);
-- 
cgit v1.2.3


From f4cfd69cf349dd27e00d5cf804b57aee04e059c2 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 14 Jul 2005 18:29:02 -0500
Subject: [CIFS] Fix path name conversion for long filenames when mapchars
 mount option was specified at mount time.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/CHANGES | 6 ++++++
 fs/cifs/misc.c  | 1 +
 2 files changed, 7 insertions(+)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index dab4774ee7bb..3196d4c4eed3 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,9 @@
+Version 1.35
+------------
+Add writepage performance improvements.  Fix path name conversions
+for long filenames on mounts which were done with "mapchars" mount option
+specified.
+
 Version 1.34
 ------------
 Fix error mapping of the TOO_MANY_LINKS (hardlinks) case.
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 072b4ee8c53e..20ae4153f791 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -611,6 +611,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
 		src_char = source[i];
 		switch (src_char) {
 			case 0:
+				target[j] = 0;
 				goto ctoUCS_out;
 			case ':':
 				target[j] = cpu_to_le16(UNI_COLON);
-- 
cgit v1.2.3


From eda3c029899cbf435d76fea43b7e1404439ccec9 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 21 Jul 2005 15:20:28 -0700
Subject: [CIFS] Add compat with SFU (part 2)

Creating FIFOs to non-Unix servers (with cifs mounts for which sfu option
was specified) now works.

Signed-off-by: Steve French (sfrench@us.ibm.com)

Thanks to Martin Koeppe for his assistance
---
 fs/cifs/cifspdu.h | 10 +++++++++-
 fs/cifs/cifssmb.c | 10 ++++++++--
 fs/cifs/dir.c     | 34 ++++++++++++++++++++++++++++++----
 fs/cifs/inode.c   | 10 ++++++++++
 fs/cifs/readdir.c |  7 +++++++
 5 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 84d37f8e986e..3cef57b7a34f 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -268,10 +268,18 @@
 /* CreateOptions */
 #define CREATE_NOT_FILE		0x00000001	/* if set must not be file */
 #define CREATE_WRITE_THROUGH	0x00000002
-#define CREATE_NOT_DIR		0x00000040	/* if set must not be directory */
+#define CREATE_SEQUENTIAL       0x00000004
+#define CREATE_SYNC_ALERT       0x00000010
+#define CREATE_ASYNC_ALERT      0x00000020
+#define CREATE_NOT_DIR		0x00000040    /* if set must not be directory */
+#define CREATE_NO_EA_KNOWLEDGE  0x00000200
+#define CREATE_EIGHT_DOT_THREE  0x00000400
 #define CREATE_RANDOM_ACCESS	0x00000800
 #define CREATE_DELETE_ON_CLOSE	0x00001000
+#define CREATE_OPEN_BY_ID       0x00002000
 #define OPEN_REPARSE_POINT	0x00200000
+#define CREATE_OPTIONS_MASK     0x007FFFFF 
+#define CREATE_OPTION_SPECIAL   0x20000000   /* system. NB not sent over wire */
 
 /* ImpersonationLevel flags */
 #define SECURITY_ANONYMOUS      0
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 56d79fd90679..fbe651858c88 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -738,7 +738,13 @@ openRetry:
 	}
 	pSMB->DesiredAccess = cpu_to_le32(access_flags);
 	pSMB->AllocationSize = 0;
-	pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
+	/* set file as system file if special file such
+	   as fifo and server expecting SFU style and
+	   no Unix extensions */
+	if(create_options & CREATE_OPTION_SPECIAL)
+		pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
+	else
+		pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
 	/* XP does not handle ATTR_POSIX_SEMANTICS */
 	/* but it helps speed up case sensitive checks for other
 	servers such as Samba */
@@ -752,7 +758,7 @@ openRetry:
 		being created */
 	pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
 	pSMB->CreateDisposition = cpu_to_le32(openDisposition);
-	pSMB->CreateOptions = cpu_to_le32(create_options);
+	pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
 	/* BB Expirement with various impersonation levels and verify */
 	pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
 	pSMB->SecurityFlags =
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 0d5e27fec92b..c0f20fc09290 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -327,13 +327,39 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
 				d_instantiate(direntry, newinode);
 		}
 	} else {
-		if((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 
-			(special_file(mode))) {
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+			int oplock = 0;
+			u16 fileHandle;
+			FILE_ALL_INFO * buf;
 
 			cFYI(1,("sfu compat create special file"));
-			/*	Attributes = cpu_to_le32(ATTR_SYSTEM); 
-				rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, ...); */
 
+			buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
+			if(buf == NULL) {
+				kfree(full_path);
+				FreeXid(xid);
+				return -ENOMEM;
+			}
+
+			rc = CIFSSMBOpen(xid, pTcon, full_path,
+					 FILE_CREATE, /* fail if exists */
+					 GENERIC_WRITE /* BB would 
+					  WRITE_OWNER | WRITE_DAC be better? */,
+					 /* Create a file and set the
+					    file attribute to SYSTEM */
+					 CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
+					 &fileHandle, &oplock, buf,
+					 cifs_sb->local_nls,
+					 cifs_sb->mnt_cifs_flags & 
+					    CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+			if(!rc) {
+				/* BB Do not bother to decode buf since no
+				   local inode yet to put timestamps in */
+				CIFSSMBClose(xid, pTcon, fileHandle);
+				d_drop(direntry);
+			}
+			kfree(buf);
 			/* add code here to set EAs */
 		}
 	}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 95354da606d6..628aa1a9fe64 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -320,6 +320,16 @@ int cifs_get_inode_info(struct inode **pinode,
 		   on dirs */
 			inode->i_mode = cifs_sb->mnt_dir_mode;
 			inode->i_mode |= S_IFDIR;
+		} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
+			   (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
+			   /* No need to le64 convert size of zero */
+			   (pfindData->EndOfFile == 0)) {
+			inode->i_mode = cifs_sb->mnt_file_mode;
+			inode->i_mode |= S_IFIFO;
+/* BB Finish for SFU style symlinks and devies */
+/*		} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
+			   (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */
+
 		} else {
 			inode->i_mode |= S_IFREG;
 			/* treat the dos attribute of read-only as read-only
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 42310281871c..dec3c9dd04d7 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -148,6 +148,13 @@ static void fill_in_inode(struct inode *tmp_inode,
 			tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
 		}
 		tmp_inode->i_mode |= S_IFDIR;
+	} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 
+		   (attr & ATTR_SYSTEM) && (end_of_file == 0)) {
+		*pobject_type = DT_FIFO;
+		tmp_inode->i_mode |= S_IFIFO;
+/* BB Finish for SFU style symlinks and devies */
+/*	} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
+		(attr & ATTR_SYSTEM) && ) { */
 /* we no longer mark these because we could not follow them */
 /*        } else if (attr & ATTR_REPARSE) {
                 *pobject_type = DT_LNK;
-- 
cgit v1.2.3


From ef6724e32142c2d9ca252d423cacc435c142734e Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 2 Aug 2005 21:31:05 -0700
Subject: [CIFS] Fix missing entries in search results when very long file
 names and more than 50 (or so) of such long search entries in the directory. 
 FindNext could send corrupt last byte of resume name when resume key was a
 few hundred bytes long file name or longer.

Fixes Samba Bug # 2932

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifssmb.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index fbe651858c88..e555cb5cf493 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2628,6 +2628,9 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 	if(name_len < PATH_MAX) {
 		memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
 		byte_count += name_len;
+		/* 14 byte parm len above enough for 2 byte null terminator */
+		pSMB->ResumeFileName[name_len] = 0;
+		pSMB->ResumeFileName[name_len+1] = 0;
 	} else {
 		rc = -EINVAL;
 		goto FNext2_err_exit;
-- 
cgit v1.2.3


From 4a6d87f1db06c9670251d6c72a89319e7d1cbaee Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Sat, 13 Aug 2005 08:15:54 -0700
Subject: [CIFS] Add missing check for path name allocation failure.  Remove
 four redundant null pointer checks before cifs_buf_release.

Found by coverity analyzer.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifssmb.c | 24 +++++++++++-------------
 fs/cifs/dir.c     |  6 +++---
 2 files changed, 14 insertions(+), 16 deletions(-)

diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index e555cb5cf493..459320222cf7 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -415,15 +415,16 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 			if(server->secMode & SECMODE_SIGN_REQUIRED)
 				cERROR(1,
 				 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
-			server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+			server->secMode &= ~(SECMODE_SIGN_ENABLED | 
+							SECMODE_SIGN_REQUIRED);
 		} else if(sign_CIFS_PDUs == 1) {
 			if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
-				server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+				server->secMode &= ~(SECMODE_SIGN_ENABLED |
+							 SECMODE_SIGN_REQUIRED);
 		}
 				
 	}
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 	return rc;
 }
 
@@ -537,9 +538,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
 			rc = -ESHUTDOWN;
 		}
 	}
-	if (pSMB)
-		cifs_small_buf_release(pSMB);
-	up(&ses->sesSem);
+	up(&ses->sesSem)	
+	cifs_small_buf_release(pSMB);
 
 	/* if session dead then we do not need to do ulogoff,
 		since server closed smb session, no sense reporting 
@@ -1796,8 +1796,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
 		}
 	}
 qreparse_out:
-	if (pSMB)
-		cifs_buf_release(pSMB);
+	cifs_buf_release(pSMB);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls
 		since file handle passed in no longer valid */
@@ -2520,12 +2519,11 @@ findFirstRetry:
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 
-	if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
+	if (rc) {/* BB add logic to retry regular search if Unix search 
+			rejected unexpectedly by server */
 		/* BB Add code to handle unsupported level rc */
 		cFYI(1, ("Error in FindFirst = %d", rc));
-
-		if (pSMB)
-			cifs_buf_release(pSMB);
+		cifs_buf_release(pSMB);
 
 		/* BB eventually could optimize out free and realloc of buf */
 		/*    for this case */
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index c0f20fc09290..c619d45060ce 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -226,7 +226,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 		}
 
 		if (rc != 0) {
-			cFYI(1,("Create worked but get_inode_info failed with rc = %d",
+			cFYI(1,
+			     ("Create worked but get_inode_info failed rc = %d",
 			      rc));
 		} else {
 			direntry->d_op = &cifs_dentry_ops;
@@ -303,8 +304,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
 	up(&direntry->d_sb->s_vfs_rename_sem);
 	if(full_path == NULL)
 		rc = -ENOMEM;
-	
-	if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
+	else if (pTcon->ses->capabilities & CAP_UNIX) {
 		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 			rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
 				mode,(__u64)current->euid,(__u64)current->egid,
-- 
cgit v1.2.3


From a59c658607b63ec7b6c2536597a075ee307b1b4c Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 17 Aug 2005 12:12:19 -0700
Subject: [CIFS] Missing ; from previous fix. Pointed out by Shaggy.

Signed-off-by: Steve French
---
 fs/cifs/cifssmb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 459320222cf7..1b073546f5d9 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -538,7 +538,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
 			rc = -ESHUTDOWN;
 		}
 	}
-	up(&ses->sesSem)	
+	up(&ses->sesSem);
 	cifs_small_buf_release(pSMB);
 
 	/* if session dead then we do not need to do ulogoff,
-- 
cgit v1.2.3


From 1982c344f1bf08118f7c224958b30c64e162009e Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 17 Aug 2005 12:38:22 -0700
Subject: [CIFS] Ensure that cifs multiplex ids do not collide.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifsglob.h  |  1 +
 fs/cifs/cifspdu.h   | 19 ++++++------
 fs/cifs/cifsproto.h |  6 ++--
 fs/cifs/cifssmb.c   | 23 +++++++++------
 fs/cifs/connect.c   |  9 ++++++
 fs/cifs/misc.c      | 84 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 6 files changed, 113 insertions(+), 29 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index d3773e57acf9..e8287f76484f 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -147,6 +147,7 @@ struct TCP_Server_Info {
 	/* (returned on Negotiate */
 	int capabilities; /* allow selective disabling of caps by smb sess */
 	__u16 timeZone;
+	__u16 CurrentMid;         /* multiplex id - rotating counter */
 	char cryptKey[CIFS_CRYPTO_KEY_SIZE];
 	char workstation_RFC1001_name[16]; /* 16th byte is always zero */
 	__u32 sequence_number; /* needed for CIFS PDU signature */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 3cef57b7a34f..49cc66825309 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1961,18 +1961,17 @@ struct data_blob {
 	perhaps add a CreateDevice - to create Pipes and other special .inodes
 	Also note POSIX open flags
 	2) Close - to return the last write time to do cache across close more safely
-	3) PosixQFSInfo - to return statfs info
-	4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes)
-	5) Mkdir - set mode
+	3) FindFirst return unique inode number - what about resume key, two 
+	forms short (matches readdir) and full (enough info to cache inodes)
+	4) Mkdir - set mode
 	
 	And under consideration: 
-	6) FindClose2 (return nanosecond timestamp ??)
-	7) Use nanosecond timestamps throughout all time fields if 
+	5) FindClose2 (return nanosecond timestamp ??)
+	6) Use nanosecond timestamps throughout all time fields if 
 	   corresponding attribute flag is set
-	8) sendfile - handle based copy
-	9) Direct i/o
-	10) "POSIX ACL" support
-	11) Misc fcntls?
+	7) sendfile - handle based copy
+	8) Direct i/o
+	9) Misc fcntls?
 	
 	what about fixing 64 bit alignment
 	
@@ -2028,7 +2027,7 @@ struct data_blob {
 	
  */
 
-/* xsymlink is a symlink format that can be used
+/* xsymlink is a symlink format (used by MacOS) that can be used
    to save symlink info in a regular file when 
    mounted to operating systems that do not
    support the cifs Unix extensions or EAs (for xattr
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 66eaa6b40373..b9b13e3fe79d 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -61,9 +61,9 @@ extern int decode_negTokenInit(unsigned char *security_blob, int length,
 extern int cifs_inet_pton(int, char * source, void *dst);
 extern int map_smb_to_linux_error(struct smb_hdr *smb);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
-			const struct cifsTconInfo *, int /* specifies length
-			    of fixed section (word count) in two byte units */
-			);
+			    const struct cifsTconInfo *, int /* length of
+			    fixed section (word count) in two byte units */);
+extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, 
 						 struct cifsTconInfo *);
 extern void DeleteOplockQEntry(struct oplock_q_entry *);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 1b073546f5d9..930be0927de2 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -330,7 +330,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 		      (void **) &pSMB, (void **) &pSMBr);
 	if (rc)
 		return rc;
-
+	pSMB->hdr.Mid = GetNextMid(server);
 	pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
 	if (extended_security)
 		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
@@ -415,15 +415,14 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 			if(server->secMode & SECMODE_SIGN_REQUIRED)
 				cERROR(1,
 				 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
-			server->secMode &= ~(SECMODE_SIGN_ENABLED | 
-							SECMODE_SIGN_REQUIRED);
+			server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
 		} else if(sign_CIFS_PDUs == 1) {
 			if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
-				server->secMode &= ~(SECMODE_SIGN_ENABLED |
-							 SECMODE_SIGN_REQUIRED);
+				server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
 		}
 				
 	}
+	
 	cifs_buf_release(pSMB);
 	return rc;
 }
@@ -519,6 +518,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
 	smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
 	
 	if(ses->server) {
+		pSMB->hdr.Mid = GetNextMid(ses->server);
+
 		if(ses->server->secMode & 
 		   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
 			pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
@@ -2519,11 +2520,12 @@ findFirstRetry:
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 
-	if (rc) {/* BB add logic to retry regular search if Unix search 
-			rejected unexpectedly by server */
+	if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
 		/* BB Add code to handle unsupported level rc */
 		cFYI(1, ("Error in FindFirst = %d", rc));
-		cifs_buf_release(pSMB);
+
+		if (pSMB)
+			cifs_buf_release(pSMB);
 
 		/* BB eventually could optimize out free and realloc of buf */
 		/*    for this case */
@@ -2857,7 +2859,10 @@ getDFSRetry:
 		      (void **) &pSMBr);
 	if (rc)
 		return rc;
-
+	
+	/* server pointer checked in called function, 
+	but should never be null here anyway */
+	pSMB->hdr.Mid = GetNextMid(ses->server);
 	pSMB->hdr.Tid = ses->ipc_tid;
 	pSMB->hdr.Uid = ses->Suid;
 	if (ses->capabilities & CAP_STATUS32) {
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 36f78596c81a..9e8256003f73 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1857,6 +1857,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 	header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
 			NULL /* no tCon exists yet */ , 13 /* wct */ );
 
+	smb_buffer->Mid = GetNextMid(ses->server);
 	pSMB->req_no_secext.AndXCommand = 0xFF;
 	pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
 	pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
@@ -2132,6 +2133,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 	/* send SMBsessionSetup here */
 	header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
 			NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+	smb_buffer->Mid = GetNextMid(ses->server);
 	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
 	pSMB->req.AndXCommand = 0xFF;
 	pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
@@ -2398,6 +2401,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 	/* send SMBsessionSetup here */
 	header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
 			NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+	smb_buffer->Mid = GetNextMid(ses->server);
 	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
 	pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
 
@@ -2740,6 +2745,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 	/* send SMBsessionSetup here */
 	header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
 			NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+	smb_buffer->Mid = GetNextMid(ses->server);
 	pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
 	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
 	pSMB->req.AndXCommand = 0xFF;
@@ -3111,6 +3118,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 
 	header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
 			NULL /*no tid */ , 4 /*wct */ );
+
+	smb_buffer->Mid = GetNextMid(ses->server);
 	smb_buffer->Uid = ses->Suid;
 	pSMB = (TCONX_REQ *) smb_buffer;
 	pSMBr = (TCONX_RSP *) smb_buffer_response;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 20ae4153f791..beeff8284169 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -34,8 +34,6 @@ extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
 extern struct task_struct * oplockThread;
 
-static __u16 GlobalMid;		/* multiplex id - rotating counter */
-
 /* The xid serves as a useful identifier for each incoming vfs request, 
    in a similar way to the mid which is useful to track each sent smb, 
    and CurrentXid can also provide a running counter (although it 
@@ -51,6 +49,8 @@ _GetXid(void)
 	GlobalTotalActiveXid++;
 	if (GlobalTotalActiveXid > GlobalMaxActiveXid)
 		GlobalMaxActiveXid = GlobalTotalActiveXid;	/* keep high water mark for number of simultaneous vfs ops in our filesystem */
+	if(GlobalTotalActiveXid > 65000)
+		cFYI(1,("warning: more than 65000 requests active"));
 	xid = GlobalCurrentXid++;
 	spin_unlock(&GlobalMid_Lock);
 	return xid;
@@ -218,6 +218,76 @@ cifs_small_buf_release(void *buf_to_free)
 	return;
 }
 
+/* 
+	Find a free multiplex id (SMB mid). Otherwise there could be
+	mid collisions which might cause problems, demultiplexing the
+	wrong response to this request. Multiplex ids could collide if
+	one of a series requests takes much longer than the others, or
+	if a very large number of long lived requests (byte range
+	locks or FindNotify requests) are pending.  No more than
+	64K-1 requests can be outstanding at one time.  If no 
+	mids are available, return zero.  A future optimization
+	could make the combination of mids and uid the key we use
+	to demultiplex on (rather than mid alone).  
+	In addition to the above check, the cifs demultiplex
+	code already used the command code as a secondary
+	check of the frame and if signing is negotiated the
+	response would be discarded if the mid were the same
+	but the signature was wrong.  Since the mid is not put in the
+	pending queue until later (when it is about to be dispatched)
+	we do have to limit the number of outstanding requests 
+	to somewhat less than 64K-1 although it is hard to imagine
+	so many threads being in the vfs at one time.
+*/
+__u16 GetNextMid(struct TCP_Server_Info *server)
+{
+	__u16 mid = 0;
+	__u16 last_mid;
+	int   collision;  
+
+	if(server == NULL)
+		return mid;
+
+	spin_lock(&GlobalMid_Lock);
+	last_mid = server->CurrentMid; /* we do not want to loop forever */
+	server->CurrentMid++;
+	/* This nested loop looks more expensive than it is.
+	In practice the list of pending requests is short, 
+	fewer than 50, and the mids are likely to be unique
+	on the first pass through the loop unless some request
+	takes longer than the 64 thousand requests before it
+	(and it would also have to have been a request that
+	 did not time out) */
+	while(server->CurrentMid != last_mid) {
+		struct list_head *tmp;
+		struct mid_q_entry *mid_entry;
+
+		collision = 0;
+		if(server->CurrentMid == 0)
+			server->CurrentMid++;
+
+		list_for_each(tmp, &server->pending_mid_q) {
+			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+
+			if ((mid_entry->mid == server->CurrentMid) &&
+			    (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
+				/* This mid is in use, try a different one */
+				collision = 1;
+				break;
+			}
+		}
+		if(collision == 0) {
+			mid = server->CurrentMid;
+			break;
+		}
+		server->CurrentMid++;
+	}
+	spin_unlock(&GlobalMid_Lock);
+	return mid;
+}
+
+/* NB: MID can not be set if treeCon not passed in, in that
+   case it is responsbility of caller to set the mid */
 void
 header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 		const struct cifsTconInfo *treeCon, int word_count
@@ -233,7 +303,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 	    (2 * word_count) + sizeof (struct smb_hdr) -
 	    4 /*  RFC 1001 length field does not count */  +
 	    2 /* for bcc field itself */ ;
-	/* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */
+	/* Note that this is the only network field that has to be converted
+	   to big endian and it is done just before we send it */
 
 	buffer->Protocol[0] = 0xFF;
 	buffer->Protocol[1] = 'S';
@@ -245,8 +316,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 	buffer->Pid = cpu_to_le16((__u16)current->tgid);
 	buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
 	spin_lock(&GlobalMid_Lock);
-	GlobalMid++;
-	buffer->Mid = GlobalMid;
 	spin_unlock(&GlobalMid_Lock);
 	if (treeCon) {
 		buffer->Tid = treeCon->tid;
@@ -256,8 +325,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 			if (treeCon->ses->capabilities & CAP_STATUS32) {
 				buffer->Flags2 |= SMBFLG2_ERR_STATUS;
 			}
-
-			buffer->Uid = treeCon->ses->Suid;	/* always in LE format */
+			/* Uid is not converted */
+			buffer->Uid = treeCon->ses->Suid;
+			buffer->Mid = GetNextMid(treeCon->ses->server);
 			if(multiuser_mount != 0) {
 		/* For the multiuser case, there are few obvious technically  */
 		/* possible mechanisms to match the local linux user (uid)    */
-- 
cgit v1.2.3


From f191401f5906f4d942fac87ebeb4671faf1ba7d6 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 18 Aug 2005 09:37:34 -0700
Subject: [CIFS] rmmod cifs can oops if done soon after the last cifs unmount

Signed-off-by: Shaggy (shaggy@austin.ibm.com)
Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifsfs.c  |  2 +-
 fs/cifs/connect.c | 25 ++++++++++++++++++-------
 2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 8cc23e7d0d5d..7fda0f7d9c00 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -834,8 +834,8 @@ static int cifs_oplock_thread(void * dummyarg)
 				spin_unlock(&GlobalMid_Lock);
 		}
 	} while(!signal_pending(current));
-	complete_and_exit (&cifs_oplock_exited, 0);
 	oplockThread = NULL;
+	complete_and_exit (&cifs_oplock_exited, 0);
 }
 
 static int __init
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 9e8256003f73..ef0432c44482 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -29,6 +29,7 @@
 #include <linux/utsname.h>
 #include <linux/mempool.h>
 #include <linux/delay.h>
+#include <linux/completion.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include "cifspdu.h"
@@ -44,6 +45,8 @@
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
 
+static DECLARE_COMPLETION(cifsd_complete);
+
 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
 		       unsigned char *p24);
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
@@ -339,6 +342,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 	atomic_inc(&tcpSesAllocCount);
 	length = tcpSesAllocCount.counter;
 	write_unlock(&GlobalSMBSeslock);
+	complete(&cifsd_complete);
 	if(length  > 1) {
 		mempool_resize(cifs_req_poolp,
 			length + cifs_min_rcv,
@@ -676,7 +680,7 @@ multi_t2_fnd:
 		msleep(125);
 	}
 
-	if (list_empty(&server->pending_mid_q)) {
+	if (!list_empty(&server->pending_mid_q)) {
 		/* mpx threads have not exited yet give them 
 		at least the smb send timeout time for long ops */
 		/* due to delays on oplock break requests, we need
@@ -713,7 +717,7 @@ multi_t2_fnd:
 			GFP_KERNEL);
 	}
 	
-	msleep(250);
+	complete_and_exit(&cifsd_complete, 0);
 	return 0;
 }
 
@@ -1617,8 +1621,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 					kfree(volume_info.password);
 				FreeXid(xid);
 				return rc;
-			} else
-				rc = 0;
+			}
+			wait_for_completion(&cifsd_complete);
+			rc = 0;
 			memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
 			srvTcp->sequence_number = 0;
 		}
@@ -1759,8 +1764,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			spin_lock(&GlobalMid_Lock);
 			srvTcp->tcpStatus = CifsExiting;
 			spin_unlock(&GlobalMid_Lock);
-			if(srvTcp->tsk)
+			if(srvTcp->tsk) {
 				send_sig(SIGKILL,srvTcp->tsk,1);
+				wait_for_completion(&cifsd_complete);
+			}
 		}
 		 /* If find_unc succeeded then rc == 0 so we can not end */
 		if (tcon)  /* up accidently freeing someone elses tcon struct */
@@ -1773,8 +1780,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 					temp_rc = CIFSSMBLogoff(xid, pSesInfo);
 					/* if the socketUseCount is now zero */
 					if((temp_rc == -ESHUTDOWN) &&
-					   (pSesInfo->server->tsk))
+					   (pSesInfo->server->tsk)) {
 						send_sig(SIGKILL,pSesInfo->server->tsk,1);
+						wait_for_completion(&cifsd_complete);
+					}
 				} else
 					cFYI(1, ("No session or bad tcon"));
 				sesInfoFree(pSesInfo);
@@ -3241,8 +3250,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
 				return 0;
 			} else if (rc == -ESHUTDOWN) {
 				cFYI(1,("Waking up socket by sending it signal"));
-				if(cifsd_task)
+				if(cifsd_task) {
 					send_sig(SIGKILL,cifsd_task,1);
+					wait_for_completion(&cifsd_complete);
+				}
 				rc = 0;
 			} /* else - we have an smb session
 				left on this socket do not kill cifsd */
-- 
cgit v1.2.3


From 8d0d50948b276b46b75b1b5855d3f9fab1e0fd92 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 18 Aug 2005 09:41:43 -0700
Subject: [CIFS] Change Notify support part 1 - add dnotify thread for
 processing notify responses.

Signed-off-by: Asser Ferno  <asser@diku.dk>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifsfs.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 7fda0f7d9c00..d77abe236a67 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -59,6 +59,8 @@ unsigned int ntlmv2_support = 0;
 unsigned int sign_CIFS_PDUs = 1;
 extern struct task_struct * oplockThread; /* remove sparse warning */
 struct task_struct * oplockThread = NULL;
+extern struct task_struct * dnotifyThread; /* remove sparse warning */
+struct task_struct * dnotifyThread = NULL;
 unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
 module_param(CIFSMaxBufSize, int, 0);
 MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
@@ -73,6 +75,7 @@ module_param(cifs_max_pending, int, 0);
 MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256");
 
 static DECLARE_COMPLETION(cifs_oplock_exited);
+static DECLARE_COMPLETION(cifs_dnotify_exited);
 
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
@@ -838,6 +841,19 @@ static int cifs_oplock_thread(void * dummyarg)
 	complete_and_exit (&cifs_oplock_exited, 0);
 }
 
+static int cifs_dnotify_thread(void * dummyarg)
+{
+	daemonize("cifsdnotifyd");
+	allow_signal(SIGTERM);
+
+	dnotifyThread = current;
+	do {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(39*HZ);
+	} while(!signal_pending(current));
+	complete_and_exit (&cifs_dnotify_exited, 0);
+}
+
 static int __init
 init_cifs(void)
 {
@@ -884,10 +900,16 @@ init_cifs(void)
 				if (!rc) {                
 					rc = (int)kernel_thread(cifs_oplock_thread, NULL, 
 						CLONE_FS | CLONE_FILES | CLONE_VM);
-					if(rc > 0)
-						return 0;
-					else 
+					if(rc > 0) {
+						rc = (int)kernel_thread(cifs_dnotify_thread, NULL,
+							CLONE_FS | CLONE_FILES | CLONE_VM);
+						if(rc > 0)
+							return 0;
+						else
+							cERROR(1,("error %d create dnotify thread", rc));
+					} else {
 						cERROR(1,("error %d create oplock thread",rc));
+					}
 				}
 				cifs_destroy_request_bufs();
 			}
@@ -916,6 +938,10 @@ exit_cifs(void)
 		send_sig(SIGTERM, oplockThread, 1);
 		wait_for_completion(&cifs_oplock_exited);
 	}
+	if(dnotifyThread) {
+		send_sig(SIGTERM, dnotifyThread, 1);
+		wait_for_completion(&cifs_dnotify_exited);
+	}
 }
 
 MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
-- 
cgit v1.2.3


From c46fa8acdc533e8084359ea11c79d56eb98313fb Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 18 Aug 2005 20:49:57 -0700
Subject: [CIFS] Add mount option for disabling sending byte range lock
 requests over the wire (to help the case when applications break with cifs
 mandatory lock behavior.  Add part one of mount option for requesting case
 insensitive path name matching.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/CHANGES      |  8 ++++++++
 fs/cifs/README       |  7 +++++++
 fs/cifs/cifs_fs_sb.h |  2 ++
 fs/cifs/cifsfs.h     |  2 +-
 fs/cifs/connect.c    | 14 +++++++++++++-
 fs/cifs/inode.c      |  4 ++++
 fs/cifs/readdir.c    | 10 ++++------
 7 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 3196d4c4eed3..b0429ea524fb 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,11 @@
+Version 1.36
+------------
+Add mount option for disabling the default behavior of sending byte range lock
+requests to the server (necessary for certain applications which break with
+mandatory lock behavior such as Evolution), and also mount option for
+requesting case insensitive matching for path based requests (requesting
+case sensitive is the default).
+
 Version 1.35
 ------------
 Add writepage performance improvements.  Fix path name conversions
diff --git a/fs/cifs/README b/fs/cifs/README
index 34b0cf7111f3..3b610d08dc1e 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -407,6 +407,13 @@ A partial list of the supported mount options follows:
 		This has no effect if the server does not support
 		Unicode on the wire.
  nomapchars     Do not translate any of these seven characters (default).
+ nocase         Request case insensitive path name matching (case
+		sensitive is the default if the server suports it).
+ nobrl          Do not send byte range lock requests to the server.
+		This is necessary for certain applications that break
+		with cifs style mandatory byte range locks (and most
+		cifs servers do not yet support requesting advisory
+		byte range locks).
  remount        remount the share (often used to change from ro to rw mounts
 	        or vice versa)
 		
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 6b93587c490e..5fb695f1e50b 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -26,6 +26,8 @@
 #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
 #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */
 #define CIFS_MOUNT_UNX_EMUL    0x80 /* Network compat with SFUnix emulation */
+#define CIFS_MOUNT_CASE_INSENS  0x100 /* Request case insenstive searches */
+#define CIFS_MOUNT_NO_BRL	0x200 /* No sending byte range locks to srv */
 
 struct cifs_sb_info {
 	struct cifsTconInfo *tcon;	/* primary mount */
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 78af5850c558..cf45ca359dba 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -96,5 +96,5 @@ extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 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.35"
+#define CIFS_VERSION   "1.36"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index ef0432c44482..6b21f6aa9f60 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -79,6 +79,8 @@ struct smb_vol {
 	unsigned remap:1;   /* set to remap seven reserved chars in filenames */
 	unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
 	unsigned sfu_emul:1;
+	unsigned nocase;     /* request case insensitive filenames */
+	unsigned nobrl;      /* disable sending byte range locks to srv */
 	unsigned int rsize;
 	unsigned int wsize;
 	unsigned int sockopt;
@@ -1040,6 +1042,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 			vol->posix_paths = 1;
 		} else if (strnicmp(data, "noposixpaths", 12) == 0) {
 			vol->posix_paths = 0;
+                } else if (strnicmp(data, "nocase", 6) == 0) {
+                        vol->nocase = 1;
+		} else if (strnicmp(data, "brl", 3) == 0) {
+			vol->nobrl =  0;
+		} else if (strnicmp(data, "nobrl", 5) == 0) {
+			vol->nobrl =  1;
 		} else if (strnicmp(data, "setuids", 7) == 0) {
 			vol->setuids = 1;
 		} else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -1699,9 +1707,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
 		if(volume_info.sfu_emul)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
+		if(volume_info.nocase)
+			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CASE_INSENS;
+		if(volume_info.nobrl)
+			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
 
 		if(volume_info.direct_io) {
-			cERROR(1,("mounting share using direct i/o"));
+			cFYI(1,("mounting share using direct i/o"));
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
 		}
 
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 628aa1a9fe64..ed3e9207d92e 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -166,6 +166,8 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 				inode->i_fop = &cifs_file_direct_ops;
 			else
 				inode->i_fop = &cifs_file_ops;
+			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+				inode->i_fop->lock = NULL;
 			inode->i_data.a_ops = &cifs_addr_ops;
 		} else if (S_ISDIR(inode->i_mode)) {
 			cFYI(1, (" Directory inode"));
@@ -369,6 +371,8 @@ int cifs_get_inode_info(struct inode **pinode,
 				inode->i_fop = &cifs_file_direct_ops;
 			else
 				inode->i_fop = &cifs_file_ops;
+			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+				inode->i_fop->lock = NULL;
 			inode->i_data.a_ops = &cifs_addr_ops;
 		} else if (S_ISDIR(inode->i_mode)) {
 			cFYI(1, (" Directory inode "));
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index dec3c9dd04d7..ef5eb804ce82 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -194,6 +194,8 @@ static void fill_in_inode(struct inode *tmp_inode,
 			tmp_inode->i_fop = &cifs_file_direct_ops;
 		else
 			tmp_inode->i_fop = &cifs_file_ops;
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+			tmp_inode->i_fop->lock = NULL;
 		tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
 		if(isNewInode)
@@ -298,6 +300,8 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
 			tmp_inode->i_fop = &cifs_file_direct_ops;
 		else
 			tmp_inode->i_fop = &cifs_file_ops;
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+			tmp_inode->i_fop->lock = NULL;
 		tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
 		if(isNewInode)
@@ -557,7 +561,6 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 		char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 
 			smbCalcSize((struct smb_hdr *)
 				cifsFile->srch_inf.ntwrk_buf_start);
-/*	dump_cifs_file_struct(file,"found entry in fce "); */
 		first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
 					- cifsFile->srch_inf.entries_in_buffer;
 		pos_in_buf = index_to_find - first_entry_in_buffer;
@@ -595,7 +598,6 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 		*num_to_ret = 0;
 	} else
 		*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
-/*	dump_cifs_file_struct(file, "end fce ");*/
 
 	return rc;
 }
@@ -815,14 +817,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 		FreeXid(xid);
 		return -EIO;
 	}
-/*	dump_cifs_file_struct(file, "Begin rdir "); */
 
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
 	if(pTcon == NULL)
 		return -EINVAL;
 
-/*	cFYI(1,("readdir2 pos: %lld",file->f_pos)); */
 
 	switch ((int) file->f_pos) {
 	case 0:
@@ -876,7 +876,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 		cifsFile->search_resume_name = NULL; */
 
 		/* BB account for . and .. in f_pos as special case */
-		/* dump_cifs_file_struct(file, "rdir after default ");*/
 
 		rc = find_cifs_entry(xid,pTcon, file,
 				&current_entry,&num_to_fill);
@@ -924,7 +923,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 	} /* end switch */
 
 rddir2_exit:
-	/* dump_cifs_file_struct(file, "end rdir ");  */
 	FreeXid(xid);
 	return rc;
 }
-- 
cgit v1.2.3


From d3485d37c0b3292aec0618b6663c57542df5da99 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Fri, 19 Aug 2005 11:04:29 -0700
Subject: [CIFS] Finish cifs mount option which requests case insensitive path
 name matching.

	Signed-off-by:  Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifs_fs_sb.h | 3 +--
 fs/cifs/cifsglob.h   | 5 +++--
 fs/cifs/connect.c    | 9 +++++++--
 fs/cifs/misc.c       | 2 ++
 4 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 5fb695f1e50b..f799f6f0e729 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -26,8 +26,7 @@
 #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
 #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */
 #define CIFS_MOUNT_UNX_EMUL    0x80 /* Network compat with SFUnix emulation */
-#define CIFS_MOUNT_CASE_INSENS  0x100 /* Request case insenstive searches */
-#define CIFS_MOUNT_NO_BRL	0x200 /* No sending byte range locks to srv */
+#define CIFS_MOUNT_NO_BRL	0x100 /* No sending byte range locks to srv */
 
 struct cifs_sb_info {
 	struct cifsTconInfo *tcon;	/* primary mount */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e8287f76484f..e7ba48c61a7a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -110,8 +110,8 @@ enum protocolEnum {
  */
 
 struct TCP_Server_Info {
-	char server_Name[SERVER_NAME_LEN_WITH_NULL];	/* 15 chars + X'20'in 16th */
-	char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];	/* Unicode version of server_Name */
+	char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20' 16th */
+	char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
 	struct socket *ssocket;
 	union {
 		struct sockaddr_in sockAddr;
@@ -231,6 +231,7 @@ struct cifsTconInfo {
 	FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo;	/* ok if file system name truncated */
 	FILE_SYSTEM_UNIX_INFO fsUnixInfo;
 	unsigned retry:1;
+	unsigned nocase:1;
 	/* BB add field for back pointer to sb struct? */
 };
 
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 6b21f6aa9f60..ac2c8bdc8e55 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1048,6 +1048,11 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 			vol->nobrl =  0;
 		} else if (strnicmp(data, "nobrl", 5) == 0) {
 			vol->nobrl =  1;
+			/* turn off mandatory locking in mode
+			if remote locking is turned off since the
+			local vfs will do advisory */
+			if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
+				vol->file_mode = S_IALLUGO;
 		} else if (strnicmp(data, "setuids", 7) == 0) {
 			vol->setuids = 1;
 		} else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -1707,8 +1712,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
 		if(volume_info.sfu_emul)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
-		if(volume_info.nocase)
-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CASE_INSENS;
 		if(volume_info.nobrl)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
 
@@ -1727,6 +1730,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			   to the same server share the last value passed in 
 			   for the retry flag is used */
 			tcon->retry = volume_info.retry;
+			tcon->nocase = volume_info.nocase;
 		} else {
 			tcon = tconInfoAlloc();
 			if (tcon == NULL)
@@ -1755,6 +1759,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 				if (!rc) {
 					atomic_inc(&pSesInfo->inUse);
 					tcon->retry = volume_info.retry;
+					tcon->nocase = volume_info.nocase;
 				}
 			}
 		}
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index beeff8284169..40d50b77bfe7 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -375,6 +375,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 		}
 		if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
 			buffer->Flags2 |= SMBFLG2_DFS;
+		if (treeCon->nocase)
+			buffer->Flags  |= SMBFLG_CASELESS;
 		if((treeCon->ses) && (treeCon->ses->server))
 			if(treeCon->ses->server->secMode & 
 			  (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-- 
cgit v1.2.3


From a5a2b489bae8f66559a531df99a26eb16b42299e Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Sat, 20 Aug 2005 21:42:53 -0700
Subject: [CIFS] Make CIFS statistics more accurate and add some stats that
 were missing.  Most importantly SMB reads were undercounted.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifs_debug.c | 30 ++++++++++++------
 fs/cifs/cifsglob.h   | 20 +++++++++++-
 fs/cifs/cifssmb.c    | 89 ++++++++++++++++++++++++++++++----------------------
 fs/cifs/file.c       |  5 ---
 fs/cifs/transport.c  |  2 +-
 5 files changed, 91 insertions(+), 55 deletions(-)

diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 838171328076..f4c6544468ab 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -254,36 +254,46 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
 			buf += sprintf(buf, "\tDISCONNECTED ");
 			length += 14;
 		}
-		item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d",
+		item_length = sprintf(buf, "\nSMBs: %d Oplock Breaks: %d",
 			atomic_read(&tcon->num_smbs_sent),
 			atomic_read(&tcon->num_oplock_brks));
 		buf += item_length;
 		length += item_length;
-		item_length = sprintf(buf,"\nReads: %d Bytes %lld",
+		item_length = sprintf(buf, "\nReads: %d Bytes %lld",
 			atomic_read(&tcon->num_reads),
 			(long long)(tcon->bytes_read));
 		buf += item_length;
 		length += item_length;
-		item_length = sprintf(buf,"\nWrites: %d Bytes: %lld",
+		item_length = sprintf(buf, "\nWrites: %d Bytes: %lld",
 			atomic_read(&tcon->num_writes),
 			(long long)(tcon->bytes_written));
+                buf += item_length;
+                length += item_length;
+                item_length = sprintf(buf, 
+			"\nLocks: %d HardLinks: %d Symlinks: %d",
+                        atomic_read(&tcon->num_locks),
+			atomic_read(&tcon->num_hardlinks),
+			atomic_read(&tcon->num_symlinks));
+                buf += item_length;
+                length += item_length;
+
+		item_length = sprintf(buf, "\nOpens: %d Closes: %d Deletes: %d",
+			atomic_read(&tcon->num_opens),
+			atomic_read(&tcon->num_closes),
+			atomic_read(&tcon->num_deletes));
 		buf += item_length;
 		length += item_length;
-		item_length = sprintf(buf,
-			"\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
-			atomic_read(&tcon->num_opens),
-			atomic_read(&tcon->num_deletes),
+		item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d",
 			atomic_read(&tcon->num_mkdirs),
 			atomic_read(&tcon->num_rmdirs));
 		buf += item_length;
 		length += item_length;
-		item_length = sprintf(buf,
-			"\nRenames: %d T2 Renames %d",
+		item_length = sprintf(buf, "\nRenames: %d T2 Renames %d",
 			atomic_read(&tcon->num_renames),
 			atomic_read(&tcon->num_t2renames));
 		buf += item_length;
 		length += item_length;
-		item_length = sprintf(buf,"\nFindFirst: %d FNext %d FClose %d",
+		item_length = sprintf(buf, "\nFindFirst: %d FNext %d FClose %d",
 			atomic_read(&tcon->num_ffirst),
 			atomic_read(&tcon->num_fnext),
 			atomic_read(&tcon->num_fclose));
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e7ba48c61a7a..6a8c7d1bee8c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -215,6 +215,7 @@ struct cifsTconInfo {
 	atomic_t num_reads;
 	atomic_t num_oplock_brks;
 	atomic_t num_opens;
+	atomic_t num_closes;
 	atomic_t num_deletes;
 	atomic_t num_mkdirs;
 	atomic_t num_rmdirs;
@@ -223,10 +224,27 @@ struct cifsTconInfo {
 	atomic_t num_ffirst;
 	atomic_t num_fnext;
 	atomic_t num_fclose;
+	atomic_t num_hardlinks;
+	atomic_t num_symlinks;
+	atomic_t num_locks;
+#ifdef CONFIG_CIFS_STATS2
+	unsigned long long time_writes;
+	unsigned long long time_reads;
+	unsigned long long time_opens;
+	unsigned long long time_deletes;
+	unsigned long long time_closes;
+	unsigned long long time_mkdirs;
+	unsigned long long time_rmdirs;
+	unsigned long long time_renames;
+	unsigned long long time_t2renames;
+	unsigned long long time_ffirst;
+	unsigned long long time_fnext;
+	unsigned long long time_fclose;
+#endif /* CONFIG_CIFS_STATS2 */
 	__u64    bytes_read;
 	__u64    bytes_written;
 	spinlock_t stat_lock;
-#endif
+#endif /* CONFIG_CIFS_STATS */
 	FILE_SYSTEM_DEVICE_INFO fsDevInfo;
 	FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo;	/* ok if file system name truncated */
 	FILE_SYSTEM_UNIX_INFO fsUnixInfo;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 930be0927de2..1292db50fe65 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -584,14 +584,12 @@ DelFileRetry:
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_deletes);
+#endif
 	if (rc) {
 		cFYI(1, ("Error in RMFile = %d", rc));
 	} 
-#ifdef CONFIG_CIFS_STATS
-        else {
-		atomic_inc(&tcon->num_deletes);
-        }
-#endif
 
 	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
@@ -633,14 +631,12 @@ RmDirRetry:
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_rmdirs);
+#endif
 	if (rc) {
 		cFYI(1, ("Error in RMDir = %d", rc));
 	}
-#ifdef CONFIG_CIFS_STATS
-        else {
-		atomic_inc(&tcon->num_rmdirs);
-        }
-#endif
 
 	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
@@ -681,14 +677,13 @@ MkDirRetry:
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_mkdirs);
+#endif
 	if (rc) {
 		cFYI(1, ("Error in Mkdir = %d", rc));
 	}
-#ifdef CONFIG_CIFS_STATS
-        else {
-		atomic_inc(&tcon->num_mkdirs);
-        }
-#endif
+
 	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto MkDirRetry;
@@ -772,6 +767,9 @@ openRetry:
 	/* 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, 1);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_opens);
+#endif
 	if (rc) {
 		cFYI(1, ("Error in Open = %d", rc));
 	} else {
@@ -789,11 +787,8 @@ openRetry:
 		    pfile_info->EndOfFile = pSMBr->EndOfFile;
 		    pfile_info->NumberOfLinks = cpu_to_le32(1);
 		}
-
-#ifdef CONFIG_CIFS_STATS
-		atomic_inc(&tcon->num_opens);
-#endif
 	}
+
 	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto openRetry;
@@ -838,6 +833,9 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_reads);
+#endif 	
 	if (rc) {
 		cERROR(1, ("Send error in read = %d", rc));
 	} else {
@@ -940,6 +938,9 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_writes);
+#endif
 	if (rc) {
 		cFYI(1, ("Send error in write = %d", rc));
 		*nbytes = 0;
@@ -1012,6 +1013,9 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 
 	rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
 			  buf, bytes_sent, &bytes_returned, long_op);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_writes);
+#endif
 	if (rc) {
 		cFYI(1, ("Send error in write = %d", rc));
 		*nbytes = 0;
@@ -1087,7 +1091,9 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
-
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_locks);
+#endif
 	if (rc) {
 		cFYI(1, ("Send error in Lock = %d", rc));
 	}
@@ -1121,6 +1127,9 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 	pSMB->ByteCount = 0;
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_closes);
+#endif 
 	if (rc) {
 		if(rc!=-EINTR) {
 			/* EINTR is expected when user ctl-c to kill app */
@@ -1193,16 +1202,13 @@ renameRetry:
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_renames);
+#endif
 	if (rc) {
 		cFYI(1, ("Send error in rename = %d", rc));
 	} 
 
-#ifdef CONFIG_CIFS_STATS
-	  else {
-		atomic_inc(&tcon->num_renames);
-	}
-#endif
-
 	cifs_buf_release(pSMB);
 
 	if (rc == -EAGAIN)
@@ -1277,14 +1283,13 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&pTcon->num_t2renames);
+#endif 
 	if (rc) {
 		cFYI(1,("Send error in Rename (by file handle) = %d", rc));
 	}
-#ifdef CONFIG_CIFS_STATS
-	  else {
-		atomic_inc(&pTcon->num_t2renames);
-	}
-#endif
+
 	cifs_buf_release(pSMB);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls
@@ -1438,6 +1443,9 @@ createSymLinkRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_symlinks);
+#endif
 	if (rc) {
 		cFYI(1,
 		     ("Send error in SetPathInfo (create symlink) = %d",
@@ -1527,6 +1535,9 @@ createHardLinkRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_hardlinks);
+#endif
 	if (rc) {
 		cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
 	}
@@ -1597,6 +1608,9 @@ winCreateHardLinkRetry:
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_hardlinks);
+#endif
 	if (rc) {
 		cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
 	}
@@ -2519,6 +2533,9 @@ findFirstRetry:
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_ffirst);
+#endif
 
 	if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
 		/* BB Add code to handle unsupported level rc */
@@ -2532,9 +2549,6 @@ findFirstRetry:
 		if (rc == -EAGAIN)
 			goto findFirstRetry;
 	} else { /* decode response */
-#ifdef CONFIG_CIFS_STATS
-		atomic_inc(&tcon->num_ffirst);
-#endif
 		/* BB remember to free buffer if error BB */
 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 		if(rc == 0) {
@@ -2643,7 +2657,9 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                                                                                               
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
-                                                                                              
+#ifdef CONFIG_CIFS_STATS
+	atomic_inc(&tcon->num_fnext);
+#endif                                                                                          
 	if (rc) {
 		if (rc == -EBADF) {
 			psrch_inf->endOfSearch = TRUE;
@@ -2651,9 +2667,6 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 		} else
 			cFYI(1, ("FindNext returned = %d", rc));
 	} else {                /* decode response */
-#ifdef CONFIG_CIFS_STATS
-		atomic_inc(&tcon->num_fnext);
-#endif
 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 		
 		if(rc == 0) {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index ddb25a0a63d5..b054df2dee1e 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -746,7 +746,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 
 #ifdef CONFIG_CIFS_STATS
 	if (total_written > 0) {
-		atomic_inc(&pTcon->num_writes);
 		spin_lock(&pTcon->stat_lock);
 		pTcon->bytes_written += total_written;
 		spin_unlock(&pTcon->stat_lock);
@@ -881,7 +880,6 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 
 #ifdef CONFIG_CIFS_STATS
 	if (total_written > 0) {
-		atomic_inc(&pTcon->num_writes);
 		spin_lock(&pTcon->stat_lock);
 		pTcon->bytes_written += total_written;
 		spin_unlock(&pTcon->stat_lock);
@@ -1248,7 +1246,6 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 			}
 		} else {
 #ifdef CONFIG_CIFS_STATS
-			atomic_inc(&pTcon->num_reads);
 			spin_lock(&pTcon->stat_lock);
 			pTcon->bytes_read += total_read;
 			spin_unlock(&pTcon->stat_lock);
@@ -1316,7 +1313,6 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 			}
 		} else {
 #ifdef CONFIG_CIFS_STATS
-			atomic_inc(&pTcon->num_reads);
 			spin_lock(&pTcon->stat_lock);
 			pTcon->bytes_read += total_read;
 			spin_unlock(&pTcon->stat_lock);
@@ -1493,7 +1489,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 
 			i +=  bytes_read >> PAGE_CACHE_SHIFT;
 #ifdef CONFIG_CIFS_STATS
-			atomic_inc(&pTcon->num_reads);
 			spin_lock(&pTcon->stat_lock);
 			pTcon->bytes_read += bytes_read;
 			spin_unlock(&pTcon->stat_lock);
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 496a2738bbe3..96f89eb66040 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -735,7 +735,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 				BCC(out_buf) = le16_to_cpu(BCC(out_buf));
 		} else {
 			rc = -EIO;
-			cFYI(1,("Bad MID state? "));
+			cERROR(1,("Bad MID state? "));
 		}
 	}
 cifs_no_response_exit:
-- 
cgit v1.2.3


From b92327fe6b25d60004b79df9e3c19091c03118ba Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 22 Aug 2005 20:09:43 -0700
Subject: [CIFS] Finish up of case-insensitive dentry handling for cifs.  This
 will eventually (or should eventually) be common code for jfs, smbfs, etc.
 but in the meantime is small enough and necessary when mounting case
 insensitive to Windows (nocase).

Signed-off-by: Shaggy (shaggy@austin.ibm.com)
Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifsfs.h  |  1 +
 fs/cifs/dir.c     | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 fs/cifs/inode.c   |  5 ++++-
 fs/cifs/link.c    |  5 ++++-
 fs/cifs/readdir.c |  5 ++++-
 5 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index d5fb3441555f..bb3404a99e5f 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -81,6 +81,7 @@ extern int cifs_dir_notify(struct file *, unsigned long arg);
 
 /* Functions related to dir entries */
 extern struct dentry_operations cifs_dentry_ops;
+extern struct dentry_operations cifs_ci_dentry_ops;
 
 /* Functions related to symlinks */
 extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index c619d45060ce..5311c50734b0 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -230,7 +230,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 			     ("Create worked but get_inode_info failed rc = %d",
 			      rc));
 		} else {
-			direntry->d_op = &cifs_dentry_ops;
+			if (pTcon->nocase)
+				direntry->d_op = &cifs_ci_dentry_ops;
+			else
+				direntry->d_op = &cifs_dentry_ops;
 			d_instantiate(direntry, newinode);
 		}
 		if((nd->flags & LOOKUP_OPEN) == FALSE) {
@@ -322,7 +325,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
 		if(!rc) {
 			rc = cifs_get_inode_info_unix(&newinode, full_path,
 						inode->i_sb,xid);
-			direntry->d_op = &cifs_dentry_ops;
+			if (pTcon->nocase)
+				direntry->d_op = &cifs_ci_dentry_ops;
+			else
+				direntry->d_op = &cifs_dentry_ops;
 			if(rc == 0)
 				d_instantiate(direntry, newinode);
 		}
@@ -418,7 +424,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
 					 parent_dir_inode->i_sb,xid);
 
 	if ((rc == 0) && (newInode != NULL)) {
-		direntry->d_op = &cifs_dentry_ops;
+		if (pTcon->nocase)
+			direntry->d_op = &cifs_ci_dentry_ops;
+		else
+			direntry->d_op = &cifs_dentry_ops;
 		d_add(direntry, newInode);
 
 		/* since paths are not looked up by component - the parent directories are presumed to be good here */
@@ -477,3 +486,42 @@ struct dentry_operations cifs_dentry_ops = {
 /* d_delete:       cifs_d_delete,       *//* not needed except for debugging */
 	/* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
 };
+
+static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
+{
+	struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
+	unsigned long hash;
+	int i;
+
+	hash = init_name_hash();
+	for (i = 0; i < q->len; i++)
+		hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
+					 hash);
+	q->hash = end_name_hash(hash);
+
+	return 0;
+}
+
+static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
+			   struct qstr *b)
+{
+	struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
+
+	if ((a->len == b->len) &&
+	    (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
+		/*
+		 * To preserve case, don't let an existing negative dentry's
+		 * case take precedence.  If a is not a negative dentry, this
+		 * should have no side effects
+		 */
+		memcpy((unsigned char *)a->name, b->name, a->len);
+		return 0;
+	}
+	return 1;
+}
+
+struct dentry_operations cifs_ci_dentry_ops = {
+	.d_revalidate = cifs_d_revalidate,
+	.d_hash = cifs_ci_hash,
+	.d_compare = cifs_ci_compare,
+};
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index ed3e9207d92e..2d50b3507d13 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -591,7 +591,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 			rc = cifs_get_inode_info(&newinode, full_path, NULL,
 						 inode->i_sb,xid);
 
-		direntry->d_op = &cifs_dentry_ops;
+		if (pTcon->nocase)
+			direntry->d_op = &cifs_ci_dentry_ops;
+		else
+			direntry->d_op = &cifs_dentry_ops;
 		d_instantiate(direntry, newinode);
 		if (direntry->d_inode)
 			direntry->d_inode->i_nlink = 2;
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index da420e8c3298..b8ec6646456a 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -199,7 +199,10 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
 			     ("Create symlink worked but get_inode_info failed with rc = %d ",
 			      rc));
 		} else {
-			direntry->d_op = &cifs_dentry_ops;
+			if (pTcon->nocase)
+				direntry->d_op = &cifs_ci_dentry_ops;
+			else
+				direntry->d_op = &cifs_dentry_ops;
 			d_instantiate(direntry, newinode);
 		}
 	}
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index ef5eb804ce82..f769292e2a93 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
 		}
 
 		*ptmp_inode = new_inode(file->f_dentry->d_sb);
-		tmp_dentry->d_op = &cifs_dentry_ops;
+		if (pTcon->nocase)
+			tmp_dentry->d_op = &cifs_ci_dentry_ops;
+		else
+			tmp_dentry->d_op = &cifs_dentry_ops;
 		if(*ptmp_inode == NULL)
 			return rc;
 		rc = 1;
-- 
cgit v1.2.3


From a10faeb2a3e266385cc334fe9af76e08e5e4330f Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 22 Aug 2005 21:38:31 -0700
Subject: [CIFS] Support for mounting to older, pre-CIFS servers added.  This
 allows specifying an RFC1001 target "called" name (netbios name of the
 server, which can now be pecified as mount option "servernetbiosname" but
 will eventually be passed in automatically on retry of host down error
 messages caused when server refuses to handle default server name and can not
 handle port 445). This is an important step, but additional testing and fixup
 is needed to add remaining function needed for these.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/CHANGES    |  7 ++++++-
 fs/cifs/cifsglob.h |  6 ++++--
 fs/cifs/connect.c  | 57 +++++++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 58 insertions(+), 12 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index b0429ea524fb..2137002aecc4 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,5 +1,6 @@
 Version 1.36
 ------------
+Add support for moounting to older pre-CIFS servers such as Windows9x and ME.
 Add mount option for disabling the default behavior of sending byte range lock
 requests to the server (necessary for certain applications which break with
 mandatory lock behavior such as Evolution), and also mount option for
@@ -10,7 +11,11 @@ Version 1.35
 ------------
 Add writepage performance improvements.  Fix path name conversions
 for long filenames on mounts which were done with "mapchars" mount option
-specified.
+specified.  Ensure multiplex ids do not collide.  Fix case in which 
+rmmod can oops if done soon after last unmount.  Fix truncated
+search (readdir) output when resume filename was a long filename.
+Fix filename conversion when mapchars mount option was specified and
+filename was a long filename.
 
 Version 1.34
 ------------
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 6a8c7d1bee8c..f143975627e0 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -110,7 +110,8 @@ enum protocolEnum {
  */
 
 struct TCP_Server_Info {
-	char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20' 16th */
+	/* 15 character server name + 0x20 16th byte indicating type = srv */
+	char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
 	char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
 	struct socket *ssocket;
 	union {
@@ -149,7 +150,8 @@ struct TCP_Server_Info {
 	__u16 timeZone;
 	__u16 CurrentMid;         /* multiplex id - rotating counter */
 	char cryptKey[CIFS_CRYPTO_KEY_SIZE];
-	char workstation_RFC1001_name[16]; /* 16th byte is always zero */
+	/* 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_SESSION_KEY_SIZE + 16]; 
 };
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index ac2c8bdc8e55..9d61844e89b6 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -63,6 +63,7 @@ struct smb_vol {
 	char *in6_addr;  /* ipv6 address as human readable form of in6_addr */
 	char *iocharset;  /* local code page for mapping to and from Unicode */
 	char source_rfc1001_name[16]; /* netbios name of client */
+	char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
 	uid_t linux_uid;
 	gid_t linux_gid;
 	mode_t file_mode;
@@ -89,7 +90,8 @@ struct smb_vol {
 
 static int ipv4_connect(struct sockaddr_in *psin_server, 
 			struct socket **csocket,
-			char * netb_name);
+			char * netb_name,
+			char * server_netb_name);
 static int ipv6_connect(struct sockaddr_in6 *psin_server, 
 			struct socket **csocket);
 
@@ -182,7 +184,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
 		} else {
 			rc = ipv4_connect(&server->addr.sockAddr, 
 					&server->ssocket,
-					server->workstation_RFC1001_name);
+					server->workstation_RFC1001_name,
+					server->server_RFC1001_name);
 		}
 		if(rc) {
 			msleep(3000);
@@ -743,7 +746,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 			toupper(system_utsname.nodename[i]);
 	}
 	vol->source_rfc1001_name[15] = 0;
-
+	/* null target name indicates to use *SMBSERVR default called name
+	   if we end up sending RFC1001 session initialize */
+	vol->target_rfc1001_name[0] = 0;
 	vol->linux_uid = current->uid;	/* current->euid instead? */
 	vol->linux_gid = current->gid;
 	vol->dir_mode = S_IRWXUGO;
@@ -996,7 +1001,31 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 				/* The string has 16th byte zero still from
 				set at top of the function  */
 				if((i==15) && (value[i] != 0))
-					printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
+					printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
+			}
+		} else if (strnicmp(data, "servern", 7) == 0) {
+			/* servernetbiosname specified override *SMBSERVER */
+			if (!value || !*value || (*value == ' ')) {
+				cFYI(1,("empty server netbiosname specified"));
+			} else {
+				/* last byte, type, is 0x20 for servr type */
+				memset(vol->target_rfc1001_name,0x20,16);
+
+				for(i=0;i<15;i++) {
+				/* BB are there cases in which a comma can be
+				   valid in this workstation netbios name (and need
+				   special handling)? */
+
+				/* user or mount helper must uppercase netbiosname */
+					if (value[i]==0)
+						break;
+					else
+						vol->target_rfc1001_name[i] = value[i];
+				}
+				/* The string has 16th byte zero still from
+				   set at top of the function  */
+				if((i==15) && (value[i] != 0))
+					printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
 			}
 		} else if (strnicmp(data, "credentials", 4) == 0) {
 			/* ignore */
@@ -1042,7 +1071,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 			vol->posix_paths = 1;
 		} else if (strnicmp(data, "noposixpaths", 12) == 0) {
 			vol->posix_paths = 0;
-                } else if (strnicmp(data, "nocase", 6) == 0) {
+                } else if ((strnicmp(data, "nocase", 6) == 0) ||
+			   (strnicmp(data, "ignorecase", 10)  == 0)) {
                         vol->nocase = 1;
 		} else if (strnicmp(data, "brl", 3) == 0) {
 			vol->nobrl =  0;
@@ -1272,7 +1302,7 @@ static void rfc1002mangle(char * target,char * source, unsigned int length)
 
 static int
 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, 
-			 char * netbios_name)
+	     char * netbios_name, char * target_name)
 {
 	int rc = 0;
 	int connected = 0;
@@ -1350,8 +1380,14 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
 		ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
 		if(ses_init_buf) {
 			ses_init_buf->trailer.session_req.called_len = 32;
-			rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
-				DEFAULT_CIFS_CALLED_NAME,16);
+			if(target_name && (target_name[0] != 0)) {
+				rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+					target_name, 16);
+			} else {
+				rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+					DEFAULT_CIFS_CALLED_NAME,16);
+			}
+
 			ses_init_buf->trailer.session_req.calling_len = 32;
 			/* calling name ends in null (byte 16) from old smb
 			convention. */
@@ -1584,7 +1620,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			sin_server.sin_port = htons(volume_info.port);
 		else
 			sin_server.sin_port = 0;
-		rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
+		rc = ipv4_connect(&sin_server,&csocket,
+				  volume_info.source_rfc1001_name,
+				  volume_info.target_rfc1001_name);
 		if (rc < 0) {
 			cERROR(1,
 			       ("Error connecting to IPv4 socket. Aborting operation"));
@@ -1638,6 +1676,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			wait_for_completion(&cifsd_complete);
 			rc = 0;
 			memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
+			memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
 			srvTcp->sequence_number = 0;
 		}
 	}
-- 
cgit v1.2.3


From 6b8edfe0f918e7585acb3bd63f62ff56e32dd3d2 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 23 Aug 2005 20:26:03 -0700
Subject: [CIFS] Support for mounting to older servers part 2.  Add support for
 legacy getattr (lookup).

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/CHANGES     |  2 ++
 fs/cifs/cifspdu.h   | 17 +++++++++++++++
 fs/cifs/cifsproto.h |  4 ++++
 fs/cifs/cifssmb.c   | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/connect.c   |  5 +++--
 fs/cifs/inode.c     | 12 ++++++++++-
 6 files changed, 96 insertions(+), 3 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 2137002aecc4..299ed312cea5 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,6 +1,8 @@
 Version 1.36
 ------------
 Add support for moounting to older pre-CIFS servers such as Windows9x and ME.
+For these older servers, add option for passing netbios name of server in
+on mount (servernetbiosname).
 Add mount option for disabling the default behavior of sending byte range lock
 requests to the server (necessary for certain applications which break with
 mandatory lock behavior such as Evolution), and also mount option for
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 49cc66825309..42c16cf32284 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -36,6 +36,7 @@
 #define SMB_COM_CLOSE                 0x04 /* triv req/rsp, timestamp ignored */
 #define SMB_COM_DELETE                0x06 /* trivial response */
 #define SMB_COM_RENAME                0x07 /* trivial response */
+#define SMB_COM_QUERY_INFORMATION     0x08 /* aka getattr */
 #define SMB_COM_SETATTR               0x09 /* trivial response */
 #define SMB_COM_LOCKING_ANDX          0x24 /* trivial response */
 #define SMB_COM_COPY                  0x29 /* trivial rsp, fail filename ignrd*/
@@ -885,6 +886,22 @@ typedef struct smb_com_create_directory_rsp {
 	__u16 ByteCount;	/* bct = 0 */
 } CREATE_DIRECTORY_RSP;
 
+typedef struct smb_com_query_information_req {
+	struct smb_hdr hdr;     /* wct = 0 */
+	__le16 ByteCount;	/* 1 + namelen + 1 */
+	__u8 BufferFormat;      /* 4 = ASCII */
+	unsigned char FileName[1];
+} QUERY_INFORMATION_REQ;
+
+typedef struct smb_com_query_information_rsp {
+	struct smb_hdr hdr;     /* wct = 10 */
+	__le16 attr;
+	__le32  last_write_time;
+	__le32 size;
+	__u16  reserved[5];
+	__le16 ByteCount;	/* bcc = 0 */
+} QUERY_INFORMATION_RSP;
+
 typedef struct smb_com_setattr_req {
 	struct smb_hdr hdr; /* wct = 8 */
 	__le16 attr;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b9b13e3fe79d..0cc0612eacb4 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -105,6 +105,10 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName,
 			FILE_ALL_INFO * findData,
 			const struct nls_table *nls_codepage, int remap);
+extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
+                        const unsigned char *searchName,
+                        FILE_ALL_INFO * findData,
+                        const struct nls_table *nls_codepage, int remap);
 
 extern int CIFSSMBUnixQPathInfo(const int xid,
 			struct cifsTconInfo *tcon,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 1292db50fe65..811ab3dffafa 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2200,6 +2200,65 @@ GetExtAttrOut:
 
 #endif /* CONFIG_POSIX */
 
+/* Legacy Query Path Information call for lookup to old servers such
+   as Win9x/WinME */
+int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
+                 const unsigned char *searchName,
+                 FILE_ALL_INFO * pFinfo,
+                 const struct nls_table *nls_codepage, int remap)
+{
+	QUERY_INFORMATION_REQ * pSMB;
+	QUERY_INFORMATION_RSP * pSMBr;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("In SMBQPath path %s", searchName)); 
+QInfRetry:
+	rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
+                      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+                    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+                                     PATH_MAX, nls_codepage, remap);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+	} else {               
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+	pSMB->BufferFormat = 0x04;
+	name_len++; /* account for buffer type byte */	
+	pSMB->hdr.smb_buf_length += (__u16) name_len;
+	pSMB->ByteCount = cpu_to_le16(name_len);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QueryInfo = %d", rc));
+	} else if (pFinfo) {            /* decode response */
+		memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
+		pFinfo->AllocationSize = (__le64) pSMBr->size;
+		pFinfo->EndOfFile = (__le64) pSMBr->size;
+		pFinfo->Attributes = (__le32) pSMBr->attr;
+	} else
+		rc = -EIO; /* bad buffer passed in */
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto QInfRetry;
+
+	return rc;
+}
+
+
+
+
 int
 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
 		 const unsigned char *searchName,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 9d61844e89b6..c75bae1242dc 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1730,8 +1730,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 		else
 			cifs_sb->wsize = CIFSMaxBufSize; /* default */
 		if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
-			cifs_sb->rsize = PAGE_CACHE_SIZE;
-			cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
+			cifs_sb->rsize = PAGE_CACHE_SIZE; 
+			/* Windows ME does this */
+			cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
 		}
 		cifs_sb->mnt_uid = volume_info.linux_uid;
 		cifs_sb->mnt_gid = volume_info.linux_gid;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 2d50b3507d13..34f0168c4041 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -215,8 +215,18 @@ int cifs_get_inode_info(struct inode **pinode,
 		pfindData = (FILE_ALL_INFO *)buf;
 		/* could do find first instead but this returns more info */
 		rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
-			      cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 
+			      cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
 				CIFS_MOUNT_MAP_SPECIAL_CHR);
+		/* BB optimize code so we do not make the above call
+		when server claims no NT SMB support and the above call
+		failed at least once - set flag in tcon or mount */
+		if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
+			rc = SMBQueryInformation(xid, pTcon, search_path,
+					pfindData, cifs_sb->local_nls, 
+					cifs_sb->mnt_cifs_flags &
+					  CIFS_MOUNT_MAP_SPECIAL_CHR);
+		}
+		
 	}
 	/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
 	if (rc) {
-- 
cgit v1.2.3


From a45443475835ab4d1c753159812aca21b5c333a3 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 24 Aug 2005 13:59:35 -0700
Subject: CIFS: Reduce CONFIG_CIFS_STATS ifdefs

Make cifs_stats code conditional in the header files to avoid ifdefs in the
main code.

Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifsglob.h | 28 +++++++++++++++++
 fs/cifs/cifssmb.c  | 88 +++++++++++++++---------------------------------------
 fs/cifs/file.c     | 34 ++++-----------------
 fs/cifs/misc.c     |  4 +--
 4 files changed, 58 insertions(+), 96 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index f143975627e0..9a3c85bdd77e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -339,6 +339,34 @@ static inline const char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
 		return '\\';
 }
 
+#ifdef CONFIG_CIFS_STATS
+#define cifs_stats_inc atomic_inc
+
+static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon,
+					    unsigned int bytes)
+{
+	if (bytes) {
+		spin_lock(&tcon->stat_lock);
+		tcon->bytes_written += bytes;
+		spin_unlock(&tcon->stat_lock);
+	}
+}
+
+static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
+					 unsigned int bytes)
+{
+	spin_lock(&tcon->stat_lock);
+	tcon->bytes_read += bytes;
+	spin_unlock(&tcon->stat_lock);
+}
+#else
+
+#define  cifs_stats_inc(field) do {} while(0)
+#define  cifs_stats_bytes_written(tcon, bytes) do {} while(0)
+#define  cifs_stats_bytes_read(tcon, bytes) do {} while(0)
+
+#endif
+
 /* one of these for every pending CIFS request to the server */
 struct mid_q_entry {
 	struct list_head qhead;	/* mids waiting on reply from this server */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 811ab3dffafa..698cdcebca04 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -166,11 +166,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 
 	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
 
-#ifdef CONFIG_CIFS_STATS
-        if(tcon != NULL) {
-                atomic_inc(&tcon->num_smbs_sent);
-        }
-#endif /* CONFIG_CIFS_STATS */
+        if(tcon != NULL)
+                cifs_stats_inc(&tcon->num_smbs_sent);
+
 	return rc;
 }  
 
@@ -269,11 +267,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
 			wct /*wct */ );
 
-#ifdef CONFIG_CIFS_STATS
-        if(tcon != NULL) {
-                atomic_inc(&tcon->num_smbs_sent);
-        }
-#endif /* CONFIG_CIFS_STATS */
+        if(tcon != NULL)
+                cifs_stats_inc(&tcon->num_smbs_sent);
+
 	return rc;
 }
 
@@ -584,9 +580,7 @@ DelFileRetry:
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_deletes);
-#endif
+	cifs_stats_inc(&tcon->num_deletes);
 	if (rc) {
 		cFYI(1, ("Error in RMFile = %d", rc));
 	} 
@@ -631,9 +625,7 @@ RmDirRetry:
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_rmdirs);
-#endif
+	cifs_stats_inc(&tcon->num_rmdirs);
 	if (rc) {
 		cFYI(1, ("Error in RMDir = %d", rc));
 	}
@@ -677,9 +669,7 @@ MkDirRetry:
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_mkdirs);
-#endif
+	cifs_stats_inc(&tcon->num_mkdirs);
 	if (rc) {
 		cFYI(1, ("Error in Mkdir = %d", rc));
 	}
@@ -767,9 +757,7 @@ openRetry:
 	/* 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, 1);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_opens);
-#endif
+	cifs_stats_inc(&tcon->num_opens);
 	if (rc) {
 		cFYI(1, ("Error in Open = %d", rc));
 	} else {
@@ -833,9 +821,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_reads);
-#endif 	
+	cifs_stats_inc(&tcon->num_reads);
 	if (rc) {
 		cERROR(1, ("Send error in read = %d", rc));
 	} else {
@@ -938,9 +924,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_writes);
-#endif
+	cifs_stats_inc(&tcon->num_writes);
 	if (rc) {
 		cFYI(1, ("Send error in write = %d", rc));
 		*nbytes = 0;
@@ -1013,9 +997,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 
 	rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
 			  buf, bytes_sent, &bytes_returned, long_op);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_writes);
-#endif
+	cifs_stats_inc(&tcon->num_writes);
 	if (rc) {
 		cFYI(1, ("Send error in write = %d", rc));
 		*nbytes = 0;
@@ -1091,9 +1073,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_locks);
-#endif
+	cifs_stats_inc(&tcon->num_locks);
 	if (rc) {
 		cFYI(1, ("Send error in Lock = %d", rc));
 	}
@@ -1127,9 +1107,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 	pSMB->ByteCount = 0;
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_closes);
-#endif 
+	cifs_stats_inc(&tcon->num_closes);
 	if (rc) {
 		if(rc!=-EINTR) {
 			/* EINTR is expected when user ctl-c to kill app */
@@ -1202,9 +1180,7 @@ renameRetry:
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_renames);
-#endif
+	cifs_stats_inc(&tcon->num_renames);
 	if (rc) {
 		cFYI(1, ("Send error in rename = %d", rc));
 	} 
@@ -1283,9 +1259,7 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&pTcon->num_t2renames);
-#endif 
+	cifs_stats_inc(&pTcon->num_t2renames);
 	if (rc) {
 		cFYI(1,("Send error in Rename (by file handle) = %d", rc));
 	}
@@ -1443,9 +1417,7 @@ createSymLinkRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_symlinks);
-#endif
+	cifs_stats_inc(&tcon->num_symlinks);
 	if (rc) {
 		cFYI(1,
 		     ("Send error in SetPathInfo (create symlink) = %d",
@@ -1535,9 +1507,7 @@ createHardLinkRetry:
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_hardlinks);
-#endif
+	cifs_stats_inc(&tcon->num_hardlinks);
 	if (rc) {
 		cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
 	}
@@ -1608,9 +1578,7 @@ winCreateHardLinkRetry:
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_hardlinks);
-#endif
+	cifs_stats_inc(&tcon->num_hardlinks);
 	if (rc) {
 		cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
 	}
@@ -2490,9 +2458,7 @@ findUniqueRetry:
 	if (rc) {
 		cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
 	} else {		/* decode response */
-#ifdef CONFIG_CIFS_STATS
-		atomic_inc(&tcon->num_ffirst);
-#endif
+		cifs_stats_inc(&tcon->num_ffirst);
 		/* BB fill in */
 	}
 
@@ -2592,9 +2558,7 @@ findFirstRetry:
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_ffirst);
-#endif
+	cifs_stats_inc(&tcon->num_ffirst);
 
 	if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
 		/* BB Add code to handle unsupported level rc */
@@ -2716,9 +2680,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                                                                                               
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_fnext);
-#endif                                                                                          
+	cifs_stats_inc(&tcon->num_fnext);
 	if (rc) {
 		if (rc == -EBADF) {
 			psrch_inf->endOfSearch = TRUE;
@@ -2795,9 +2757,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
 	if (rc) {
 		cERROR(1, ("Send error in FindClose = %d", rc));
 	}
-#ifdef CONFIG_CIFS_STATS
-	atomic_inc(&tcon->num_fclose);
-#endif
+	cifs_stats_inc(&tcon->num_fclose);
 	cifs_small_buf_release(pSMB);
 
 	/* Since session is dead, search handle closed on server already */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index b054df2dee1e..5857d12611e6 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -744,13 +744,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 				    15 seconds is plenty */
 	}
 
-#ifdef CONFIG_CIFS_STATS
-	if (total_written > 0) {
-		spin_lock(&pTcon->stat_lock);
-		pTcon->bytes_written += total_written;
-		spin_unlock(&pTcon->stat_lock);
-	}
-#endif		
+	cifs_stats_bytes_written(pTcon, total_written);
 
 	/* since the write may have blocked check these pointers again */
 	if (file->f_dentry) {
@@ -878,13 +872,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 				    15 seconds is plenty */
 	}
 
-#ifdef CONFIG_CIFS_STATS
-	if (total_written > 0) {
-		spin_lock(&pTcon->stat_lock);
-		pTcon->bytes_written += total_written;
-		spin_unlock(&pTcon->stat_lock);
-	}
-#endif		
+	cifs_stats_bytes_written(pTcon, total_written);
 
 	/* since the write may have blocked check these pointers again */
 	if (file->f_dentry) {
@@ -1245,11 +1233,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 				return rc;
 			}
 		} else {
-#ifdef CONFIG_CIFS_STATS
-			spin_lock(&pTcon->stat_lock);
-			pTcon->bytes_read += total_read;
-			spin_unlock(&pTcon->stat_lock);
-#endif
+			cifs_stats_bytes_read(pTcon, bytes_read);
 			*poffset += bytes_read;
 		}
 	}
@@ -1312,11 +1296,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 				return rc;
 			}
 		} else {
-#ifdef CONFIG_CIFS_STATS
-			spin_lock(&pTcon->stat_lock);
-			pTcon->bytes_read += total_read;
-			spin_unlock(&pTcon->stat_lock);
-#endif
+			cifs_stats_bytes_read(pTcon, total_read);
 			*poffset += bytes_read;
 		}
 	}
@@ -1488,11 +1468,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 				le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
 
 			i +=  bytes_read >> PAGE_CACHE_SHIFT;
-#ifdef CONFIG_CIFS_STATS
-			spin_lock(&pTcon->stat_lock);
-			pTcon->bytes_read += bytes_read;
-			spin_unlock(&pTcon->stat_lock);
-#endif
+			cifs_stats_bytes_read(pTcon, bytes_read);
 			if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
 				i++; /* account for partial page */
 
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 40d50b77bfe7..fafbdbfa63a1 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -520,9 +520,7 @@ is_valid_oplock_break(struct smb_hdr *buf)
 	list_for_each(tmp, &GlobalTreeConnectionList) {
 		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
 		if (tcon->tid == buf->Tid) {
-#ifdef CONFIG_CIFS_STATS
-			atomic_inc(&tcon->num_oplock_brks);
-#endif
+			cifs_stats_inc(&tcon->num_oplock_brks);
 			list_for_each(tmp1,&tcon->openFileList){
 				netfile = list_entry(tmp1,struct cifsFileInfo,
 						     tlist);
-- 
cgit v1.2.3


From c0c3e8edaabcb6cf6786226813cf087ad21f0743 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 24 Aug 2005 14:01:13 -0700
Subject: CIFS: Fix typos in fs/cifs/CHANGES

Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/CHANGES | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 299ed312cea5..340b4ffb3493 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,6 +1,6 @@
 Version 1.36
 ------------
-Add support for moounting to older pre-CIFS servers such as Windows9x and ME.
+Add support for mounting to older pre-CIFS servers such as Windows9x and ME.
 For these older servers, add option for passing netbios name of server in
 on mount (servernetbiosname).
 Add mount option for disabling the default behavior of sending byte range lock
@@ -26,7 +26,7 @@ Do not oops if root user kills cifs oplock kernel thread or
 kills the cifsd thread (NB: killing the cifs kernel threads is not
 recommended, unmount and rmmod cifs will kill them when they are
 no longer needed).  Fix readdir to ASCII servers (ie older servers
-which do not support Unicode) and also require asterik.
+which do not support Unicode) and also require asterisk.
 Fix out of memory case in which data could be written one page
 off in the page cache.
 
@@ -116,7 +116,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call.
 
 Version 1.25
 ------------
-Fix internationlization problem in cifs readdir with filenames that map to 
+Fix internationalization problem in cifs readdir with filenames that map to 
 longer UTF8 strings than the string on the wire was in Unicode.  Add workaround
 for readdir to netapp servers. Fix search rewind (seek into readdir to return 
 non-consecutive entries).  Do not do readdir when server negotiates 
@@ -291,7 +291,7 @@ Fix caching problem when files opened by multiple clients in which
 page cache could contain stale data, and write through did
 not occur often enough while file was still open when read ahead
 (read oplock) not allowed.  Treat "sep=" when first mount option
-as an overrride of comma as the default separator between mount
+as an override of comma as the default separator between mount
 options. 
 
 Version 1.01
@@ -301,7 +301,7 @@ Allow passwords longer than 16 bytes. Allow null password string.
 Version 1.00
 ------------
 Gracefully clean up failed mounts when attempting to mount to servers such as
-Windows 98 that terminate tcp sessions during prototocol negotiation.  Handle
+Windows 98 that terminate tcp sessions during protocol negotiation.  Handle
 embedded commas in mount parsing of passwords.
 
 Version 0.99
@@ -310,7 +310,7 @@ Invalidate local inode cached pages on oplock break and when last file
 instance is closed so that the client does not continue using stale local
 copy rather than later modified server copy of file.  Do not reconnect
 when server drops the tcp session prematurely before negotiate
-protocol response.  Fix oops in roepen_file when dentry freed.  Allow
+protocol response.  Fix oops in reopen_file when dentry freed.  Allow
 the support for CIFS Unix Extensions to be disabled via proc interface.
 
 Version 0.98
@@ -652,7 +652,7 @@ versions of 2.4 kernel (now builds and works again on kernels at least as early
 Version 0.41
 ------------
 Various minor fixes for Connectathon Posix "basic" file i/o test suite.  Directory caching fixed so hardlinked
-files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked.
+files now return the correct number of links on fstat as they are repeatedly linked and unlinked.
 
 Version 0.40
 ------------
@@ -719,7 +719,7 @@ session)
 and cleaned them up and made them more consistent with other cifs functions. 
 
 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways 
-(with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
+(with or without Unix extensions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
 nor is the symlink support using the Unix extensions
 
 8) Started adding the readlink and follow_link code 
-- 
cgit v1.2.3


From e2a98a7543696306346ba8302a8df6cedf20fdfc Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 24 Aug 2005 14:43:14 -0700
Subject: [CIFS] Update thanks/contributor list with Miklos Szeredi
 (Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> also should have been
 listed on the last cifs patch fixing some lookup intent handling in cifs)

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/AUTHORS | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
index 72fdc10dfdd7..8848e4dfa026 100644
--- a/fs/cifs/AUTHORS
+++ b/fs/cifs/AUTHORS
@@ -32,6 +32,10 @@ Domen Puncer
 Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
 Vince Negri and Dave Stahl (for finding an important caching bug)
 Adrian Bunk (kcalloc cleanups)
+Miklos Szeredi 
+Kazeon team for various fixes especially for 2.4 version.
+Asser Ferno (Change Notify support)
+Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
 
 Test case and Bug Report contributors
 -------------------------------------
-- 
cgit v1.2.3


From ff5dbd9ead0d82466cab8bdbdcbc9666707d328a Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 24 Aug 2005 17:10:36 -0700
Subject: [CIFS] Change notify support part 2

Signed-off-by: Asser Ferno <asser@diku.dk>
Signed-off-by: Steve French <sfrench@us.ibm.com> and lightly modified
---
 fs/cifs/cifsglob.h | 17 +++++++++++++++++
 fs/cifs/cifspdu.h  |  1 +
 fs/cifs/cifssmb.c  | 16 ++++++++++++++++
 3 files changed, 34 insertions(+)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 9a3c85bdd77e..92fba7609e67 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -391,6 +391,20 @@ struct oplock_q_entry {
 	__u16 netfid;
 };
 
+/* for pending dnotify requests */
+struct dir_notify_req {
+       struct list_head lhead;
+       __le16 Pid;
+       __le16 PidHigh;
+       __u16 Mid;
+       __u16 Tid;
+       __u16 Uid;
+       __u16 netfid;
+       __u32 filter; /* CompletionFilter (for multishot) */
+       int multishot;
+       struct dentry * dentry;
+};
+
 #define   MID_FREE 0
 #define   MID_REQUEST_ALLOCATED 1
 #define   MID_REQUEST_SUBMITTED 2
@@ -459,6 +473,9 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;  /* protects list inserts on 3 above */
 
 GLOBAL_EXTERN struct list_head GlobalOplock_Q;
 
+GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */
+GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */
+
 /*
  * Global transaction id (XID) information
  */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 42c16cf32284..026c88f486a2 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -53,6 +53,7 @@
 #define SMB_COM_NT_TRANSACT           0xA0
 #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
 #define SMB_COM_NT_CREATE_ANDX        0xA2
+#define SMB_COM_NT_CANCEL             0xA4 /* no response */
 #define SMB_COM_NT_RENAME             0xA5 /* trivial response */
 
 /* Transact2 subcommand codes */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 698cdcebca04..36d45b1dffc2 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -4015,6 +4015,22 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
 			(struct smb_hdr *) pSMBr, &bytes_returned, -1);
 	if (rc) {
 		cFYI(1, ("Error in Notify = %d", rc));
+	} else {
+		/* Add file to outstanding requests */
+		dnotify_req = (struct dir_notify_req *) kmalloc(
+						sizeof(struct dir_notify_req), GFP_KERNEL);
+		dnotify_req->Pid = pSMB->hdr.Pid;
+		dnotify_req->PidHigh = pSMB->hdr.PidHigh;
+		dnotify_req->Mid = pSMB->hdr.Mid;
+		dnotify_req->Tid = pSMB->hdr.Tid;
+		dnotify_req->Uid = pSMB->hdr.Uid;
+		dnotify_req->netfid = netfid;
+		dnotify_req->dentry = dentry;
+		dnotify_req->filter = filter;
+		dnotify_req->multishot = multishot;
+		spin_lock(&GlobalMid_Lock);
+		list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList);
+		spin_unlock(&GlobalMid_Lock);
 	}
 	cifs_buf_release(pSMB);
 	return rc;	
-- 
cgit v1.2.3


From abb15b8ae4eb7cdff0061e7ac5eca1f8dd8a84af Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 24 Aug 2005 18:51:02 -0700
Subject: [CIFS] Missing line from previous patch

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifssmb.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 36d45b1dffc2..be2a3b9a718c 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3983,6 +3983,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
 	int rc = 0;
 	struct smb_com_transaction_change_notify_req * pSMB = NULL;
 	struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
+	struct dir_notify_req *dnotify_req;
 	int bytes_returned;
 
 	cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
-- 
cgit v1.2.3


From 167a251ad6678ad26aa3cf27bab677b274374ab6 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 24 Aug 2005 20:03:11 -0700
Subject: [CIFS] Change notify support part 3

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifsglob.h  | 2 +-
 fs/cifs/cifsproto.h | 3 ++-
 fs/cifs/cifssmb.c   | 7 ++++---
 fs/cifs/fcntl.c     | 8 +++++---
 4 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 92fba7609e67..236de07cbda6 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -402,7 +402,7 @@ struct dir_notify_req {
        __u16 netfid;
        __u32 filter; /* CompletionFilter (for multishot) */
        int multishot;
-       struct dentry * dentry;
+       struct file * dentry;
 };
 
 #define   MID_FREE 0
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0cc0612eacb4..28b1ebbd3801 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -275,7 +275,8 @@ extern int CIFSSMBCopy(int xid,
 			int remap_special_chars);
 extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
 			const int notify_subdirs,const __u16 netfid,
-			__u32 filter, const struct nls_table *nls_codepage);
+			__u32 filter, struct file * file, int multishot, 
+			const struct nls_table *nls_codepage);
 extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName, char * EAData,
 			size_t bufsize, const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index be2a3b9a718c..67a6240ff2ba 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3977,8 +3977,9 @@ setPermsRetry:
 }
 
 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
-			const int notify_subdirs, const __u16 netfid,
-			__u32 filter, const struct nls_table *nls_codepage)
+		  const int notify_subdirs, const __u16 netfid,
+		  __u32 filter, struct file * pfile, int multishot, 
+		  const struct nls_table *nls_codepage)
 {
 	int rc = 0;
 	struct smb_com_transaction_change_notify_req * pSMB = NULL;
@@ -4026,7 +4027,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
 		dnotify_req->Tid = pSMB->hdr.Tid;
 		dnotify_req->Uid = pSMB->hdr.Uid;
 		dnotify_req->netfid = netfid;
-		dnotify_req->dentry = dentry;
+		dnotify_req->pfile = pfile;
 		dnotify_req->filter = filter;
 		dnotify_req->multishot = multishot;
 		spin_lock(&GlobalMid_Lock);
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
index d47ce7f49dc3..2e5137b7352a 100644
--- a/fs/cifs/fcntl.c
+++ b/fs/cifs/fcntl.c
@@ -100,8 +100,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
 		} else {
 			filter = convert_to_cifs_notify_flags(arg);
 			if(filter != 0) {
-				rc = CIFSSMBNotify(xid, pTcon, 0 /* no subdirs */, netfid, 
-					filter, cifs_sb->local_nls);
+				rc = CIFSSMBNotify(xid, pTcon, 
+					0 /* no subdirs */, netfid,
+					filter, file, arg & DN_MULTISHOT,
+					cifs_sb->local_nls);
 			} else {
 				rc = -EINVAL;
 			}
@@ -109,7 +111,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
 			it would close automatically but may be a way
 			to do it easily when inode freed or when
 			notify info is cleared/changed */
-            cERROR(1,("notify rc %d",rc));
+			cFYI(1,("notify rc %d",rc));
 		}
 	}
 	
-- 
cgit v1.2.3


From e22cb8bcb8bce94bf5cca90c98933a28816c6a75 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 24 Aug 2005 20:25:21 -0700
Subject: [CIFS] Use file instead of dentry in cifs dir_notify struct

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifsglob.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 236de07cbda6..a9c791edede5 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -402,7 +402,7 @@ struct dir_notify_req {
        __u16 netfid;
        __u32 filter; /* CompletionFilter (for multishot) */
        int multishot;
-       struct file * dentry;
+       struct file * pfile;
 };
 
 #define   MID_FREE 0
-- 
cgit v1.2.3


From a9d02ad49013c8fc527f06ca66417103cdbb08b6 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 24 Aug 2005 23:06:05 -0700
Subject: [CIFS] Support for legacy servers part 3 - Add support for Open and
 most of Read support.

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifspdu.h   |  73 ++++++++++++++++++
 fs/cifs/cifsproto.h |   8 ++
 fs/cifs/cifssmb.c   | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/dir.c       |   7 ++
 fs/cifs/file.c      |  29 ++++++-
 5 files changed, 330 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 026c88f486a2..cf466595b0d4 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -40,6 +40,7 @@
 #define SMB_COM_SETATTR               0x09 /* trivial response */
 #define SMB_COM_LOCKING_ANDX          0x24 /* trivial response */
 #define SMB_COM_COPY                  0x29 /* trivial rsp, fail filename ignrd*/
+#define SMB_COM_OPEN_ANDX             0x2D /* Legacy open for old servers */
 #define SMB_COM_READ_ANDX             0x2E
 #define SMB_COM_WRITE_ANDX            0x2F
 #define SMB_COM_TRANSACTION2          0x32
@@ -625,6 +626,7 @@ typedef struct smb_com_findclose_req {
 } FINDCLOSE_REQ;
 
 /* OpenFlags */
+#define REQ_MORE_INFO      0x00000001  /* legacy (OPEN_AND_X) only */
 #define REQ_OPLOCK         0x00000002
 #define REQ_BATCHOPLOCK    0x00000004
 #define REQ_OPENDIRONLY    0x00000008
@@ -680,6 +682,62 @@ typedef struct smb_com_open_rsp {
 	__u16 ByteCount;	/* bct = 0 */
 } OPEN_RSP;
 
+/* format of legacy open request */
+typedef struct smb_com_openx_req {
+	struct smb_hdr	hdr;	/* wct = 15 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__le16 AndXOffset;
+	__le16 OpenFlags;
+	__le16 Mode;
+	__le16 Sattr; /* search attributes */
+	__le16 FileAttributes;  /* dos attrs */
+	__le32 CreateTime; /* os2 format */
+	__le16 OpenFunction;
+	__le32 EndOfFile;
+	__le32 Timeout;
+	__le32 Reserved;
+	__u16  ByteCount;  /* file name follows */
+	char   fileName[1];
+} OPENX_REQ;
+
+typedef struct smb_com_openx_rsp {
+	struct smb_hdr	hdr;	/* wct = 15 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__le16 AndXOffset;
+	__u16  Fid;
+	__le16 FileAttributes;
+	__le32 LastWriteTime; /* os2 format */
+	__le32 EndOfFile;
+	__le16 Access;
+	__le16 FileType;
+	__le16 IPCState;
+	__le16 Action;
+	__u32  FileId;
+	__u16  Reserved;
+	__u16  ByteCount;
+} OPENX_RSP; 
+
+/* Legacy write request for older servers */
+typedef struct smb_com_writex_req {
+        struct smb_hdr hdr;     /* wct = 12 */
+        __u8 AndXCommand;
+        __u8 AndXReserved;
+        __le16 AndXOffset;
+        __u16 Fid;
+        __le32 OffsetLow;
+        __u32 Reserved; /* Timeout */
+        __le16 WriteMode; /* 1 = write through */
+        __le16 Remaining;
+        __le16 Reserved2;
+        __le16 DataLengthLow;
+        __le16 DataOffset;
+        __le16 ByteCount;
+        __u8 Pad;               /* BB check for whether padded to DWORD boundary and optimum performance here */
+        char Data[0];
+} WRITEX_REQ;
+
 typedef struct smb_com_write_req {
 	struct smb_hdr hdr;	/* wct = 14 */
 	__u8 AndXCommand;
@@ -711,6 +769,21 @@ typedef struct smb_com_write_rsp {
 	__u16 ByteCount;
 } WRITE_RSP;
 
+/* legacy read request for older servers */
+typedef struct smb_com_readx_req {
+        struct smb_hdr hdr;     /* wct = 10 */
+        __u8 AndXCommand;
+        __u8 AndXReserved;
+        __le16 AndXOffset;
+        __u16 Fid;
+        __le32 OffsetLow;
+        __le16 MaxCount;
+        __le16 MinCount;                /* obsolete */
+        __le32 Reserved;
+        __le16 Remaining;
+        __le16 ByteCount;
+} READX_REQ;
+
 typedef struct smb_com_read_req {
 	struct smb_hdr hdr;	/* wct = 12 */
 	__u8 AndXCommand;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 28b1ebbd3801..c411f2e001aa 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -218,9 +218,17 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
 			const int access_flags, const int omode,
 			__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
 			const struct nls_table *nls_codepage, int remap);
+extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
+			const char *fileName, const int disposition,
+			const int access_flags, const int omode,
+			__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
+			const struct nls_table *nls_codepage, int remap);
 extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
 			const int smb_file_id);
 
+extern int SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
+			const int netfid, unsigned int count,
+			const __u64 lseek, unsigned int *nbytes, char **buf);
 extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 			const int netfid, unsigned int count,
 			const __u64 lseek, unsigned int *nbytes, char **buf);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 67a6240ff2ba..c8ae3ef422ba 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -680,6 +680,146 @@ MkDirRetry:
 	return rc;
 }
 
+static __u16 convert_disposition(int disposition)
+{
+	__u16 ofun = 0;
+
+	switch (disposition) {
+		case FILE_SUPERSEDE:
+			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
+			break;
+		case FILE_OPEN:
+			ofun = SMBOPEN_OAPPEND;
+			break;
+		case FILE_CREATE:
+			ofun = SMBOPEN_OCREATE;
+			break;
+		case FILE_OPEN_IF:
+			ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
+			break;
+		case FILE_OVERWRITE:
+			ofun = SMBOPEN_OTRUNC;
+			break;
+		case FILE_OVERWRITE_IF:
+			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
+			break;
+		default:
+			cFYI(1,("unknown disposition %d",disposition));
+			ofun =  SMBOPEN_OAPPEND; /* regular open */
+	}
+	return ofun;
+}
+
+int
+SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
+	    const char *fileName, const int openDisposition,
+	    const int access_flags, const int create_options, __u16 * netfid,
+            int *pOplock, FILE_ALL_INFO * pfile_info,
+	    const struct nls_table *nls_codepage, int remap)
+{
+	int rc = -EACCES;
+	OPENX_REQ *pSMB = NULL;
+	OPENX_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len;
+	__u16 count;
+
+OldOpenRetry:
+	rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->AndXCommand = 0xFF;       /* none */
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		count = 1;      /* account for one byte pad to word boundary */
+		name_len =
+		   cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
+				    fileName, PATH_MAX, nls_codepage, remap);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+	} else {                /* BB improve check for buffer overruns BB */
+		count = 0;      /* no pad */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->fileName, fileName, name_len);
+	}
+	if (*pOplock & REQ_OPLOCK)
+		pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
+	else if (*pOplock & REQ_BATCHOPLOCK) {
+		pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
+	}
+	pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
+	/* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
+	/* 0 = read
+	   1 = write
+	   2 = rw
+	   3 = execute
+        */
+	pSMB->Mode = cpu_to_le16(2);
+	pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
+	/* set file as system file if special file such
+	   as fifo and server expecting SFU style and
+	   no Unix extensions */
+
+        if(create_options & CREATE_OPTION_SPECIAL)
+                pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
+        else
+                pSMB->FileAttributes = cpu_to_le16(ATTR_NORMAL);
+
+	/* if ((omode & S_IWUGO) == 0)
+		pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
+	/*  Above line causes problems due to vfs splitting create into two
+	    pieces - need to set mode after file created not while it is
+	    being created */
+
+	/* BB FIXME BB */
+/*	pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
+	/* BB FIXME END BB */
+	pSMB->OpenFunction = convert_disposition(openDisposition);
+	count += name_len;
+	pSMB->hdr.smb_buf_length += count;
+
+	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, 1);
+	cifs_stats_inc(&tcon->num_opens);
+	if (rc) {
+		cFYI(1, ("Error in Open = %d", rc));
+	} else {
+	/* BB verify if wct == 15 */
+
+/*		*pOplock = pSMBr->OplockLevel; */  /* BB take from action field BB */
+
+		*netfid = pSMBr->Fid;   /* cifs fid stays in le */
+		/* Let caller know file was created so we can set the mode. */
+		/* Do we care about the CreateAction in any other cases? */
+	/* BB FIXME BB */
+/*		if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+			*pOplock |= CIFS_CREATE_ACTION; */
+	/* BB FIXME END */
+
+		if(pfile_info) {
+			pfile_info->CreationTime = 0; /* BB convert CreateTime*/
+			pfile_info->LastAccessTime = 0; /* BB fixme */
+			pfile_info->LastWriteTime = 0; /* BB fixme */
+			pfile_info->ChangeTime = 0;  /* BB fixme */
+			pfile_info->Attributes = pSMBr->FileAttributes; 
+			/* the file_info buf is endian converted by caller */
+			pfile_info->AllocationSize = pSMBr->EndOfFile;
+			pfile_info->EndOfFile = pSMBr->EndOfFile;
+			pfile_info->NumberOfLinks = cpu_to_le32(1);
+		}
+	}
+
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto OldOpenRetry;
+	return rc;
+}
+
 int
 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
 	    const char *fileName, const int openDisposition,
@@ -783,6 +923,81 @@ openRetry:
 	return rc;
 }
 
+int
+SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
+            const int netfid, unsigned int count,
+            const __u64 lseek, unsigned int *nbytes, char **buf)
+{
+	int rc = -EACCES;
+	READX_REQ *pSMB = NULL;
+	READ_RSP *pSMBr = NULL;
+	char *pReadData = NULL;
+	int bytes_returned;
+
+	cFYI(1,("Legacy read %d bytes fid %d",count,netfid));
+
+	/* field is shorter in legacy read, only 16 bits */
+	if(count > 2048)
+		count = 2048;  /* BB FIXME make this configurable */
+
+	if(lseek > 0xFFFFFFFF)
+		return -EIO; /* can not read that far into file on old server */
+
+	*nbytes = 0;
+	rc = smb_init(SMB_COM_READ_ANDX, 10, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	/* tcon and ses pointer are checked in smb_init */
+	if (tcon->ses->server == NULL)
+		return -ECONNABORTED;
+
+	pSMB->AndXCommand = 0xFF;       /* none */
+	pSMB->Fid = netfid;
+	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
+	pSMB->Remaining = 0;
+	pSMB->MaxCount = cpu_to_le16(count);
+	pSMB->Reserved = 0; /* Must Be Zero */
+	pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_reads);
+	if (rc) {
+		cERROR(1, ("Send error in legacy read = %d", rc));
+	} else {
+		int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
+		data_length = data_length << 16;
+		data_length += le16_to_cpu(pSMBr->DataLength);
+		*nbytes = data_length;
+
+		/*check that DataLength would not go beyond end of SMB */
+		if ((data_length > CIFSMaxBufSize) || (data_length > count)) {
+			cFYI(1,("bad length %d for count %d",data_length,count));
+			rc = -EIO;
+			*nbytes = 0;
+		} else {
+			pReadData = (char *) (&pSMBr->hdr.Protocol) +
+						le16_to_cpu(pSMBr->DataOffset);
+/*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
+			 	cERROR(1,("Faulting on read rc = %d",rc));
+				rc = -EFAULT;
+			}*/ /* can not use copy_to_user when using page cache*/
+			if(*buf)
+				memcpy(*buf,pReadData,data_length);
+		}
+	}
+	if(*buf)
+		cifs_buf_release(pSMB);
+	else
+		*buf = (char *)pSMB;
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls
+		since file handle passed in no longer valid */
+	return rc;
+}
+
 /* If no buffer passed in, then caller wants to do the copy
 	as in the case of readpages so the SMB buffer must be
 	freed by the caller */
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 5311c50734b0..248ddebd67f4 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -184,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 			 desiredAccess, CREATE_NOT_DIR,
 			 &fileHandle, &oplock, buf, cifs_sb->local_nls,
 			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if(rc == -EIO) {
+		/* old server, retry the open legacy style */
+		rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
+			desiredAccess, CREATE_NOT_DIR,
+			&fileHandle, &oplock, buf, cifs_sb->local_nls,
+			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	} 
 	if (rc) {
 		cFYI(1, ("cifs_create returned 0x%x ", rc));
 	} else {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 5857d12611e6..8ae962e7c93f 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -256,6 +256,13 @@ int cifs_open(struct inode *inode, struct file *file)
 			 CREATE_NOT_DIR, &netfid, &oplock, buf,
 			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
 				 & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if (rc == -EIO) {
+		/* Old server, try legacy style OpenX */
+		rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
+			desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
+			cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+				& CIFS_MOUNT_MAP_SPECIAL_CHR);
+	}
 	if (rc) {
 		cFYI(1, ("cifs_open returned 0x%x ", rc));
 		goto out;
@@ -1210,7 +1217,12 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 				 open_file->netfid,
 				 current_read_size, *poffset,
 				 &bytes_read, &smb_read_data);
-
+			if(rc == -EINVAL) {
+				rc = SMBLegacyRead(xid, pTcon,
+					open_file->netfid,
+					current_read_size, *poffset,
+					&bytes_read, &smb_read_data);
+			}
 			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
 			if (copy_to_user(current_offset, 
 					 smb_read_data + 4 /* RFC1001 hdr */
@@ -1287,6 +1299,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 				 open_file->netfid,
 				 current_read_size, *poffset,
 				 &bytes_read, &current_offset);
+			if(rc == -EINVAL) {
+				rc = SMBLegacyRead(xid, pTcon,
+					open_file->netfid,
+					current_read_size, *poffset,
+					&bytes_read, &current_offset);
+			}
 		}
 		if (rc || (bytes_read == 0)) {
 			if (total_read) {
@@ -1443,7 +1461,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 				open_file->netfid,
 				read_size, offset,
 				&bytes_read, &smb_read_data);
-			/* BB need to check return code here */
+			if (rc == -EINVAL) {
+				rc = SMBLegacyRead(xid, pTcon,
+					open_file->netfid,
+					read_size, offset,
+					&bytes_read, &smb_read_data);
+			}
+
+			/* BB more RC checks ? */
 			if (rc== -EAGAIN) {
 				if (smb_read_data) {
 					cifs_buf_release(smb_read_data);
-- 
cgit v1.2.3


From 7f57356b70dda014ef269135942426e4a852023e Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 30 Aug 2005 11:32:14 -0700
Subject: [CIFS] Remove cifs_sb argument from *build_path_from_dentry

This argument was added in a recent patch, but is unnecessary, since
the superblock is easily obtained from the dentry.

Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifsproto.h |  2 +-
 fs/cifs/dir.c       | 11 ++++++-----
 fs/cifs/fcntl.c     |  2 +-
 fs/cifs/file.c      |  4 ++--
 fs/cifs/inode.c     | 14 +++++++-------
 fs/cifs/link.c      | 15 +++++++--------
 fs/cifs/readdir.c   |  2 +-
 fs/cifs/xattr.c     |  8 ++++----
 8 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c411f2e001aa..656b78ddf674 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -40,7 +40,7 @@ extern unsigned int _GetXid(void);
 extern void _FreeXid(unsigned int);
 #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid));
 #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));}
-extern char *build_path_from_dentry(struct dentry *, const struct cifs_sb_info *cifs_sb);
+extern char *build_path_from_dentry(struct dentry *);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 extern void renew_parental_timestamps(struct dentry *direntry);
 extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 248ddebd67f4..cf90c9ad2c87 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -43,11 +43,12 @@ renew_parental_timestamps(struct dentry *direntry)
 
 /* Note: caller must free return buffer */
 char *
-build_path_from_dentry(struct dentry *direntry, const struct cifs_sb_info *cifs_sb)
+build_path_from_dentry(struct dentry *direntry)
 {
 	struct dentry *temp;
 	int namelen = 0;
 	char *full_path;
+	char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
 
 	if(direntry == NULL)
 		return NULL;  /* not much we can do if dentry is freed and
@@ -74,7 +75,7 @@ cifs_bp_rename_retry:
 		if (namelen < 0) {
 			break;
 		} else {
-			full_path[namelen] = CIFS_DIR_SEP(cifs_sb);
+			full_path[namelen] = dirsep;
 			strncpy(full_path + namelen + 1, temp->d_name.name,
 				temp->d_name.len);
 			cFYI(0, (" name: %s ", full_path + namelen));
@@ -138,7 +139,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 	pTcon = cifs_sb->tcon;
 
 	down(&direntry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&direntry->d_sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
@@ -310,7 +311,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
 	pTcon = cifs_sb->tcon;
 
 	down(&direntry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&direntry->d_sb->s_vfs_rename_sem);
 	if(full_path == NULL)
 		rc = -ENOMEM;
@@ -409,7 +410,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
 	/* can not grab the rename sem here since it would
 	deadlock in the cases (beginning of sys_rename itself)
 	in which we already have the sb rename sem */
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	if(full_path == NULL) {
 		FreeXid(xid);
 		return ERR_PTR(-ENOMEM);
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
index 2e5137b7352a..d527e2c76073 100644
--- a/fs/cifs/fcntl.c
+++ b/fs/cifs/fcntl.c
@@ -83,7 +83,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
 	pTcon = cifs_sb->tcon;
 
 	down(&file->f_dentry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
+	full_path = build_path_from_dentry(file->f_dentry);
 	up(&file->f_dentry->d_sb->s_vfs_rename_sem);
 
 	if(full_path == NULL) {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 8ae962e7c93f..026b5c5ccc89 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -196,7 +196,7 @@ int cifs_open(struct inode *inode, struct file *file)
 	}
 
 	down(&inode->i_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
+	full_path = build_path_from_dentry(file->f_dentry);
 	up(&inode->i_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
@@ -366,7 +366,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
    those that already have the rename sem can end up causing writepage
    to get called and if the server was down that means we end up here,
    and we can never tell if the caller already has the rename_sem */
-	full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
+	full_path = build_path_from_dentry(file->f_dentry);
 	if (full_path == NULL) {
 		up(&pCifsFile->fh_sem);
 		FreeXid(xid);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 34f0168c4041..0485c6d6ecd5 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -436,7 +436,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
 	/* Unlink can be called from rename so we can not grab the sem here
 	   since we deadlock otherwise */
 /*	down(&direntry->d_sb->s_vfs_rename_sem);*/
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 /*	up(&direntry->d_sb->s_vfs_rename_sem);*/
 	if (full_path == NULL) {
 		FreeXid(xid);
@@ -580,7 +580,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 	pTcon = cifs_sb->tcon;
 
 	down(&inode->i_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&inode->i_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
@@ -654,7 +654,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 	pTcon = cifs_sb->tcon;
 
 	down(&inode->i_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&inode->i_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
@@ -707,8 +707,8 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
 
 	/* we already  have the rename sem so we do not need to grab it again
 	   here to protect the path integrity */
-	fromName = build_path_from_dentry(source_direntry, cifs_sb_source);
-	toName = build_path_from_dentry(target_direntry, cifs_sb_target);
+	fromName = build_path_from_dentry(source_direntry);
+	toName = build_path_from_dentry(target_direntry);
 	if ((fromName == NULL) || (toName == NULL)) {
 		rc = -ENOMEM;
 		goto cifs_rename_exit;
@@ -824,7 +824,7 @@ int cifs_revalidate(struct dentry *direntry)
 
 	/* can not safely grab the rename sem here if rename calls revalidate
 	   since that would deadlock */
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
@@ -973,7 +973,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 	pTcon = cifs_sb->tcon;
 
 	down(&direntry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&direntry->d_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index b8ec6646456a..b43e071fe110 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -49,8 +49,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
    BB note DFS case in future though (when we may have to check) */
 
 	down(&inode->i_sb->s_vfs_rename_sem);
-	fromName = build_path_from_dentry(old_file, cifs_sb_target);
-	toName = build_path_from_dentry(direntry, cifs_sb_target);
+	fromName = build_path_from_dentry(old_file);
+	toName = build_path_from_dentry(direntry);
 	up(&inode->i_sb->s_vfs_rename_sem);
 	if((fromName == NULL) || (toName == NULL)) {
 		rc = -ENOMEM;
@@ -105,17 +105,16 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 
 	xid = GetXid();
 
-	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb->tcon;
-
 	down(&direntry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&direntry->d_sb->s_vfs_rename_sem);
 
 	if (!full_path)
 		goto out_no_free;
 
 	cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
 	target_path = kmalloc(PATH_MAX, GFP_KERNEL);
 	if (!target_path) {
 		target_path = ERR_PTR(-ENOMEM);
@@ -168,7 +167,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
 	pTcon = cifs_sb->tcon;
 
 	down(&inode->i_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&inode->i_sb->s_vfs_rename_sem);
 
 	if(full_path == NULL) {
@@ -237,7 +236,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
 /* BB would it be safe against deadlock to grab this sem 
       even though rename itself grabs the sem and calls lookup? */
 /*       down(&inode->i_sb->s_vfs_rename_sem);*/
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 /*       up(&inode->i_sb->s_vfs_rename_sem);*/
 
 	if(full_path == NULL) {
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index f769292e2a93..9780f4ee7f12 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -368,7 +368,7 @@ static int initiate_cifs_search(const int xid, struct file *file)
 		return -EINVAL;
 
 	down(&file->f_dentry->d_sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
+	full_path = build_path_from_dentry(file->f_dentry);
 	up(&file->f_dentry->d_sb->s_vfs_rename_sem);
 
 	if(full_path == NULL) {
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index f4fc8ddebba7..c1e02eff1d25 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -63,7 +63,7 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name)
 	pTcon = cifs_sb->tcon;
                                                                                      
 	down(&sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
@@ -118,7 +118,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
 	pTcon = cifs_sb->tcon;
 
 	down(&sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
@@ -227,7 +227,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
 	pTcon = cifs_sb->tcon;
 
 	down(&sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
@@ -328,7 +328,7 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
 	pTcon = cifs_sb->tcon;
 
 	down(&sb->s_vfs_rename_sem);
-	full_path = build_path_from_dentry(direntry, cifs_sb);
+	full_path = build_path_from_dentry(direntry);
 	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
-- 
cgit v1.2.3


From 16abbecdad3367c76c12537450eba0d86943fe2c Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 30 Aug 2005 13:10:14 -0700
Subject: [CIFS] Add support for suspend

cifsd had been preventing software suspend from completing.

Signed-off-by: pavel@suse.de
Signed-off-by: Steve French <sfrench@us.ibm.com>  lightly modified
---

 fs/cifs/CHANGES   |    3 ++-
 fs/cifs/cifsfs.c  |    4 ++++
 fs/cifs/connect.c |    2 ++
 3 files changed, 8 insertions(+), 1 deletions(-)
---
 fs/cifs/CHANGES   | 3 ++-
 fs/cifs/cifsfs.c  | 4 ++++
 fs/cifs/connect.c | 2 ++
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 340b4ffb3493..6c73f020ef40 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -2,7 +2,8 @@ Version 1.36
 ------------
 Add support for mounting to older pre-CIFS servers such as Windows9x and ME.
 For these older servers, add option for passing netbios name of server in
-on mount (servernetbiosname).
+on mount (servernetbiosname).  Add suspend support for power management, to
+avoid cifsd thread preventing software suspend from working.
 Add mount option for disabling the default behavior of sending byte range lock
 requests to the server (necessary for certain applications which break with
 mandatory lock behavior such as Evolution), and also mount option for
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index d77abe236a67..43fb2aafa528 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -784,6 +784,8 @@ static int cifs_oplock_thread(void * dummyarg)
 
 	oplockThread = current;
 	do {
+		if(try_to_freeze()) 
+			continue;
 		set_current_state(TASK_INTERRUPTIBLE);
 		
 		schedule_timeout(1*HZ);  
@@ -848,6 +850,8 @@ static int cifs_dnotify_thread(void * dummyarg)
 
 	dnotifyThread = current;
 	do {
+		if(try_to_freeze())
+			continue;
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(39*HZ);
 	} while(!signal_pending(current));
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c75bae1242dc..134195cc4073 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -355,6 +355,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 	}
 
 	while (server->tcpStatus != CifsExiting) {
+		if(try_to_freeze())
+			continue;
 		if (bigbuf == NULL) {
 			bigbuf = cifs_buf_get();
 			if(bigbuf == NULL) {
-- 
cgit v1.2.3


From cb8be64084e6294fcb9e558188fe104050b94f0b Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 30 Aug 2005 15:25:52 -0700
Subject: [CIFS] Add nolock synonym (ala nfs) for nobrl to disable sending byte
 range locks remotely.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/connect.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 134195cc4073..f784b70abfeb 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1078,7 +1078,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                         vol->nocase = 1;
 		} else if (strnicmp(data, "brl", 3) == 0) {
 			vol->nobrl =  0;
-		} else if (strnicmp(data, "nobrl", 5) == 0) {
+		} else if ((strnicmp(data, "nobrl", 5) == 0) || 
+			   (strnicmp(data, "nolock", 6)) {
 			vol->nobrl =  1;
 			/* turn off mandatory locking in mode
 			if remote locking is turned off since the
-- 
cgit v1.2.3


From 1c9551878c4629ca78dfe12ed23b9dc8d97770cc Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 30 Aug 2005 20:58:07 -0700
Subject: [CIFS] Add support for legacy servers part 4 	Fix WriteX support for
 old servers which do not support large 	files.

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifssmb.c | 27 +++++++++++++++++++----
 fs/cifs/connect.c |  2 +-
 fs/cifs/file.c    | 66 ++++++++++++++++++++++++++++++++++++++++---------------
 3 files changed, 72 insertions(+), 23 deletions(-)

diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index c8ae3ef422ba..74733851cfad 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1082,12 +1082,20 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 	int rc = -EACCES;
 	WRITE_REQ *pSMB = NULL;
 	WRITE_RSP *pSMBr = NULL;
-	int bytes_returned;
+	int bytes_returned, wct;
 	__u32 bytes_sent;
 	__u16 byte_count;
 
 	/* cFYI(1,("write at %lld %d bytes",offset,count));*/
-	rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
+	if(tcon->ses == NULL)
+		return -ECONNABORTED;
+
+	if(tcon->ses->capabilities & CAP_LARGE_FILES)
+		wct = 14;
+	else
+		wct = 12;
+
+	rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
 	if (rc)
 		return rc;
@@ -1098,7 +1106,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 	pSMB->AndXCommand = 0xFF;	/* none */
 	pSMB->Fid = netfid;
 	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
-	pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+	if(wct == 14) 
+		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+	else if((offset >> 32) > 0) /* can not handle this big offset for old */
+		return -EIO;
+	
 	pSMB->Reserved = 0xFFFFFFFF;
 	pSMB->WriteMode = 0;
 	pSMB->Remaining = 0;
@@ -1135,7 +1147,14 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
 	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
 	pSMB->hdr.smb_buf_length += bytes_sent+1;
-	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	if(wct == 14)
+		pSMB->ByteCount = cpu_to_le16(byte_count);
+	else { /* old style write has byte count 4 bytes earlier */
+		struct smb_com_writex_req * pSMBW = 
+			(struct smb_com_writex_req *)pSMB;
+		pSMBW->ByteCount = cpu_to_le16(byte_count);
+	}
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f784b70abfeb..196976049c00 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1079,7 +1079,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 		} else if (strnicmp(data, "brl", 3) == 0) {
 			vol->nobrl =  0;
 		} else if ((strnicmp(data, "nobrl", 5) == 0) || 
-			   (strnicmp(data, "nolock", 6)) {
+			   (strnicmp(data, "nolock", 6) == 0)) {
 			vol->nobrl =  1;
 			/* turn off mandatory locking in mode
 			if remote locking is turned off since the
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index ef455dda0473..b6c303f6373f 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1183,11 +1183,16 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 	char *smb_read_data;
 	char __user *current_offset;
 	struct smb_com_read_rsp *pSMBr;
+	int use_old_read = FALSE;
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
 
+	if(pTcon->ses)
+		if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0)
+			use_old_read = TRUE;
+
 	if (file->private_data == NULL) {
 		FreeXid(xid);
 		return -EBADF;
@@ -1212,16 +1217,21 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 				if (rc != 0)
 					break;
 			}
-
-			rc = CIFSSMBRead(xid, pTcon,
-				 open_file->netfid,
-				 current_read_size, *poffset,
-				 &bytes_read, &smb_read_data);
-			if(rc == -EINVAL) {
+			if(use_old_read)
 				rc = SMBLegacyRead(xid, pTcon,
 					open_file->netfid,
 					current_read_size, *poffset,
 					&bytes_read, &smb_read_data);
+			else {
+				rc = CIFSSMBRead(xid, pTcon,
+					open_file->netfid,
+					current_read_size, *poffset,
+					&bytes_read, &smb_read_data);
+				if(rc == -EINVAL) {
+					use_old_read = TRUE;
+					rc = -EAGAIN;
+					continue;
+				}
 			}
 			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
 			if (copy_to_user(current_offset, 
@@ -1266,6 +1276,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	int xid;
 	char *current_offset;
 	struct cifsFileInfo *open_file;
+	int use_old_read = FALSE;
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
@@ -1276,6 +1287,9 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 		return -EBADF;
 	}
 	open_file = (struct cifsFileInfo *)file->private_data;
+	if(pTcon->ses)
+		if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0)
+			use_old_read = TRUE;
 
 	if ((file->f_flags & O_ACCMODE) == O_WRONLY)
 		cFYI(1, ("attempting read on write only file instance"));
@@ -1294,16 +1308,23 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 				if (rc != 0)
 					break;
 			}
-
-			rc = CIFSSMBRead(xid, pTcon,
-				 open_file->netfid,
-				 current_read_size, *poffset,
-				 &bytes_read, &current_offset);
-			if(rc == -EINVAL) {
+			if(use_old_read) 
 				rc = SMBLegacyRead(xid, pTcon,
+					 open_file->netfid,
+					 current_read_size, *poffset,
+					 &bytes_read, &current_offset);
+			else {
+				rc = CIFSSMBRead(xid, pTcon,
 					open_file->netfid,
 					current_read_size, *poffset,
 					&bytes_read, &current_offset);
+				/* check if server disavows support for
+				   64 bit offsets */
+				if(rc == -EINVAL) {
+					rc = -EAGAIN;
+					use_old_read = TRUE;
+					continue;
+				}
 			}
 		}
 		if (rc || (bytes_read == 0)) {
@@ -1402,6 +1423,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 	struct smb_com_read_rsp *pSMBr;
 	struct pagevec lru_pvec;
 	struct cifsFileInfo *open_file;
+	int use_old_read = FALSE;
 
 	xid = GetXid();
 	if (file->private_data == NULL) {
@@ -1411,7 +1433,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 	open_file = (struct cifsFileInfo *)file->private_data;
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
-
+	if(pTcon->ses)
+		if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0)
+			use_old_read = TRUE;
 	pagevec_init(&lru_pvec, 0);
 
 	for (i = 0; i < num_pages; ) {
@@ -1457,15 +1481,21 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 					break;
 			}
 
-			rc = CIFSSMBRead(xid, pTcon,
-				open_file->netfid,
-				read_size, offset,
-				&bytes_read, &smb_read_data);
-			if (rc == -EINVAL) {
+			if(use_old_read)
 				rc = SMBLegacyRead(xid, pTcon,
 					open_file->netfid,
 					read_size, offset,
 					&bytes_read, &smb_read_data);
+			else {
+				rc = CIFSSMBRead(xid, pTcon,
+					open_file->netfid,
+					read_size, offset,
+					&bytes_read, &smb_read_data);
+				if(rc == -EINVAL) {
+					use_old_read = TRUE;
+					rc = -EAGAIN;
+					continue;
+				}
 			}
 
 			/* BB more RC checks ? */
-- 
cgit v1.2.3


From bfa0d75a1eee59f0577e3c1697ff570b77581a35 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 31 Aug 2005 21:50:37 -0700
Subject: [CIFS] Add support for legacy servers part 5 Handle small negotiated
 read sizes (under 4K) and finish up read and write support.

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifsproto.h |  3 --
 fs/cifs/cifssmb.c   | 99 +++++++++++------------------------------------------
 fs/cifs/file.c      | 58 +++----------------------------
 fs/cifs/inode.c     |  7 ++++
 fs/cifs/readdir.c   |  9 ++++-
 5 files changed, 39 insertions(+), 137 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 656b78ddf674..6943f7c6de08 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -226,9 +226,6 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
 			const int smb_file_id);
 
-extern int SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
-			const int netfid, unsigned int count,
-			const __u64 lseek, unsigned int *nbytes, char **buf);
 extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 			const int netfid, unsigned int count,
 			const __u64 lseek, unsigned int *nbytes, char **buf);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 74733851cfad..b8830118f09a 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -923,81 +923,6 @@ openRetry:
 	return rc;
 }
 
-int
-SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
-            const int netfid, unsigned int count,
-            const __u64 lseek, unsigned int *nbytes, char **buf)
-{
-	int rc = -EACCES;
-	READX_REQ *pSMB = NULL;
-	READ_RSP *pSMBr = NULL;
-	char *pReadData = NULL;
-	int bytes_returned;
-
-	cFYI(1,("Legacy read %d bytes fid %d",count,netfid));
-
-	/* field is shorter in legacy read, only 16 bits */
-	if(count > 2048)
-		count = 2048;  /* BB FIXME make this configurable */
-
-	if(lseek > 0xFFFFFFFF)
-		return -EIO; /* can not read that far into file on old server */
-
-	*nbytes = 0;
-	rc = smb_init(SMB_COM_READ_ANDX, 10, tcon, (void **) &pSMB,
-		      (void **) &pSMBr);
-	if (rc)
-		return rc;
-
-	/* tcon and ses pointer are checked in smb_init */
-	if (tcon->ses->server == NULL)
-		return -ECONNABORTED;
-
-	pSMB->AndXCommand = 0xFF;       /* none */
-	pSMB->Fid = netfid;
-	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
-	pSMB->Remaining = 0;
-	pSMB->MaxCount = cpu_to_le16(count);
-	pSMB->Reserved = 0; /* Must Be Zero */
-	pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
-
-	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-	cifs_stats_inc(&tcon->num_reads);
-	if (rc) {
-		cERROR(1, ("Send error in legacy read = %d", rc));
-	} else {
-		int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
-		data_length = data_length << 16;
-		data_length += le16_to_cpu(pSMBr->DataLength);
-		*nbytes = data_length;
-
-		/*check that DataLength would not go beyond end of SMB */
-		if ((data_length > CIFSMaxBufSize) || (data_length > count)) {
-			cFYI(1,("bad length %d for count %d",data_length,count));
-			rc = -EIO;
-			*nbytes = 0;
-		} else {
-			pReadData = (char *) (&pSMBr->hdr.Protocol) +
-						le16_to_cpu(pSMBr->DataOffset);
-/*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
-			 	cERROR(1,("Faulting on read rc = %d",rc));
-				rc = -EFAULT;
-			}*/ /* can not use copy_to_user when using page cache*/
-			if(*buf)
-				memcpy(*buf,pReadData,data_length);
-		}
-	}
-	if(*buf)
-		cifs_buf_release(pSMB);
-	else
-		*buf = (char *)pSMB;
-
-	/* Note: On -EAGAIN error only caller can retry on handle based calls
-		since file handle passed in no longer valid */
-	return rc;
-}
-
 /* If no buffer passed in, then caller wants to do the copy
 	as in the case of readpages so the SMB buffer must be
 	freed by the caller */
@@ -1012,11 +937,16 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 	READ_RSP *pSMBr = NULL;
 	char *pReadData = NULL;
 	int bytes_returned;
+	int wct;
 
 	cFYI(1,("Reading %d bytes on fid %d",count,netfid));
+	if(tcon->ses->capabilities & CAP_LARGE_FILES)
+		wct = 12;
+	else
+		wct = 10; /* old style read */
 
 	*nbytes = 0;
-	rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
+	rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
 	if (rc)
 		return rc;
@@ -1028,12 +958,23 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 	pSMB->AndXCommand = 0xFF;	/* none */
 	pSMB->Fid = netfid;
 	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
-	pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+	if(wct == 12)
+		pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+        else if((lseek >> 32) > 0) /* can not handle this big offset for old */
+                return -EIO;
+
 	pSMB->Remaining = 0;
 	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
 	pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
-	pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
-
+	if(wct == 12)
+		pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
+	else {
+		/* old style read */
+		struct smb_com_readx_req * pSMBW = 
+			(struct smb_com_readx_req *)pSMB;
+		pSMBW->ByteCount = 0;	
+	}
+	
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	cifs_stats_inc(&tcon->num_reads);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index b6c303f6373f..5ecda554f913 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1183,16 +1183,11 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 	char *smb_read_data;
 	char __user *current_offset;
 	struct smb_com_read_rsp *pSMBr;
-	int use_old_read = FALSE;
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
 
-	if(pTcon->ses)
-		if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0)
-			use_old_read = TRUE;
-
 	if (file->private_data == NULL) {
 		FreeXid(xid);
 		return -EBADF;
@@ -1217,22 +1212,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 				if (rc != 0)
 					break;
 			}
-			if(use_old_read)
-				rc = SMBLegacyRead(xid, pTcon,
-					open_file->netfid,
-					current_read_size, *poffset,
-					&bytes_read, &smb_read_data);
-			else {
-				rc = CIFSSMBRead(xid, pTcon,
+			rc = CIFSSMBRead(xid, pTcon,
 					open_file->netfid,
 					current_read_size, *poffset,
 					&bytes_read, &smb_read_data);
-				if(rc == -EINVAL) {
-					use_old_read = TRUE;
-					rc = -EAGAIN;
-					continue;
-				}
-			}
 			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
 			if (copy_to_user(current_offset, 
 					 smb_read_data + 4 /* RFC1001 hdr */
@@ -1276,7 +1259,6 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	int xid;
 	char *current_offset;
 	struct cifsFileInfo *open_file;
-	int use_old_read = FALSE;
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
@@ -1287,9 +1269,6 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 		return -EBADF;
 	}
 	open_file = (struct cifsFileInfo *)file->private_data;
-	if(pTcon->ses)
-		if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0)
-			use_old_read = TRUE;
 
 	if ((file->f_flags & O_ACCMODE) == O_WRONLY)
 		cFYI(1, ("attempting read on write only file instance"));
@@ -1308,24 +1287,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 				if (rc != 0)
 					break;
 			}
-			if(use_old_read) 
-				rc = SMBLegacyRead(xid, pTcon,
-					 open_file->netfid,
-					 current_read_size, *poffset,
-					 &bytes_read, &current_offset);
-			else {
-				rc = CIFSSMBRead(xid, pTcon,
+			rc = CIFSSMBRead(xid, pTcon,
 					open_file->netfid,
 					current_read_size, *poffset,
 					&bytes_read, &current_offset);
-				/* check if server disavows support for
-				   64 bit offsets */
-				if(rc == -EINVAL) {
-					rc = -EAGAIN;
-					use_old_read = TRUE;
-					continue;
-				}
-			}
 		}
 		if (rc || (bytes_read == 0)) {
 			if (total_read) {
@@ -1423,7 +1388,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 	struct smb_com_read_rsp *pSMBr;
 	struct pagevec lru_pvec;
 	struct cifsFileInfo *open_file;
-	int use_old_read = FALSE;
 
 	xid = GetXid();
 	if (file->private_data == NULL) {
@@ -1433,9 +1397,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 	open_file = (struct cifsFileInfo *)file->private_data;
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
-	if(pTcon->ses)
-		if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0)
-			use_old_read = TRUE;
+
 	pagevec_init(&lru_pvec, 0);
 
 	for (i = 0; i < num_pages; ) {
@@ -1481,22 +1443,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 					break;
 			}
 
-			if(use_old_read)
-				rc = SMBLegacyRead(xid, pTcon,
-					open_file->netfid,
-					read_size, offset,
-					&bytes_read, &smb_read_data);
-			else {
-				rc = CIFSSMBRead(xid, pTcon,
+			rc = CIFSSMBRead(xid, pTcon,
 					open_file->netfid,
 					read_size, offset,
 					&bytes_read, &smb_read_data);
-				if(rc == -EINVAL) {
-					use_old_read = TRUE;
-					rc = -EAGAIN;
-					continue;
-				}
-			}
 
 			/* BB more RC checks ? */
 			if (rc== -EAGAIN) {
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 0485c6d6ecd5..0fbe02ebc033 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -169,6 +169,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 				inode->i_fop->lock = NULL;
 			inode->i_data.a_ops = &cifs_addr_ops;
+			/* check if server can support readpages */
+			if(pTcon->ses->server->maxBuf < 
+			    4096 + MAX_CIFS_HDR_SIZE)
+				inode->i_data.a_ops->readpages = NULL;
 		} else if (S_ISDIR(inode->i_mode)) {
 			cFYI(1, (" Directory inode"));
 			inode->i_op = &cifs_dir_inode_ops;
@@ -384,6 +388,9 @@ int cifs_get_inode_info(struct inode **pinode,
 			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 				inode->i_fop->lock = NULL;
 			inode->i_data.a_ops = &cifs_addr_ops;
+			if(pTcon->ses->server->maxBuf < 
+			     4096 + MAX_CIFS_HDR_SIZE)
+				inode->i_data.a_ops->readpages = NULL;
 		} else if (S_ISDIR(inode->i_mode)) {
 			cFYI(1, (" Directory inode "));
 			inode->i_op = &cifs_dir_inode_ops;
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 9780f4ee7f12..a1e8dc901de4 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -200,7 +200,10 @@ static void fill_in_inode(struct inode *tmp_inode,
 		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 			tmp_inode->i_fop->lock = NULL;
 		tmp_inode->i_data.a_ops = &cifs_addr_ops;
-
+		if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+		   (cifs_sb->tcon->ses->server->maxBuf <
+			4096 + MAX_CIFS_HDR_SIZE))
+			tmp_inode->i_data.a_ops->readpages = NULL;
 		if(isNewInode)
 			return; /* No sense invalidating pages for new inode
 				   since have not started caching readahead file
@@ -306,6 +309,10 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
 		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 			tmp_inode->i_fop->lock = NULL;
 		tmp_inode->i_data.a_ops = &cifs_addr_ops;
+		if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+		   (cifs_sb->tcon->ses->server->maxBuf < 
+			4096 + MAX_CIFS_HDR_SIZE))
+			tmp_inode->i_data.a_ops->readpages = NULL;
 
 		if(isNewInode)
 			return; /* No sense invalidating pages for new inode since we
-- 
cgit v1.2.3


From 9a899e76683639486846ce17dbaa0c2ec1ae5ab5 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 6 Sep 2005 15:55:49 -0700
Subject: [CIFS] Update cifs TODO list with additional new features that have
 been requested.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/TODO | 48 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 31 insertions(+), 17 deletions(-)

diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index 8cc881694e29..0593f6447319 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,4 +1,4 @@
-version 1.34 April 29, 2005
+version 1.36 September 6, 2005
 
 A Partial List of Missing Features
 ==================================
@@ -7,14 +7,14 @@ Contributions are welcome.  There are plenty of opportunities
 for visible, important contributions to this module.  Here
 is a partial list of the known problems and missing features:
 
-a) Support for SecurityDescriptors for chmod/chgrp/chown so
-these can be supported for Windows servers
+a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown
+so that these operations can be supported to Windows servers
 
-b) Better pam/winbind integration (e.g. to handle uid mapping
-better)
+b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS
+SecurityDescriptors
 
-c) multi-user mounts - multiplexed sessionsetups over single vc
-(ie tcp session) - more testing needed
+c) Better pam/winbind integration (e.g. to handle uid mapping
+better)
 
 d) Kerberos/SPNEGO session setup support - (started)
 
@@ -29,12 +29,17 @@ f) Directory entry caching relies on a 1 second timer, rather than
 using FindNotify or equivalent.  - (started)
 
 g) A few byte range testcases fail due to POSIX vs. Windows/CIFS
-style byte range lock differences
+style byte range lock differences.  Save byte range locks so
+reconnect can replay them.  
 
-h) quota support
+h) Support unlock all (unlock 0,MAX_OFFSET)
+by unlocking all known byte range locks that we locked on the file.
+
+i) quota support (needs minor kernel change since quota calls
+to make it to network filesystems or deviceless filesystems)
 
 j) finish writepages support (multi-page write behind for improved
-performance) and syncpage
+performance) and syncpage. Started by Shaggy.
 
 k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
 extra copy in/out of the socket buffers in some cases.
@@ -57,20 +62,18 @@ p) Add support for storing symlink and fifo info to Windows servers
 in the Extended Attribute format their SFU clients would recognize.
 
 q) Finish fcntl D_NOTIFY support so kde and gnome file list windows
-will autorefresh (started)
+will autorefresh (partially complete by Asser). Needs minor kernel
+vfs change to support removing D_NOTIFY on a file.   
 
 r) Add GUI tool to configure /proc/fs/cifs settings and for display of
 the CIFS statistics (started)
 
-q) implement support for security and trusted categories of xattrs
+s) implement support for security and trusted categories of xattrs
 (requires minor protocol extension) to enable better support for SELINUX
 
-r) Implement O_DIRECT flag on open (already supported on mount)
-
-s) Allow remapping of last remaining character (\) to +0xF000 which
-(this character is valid for POSIX but not for Windows)
+t) Implement O_DIRECT flag on open (already supported on mount)
 
-t) Create UID mapping facility so server UIDs can be mapped on a per
+u) Create UID mapping facility so server UIDs can be mapped on a per
 mount or a per server basis to client UIDs or nobody if no mapping
 exists.  This is helpful when Unix extensions are negotiated to
 allow better permission checking when UIDs differ on the server
@@ -78,6 +81,17 @@ and client.  Add new protocol request to the CIFS protocol
 standard for asking the server for the corresponding name of a
 particular uid.
 
+v) Add support for CIFS Unix and also the newer POSIX extensions to the
+server side for Samba 4.
+
+w) Finish up the dos time conversion routines needed to return old server
+time to the client (default time, of now or time 0 is used now for these 
+very old servers)
+
+x) Add support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers)
+
+y) Finish testing of Windows 9x/Windows ME server support (started).
+
 KNOWN BUGS (updated April 29, 2005)
 ====================================
 See http://bugzilla.samba.org - search on product "CifsVFS" for
-- 
cgit v1.2.3


From ab2f218f4fa2c36ecd39ac1406eec1e63cd430bd Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 15 Sep 2005 20:44:50 -0700
Subject: [CIFS] Fix compiler warnings

Fix some compiler warnings noticed on x64 by me and ppc64 by Shaggy

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/asn1.c      | 3 ++-
 fs/cifs/cifsglob.h  | 2 +-
 fs/cifs/file.c      | 4 ++--
 fs/cifs/transport.c | 2 +-
 4 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c
index e02010dd73ec..98539e2afe81 100644
--- a/fs/cifs/asn1.c
+++ b/fs/cifs/asn1.c
@@ -191,7 +191,8 @@ asn1_header_decode(struct asn1_ctx *ctx,
 		   unsigned char **eoc,
 		   unsigned int *cls, unsigned int *con, unsigned int *tag)
 {
-	unsigned int def, len;
+	unsigned int def = 0; 
+	unsigned int len = 0;
 
 	if (!asn1_id_decode(ctx, cls, con, tag))
 		return 0;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index a9c791edede5..cd421c76805e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -331,7 +331,7 @@ CIFS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
-static inline const char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
+static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
 {
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
 		return '/';
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 5ecda554f913..4173f23a71d9 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -791,8 +791,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 
 	pTcon = cifs_sb->tcon;
 
-	cFYI(1,(" write %d bytes to offset %lld of %s", write_size,
-	   *poffset, file->f_dentry->d_name.name)); /* BB removeme BB */
+	cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
+	   *poffset, file->f_dentry->d_name.name));
 
 	if (file->private_data == NULL)
 		return -EBADF;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 96f89eb66040..d5e0c4018f92 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -485,7 +485,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 				BCC(in_buf) = le16_to_cpu(BCC(in_buf));
 		} else {
 			rc = -EIO;
-			cFYI(1,("Bad MID state? "));
+			cFYI(1,("Bad MID state?"));
 		}
 	}
 cifs_no_response_exit2:
-- 
cgit v1.2.3


From eafe87012159a40a1e7151cc576e99a22aea2f0b Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 15 Sep 2005 21:47:30 -0700
Subject: [CIFS] Fix readdir caching when unlink removes file in current search
 buffer, and this is followed by a rewind search to just before the deleted
 entry.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/CHANGES   |  5 +++++
 fs/cifs/cifsfs.h  |  2 +-
 fs/cifs/readdir.c | 37 ++++++++++++++++++++++++++++++++-----
 3 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 6c73f020ef40..8b55e56cf1fe 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,8 @@
+Version 1.37
+------------
+Fix readdir caching when unlink removes file in current search buffer,
+and this is followed by a rewind search to just before the deleted entry.
+
 Version 1.36
 ------------
 Add support for mounting to older pre-CIFS servers such as Windows9x and ME.
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index bb3404a99e5f..0f6d352ab813 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -97,5 +97,5 @@ extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 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.36"
+#define CIFS_VERSION   "1.37"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index a1e8dc901de4..a86bd1c07602 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -396,7 +396,8 @@ ffirst_retry:
 
 	rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
 		&cifsFile->netfid, &cifsFile->srch_inf,
-		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
+		cifs_sb->mnt_cifs_flags & 
+			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
 	if(rc == 0)
 		cifsFile->invalidHandle = FALSE;
 	if((rc == -EOPNOTSUPP) && 
@@ -513,6 +514,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
 	return rc;
 }
 
+/* Check if directory that we are searching has changed so we can decide
+   whether we can use the cached search results from the previous search */
+static int is_dir_changed(struct file * file)
+{
+	struct inode * inode;
+	struct cifsInodeInfo *cifsInfo;
+
+	if(file->f_dentry == NULL)
+		return 0;
+
+	inode = file->f_dentry->d_inode;
+
+	if(inode == NULL)
+		return 0;
+
+	cifsInfo = CIFS_I(inode);
+
+	if(cifsInfo->time == 0)
+		return 1; /* directory was changed, perhaps due to unlink */
+	else
+		return 0;
+
+}
+
 /* find the corresponding entry in the search */
 /* Note that the SMB server returns search entries for . and .. which
    complicates logic here if we choose to parse for them and we do not
@@ -529,7 +554,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 	struct cifsFileInfo * cifsFile = file->private_data;
 	/* check if index in the buffer */
 	
-	if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL))
+	if((cifsFile == NULL) || (ppCurrentEntry == NULL) || 
+	   (num_to_ret == NULL))
 		return -ENOENT;
 	
 	*ppCurrentEntry = NULL;
@@ -537,7 +563,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 		cifsFile->srch_inf.index_of_last_entry - 
 			cifsFile->srch_inf.entries_in_buffer;
 /*	dump_cifs_file_struct(file, "In fce ");*/
-	if(index_to_find < first_entry_in_buffer) {
+	if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
+	     is_dir_changed(file)) || 
+	   (index_to_find < first_entry_in_buffer)) {
 		/* close and restart search */
 		cFYI(1,("search backing up - close and restart search"));
 		cifsFile->invalidHandle = TRUE;
@@ -604,7 +632,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 	}
 
 	if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
-		cFYI(1,("can not return entries when pos_in_buf beyond last entry"));
+		cFYI(1,("can not return entries pos_in_buf beyond last entry"));
 		*num_to_ret = 0;
 	} else
 		*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
@@ -833,7 +861,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 	if(pTcon == NULL)
 		return -EINVAL;
 
-
 	switch ((int) file->f_pos) {
 	case 0:
 		/*if (filldir(direntry, ".", 1, file->f_pos,
-- 
cgit v1.2.3


From f9f5c81769f88bccd177423a30a7d30461754c39 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 15 Sep 2005 23:06:38 -0700
Subject: [CIFS] Add support for legacy servers part six. Fix read syntax so we
 do not request more than negotiated buffer size even if buffer size is small
 (smaller than one page)

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/file.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 4173f23a71d9..3766db2bb7f2 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1278,6 +1278,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	     total_read += bytes_read, current_offset += bytes_read) {
 		current_read_size = min_t(const int, read_size - total_read,
 					  cifs_sb->rsize);
+		/* For windows me and 9x we do not want to request more
+		than it negotiated since it will refuse the read then */
+		if((pTcon->ses) && 
+			!(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
+			current_read_size = min_t(const int, current_read_size,
+					pTcon->ses->server->maxBuf - 128);
+		}
 		rc = -EAGAIN;
 		while (rc == -EAGAIN) {
 			if ((open_file->invalidHandle) && 
-- 
cgit v1.2.3


From 3e87d80391c84eefceb4bda94a6363661dba4f71 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Sun, 18 Sep 2005 20:49:21 -0700
Subject: [CIFS] Add support for legacy servers part seven. Fix open for write,
 begin implementation of Win9x style set file size via open then write of zero
 bytes.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifssmb.c | 10 ++++++----
 fs/cifs/inode.c   | 15 +++++++++++++++
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index b8830118f09a..575b2281518d 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -766,7 +766,7 @@ OldOpenRetry:
         if(create_options & CREATE_OPTION_SPECIAL)
                 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
         else
-                pSMB->FileAttributes = cpu_to_le16(ATTR_NORMAL);
+                pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
 
 	/* if ((omode & S_IWUGO) == 0)
 		pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
@@ -777,6 +777,8 @@ OldOpenRetry:
 	/* BB FIXME BB */
 /*	pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
 	/* BB FIXME END BB */
+
+	pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
 	pSMB->OpenFunction = convert_disposition(openDisposition);
 	count += name_len;
 	pSMB->hdr.smb_buf_length += count;
@@ -3689,7 +3691,7 @@ SetEOFRetry:
 				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
-	} else {		/* BB improve the check for buffer overruns BB */
+	} else {	/* BB improve the check for buffer overruns BB */
 		name_len = strnlen(fileName, PATH_MAX);
 		name_len++;	/* trailing null */
 		strncpy(pSMB->FileName, fileName, name_len);
@@ -3697,7 +3699,7 @@ SetEOFRetry:
 	params = 6 + name_len;
 	data_count = sizeof (struct file_end_of_file_info);
 	pSMB->MaxParameterCount = cpu_to_le16(2);
-	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB size from sess */
+	pSMB->MaxDataCount = cpu_to_le16(4100);
 	pSMB->MaxSetupCount = 0;
 	pSMB->Reserved = 0;
 	pSMB->Flags = 0;
@@ -4079,7 +4081,7 @@ setPermsRetry:
 				     PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
-	} else {		/* BB improve the check for buffer overruns BB */
+	} else {	/* BB improve the check for buffer overruns BB */
 		name_len = strnlen(fileName, PATH_MAX);
 		name_len++;	/* trailing null */
 		strncpy(pSMB->FileName, fileName, name_len);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 0fbe02ebc033..6e82e1ae03b4 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1030,6 +1030,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 					/* now that we found one valid file
 					   handle no sense continuing to loop
 					   trying others, so break here */
+					/* if(rc == -EINVAL) {
+						int bytes_written;
+						rc = CIFSSMBWrite(xid, pTcon,
+							nfid, 0,
+							attrs->ia_size, 
+							&bytes_written,
+							NULL, NULL, long_op);
+					} */
 					break;
 				}
 			}
@@ -1048,6 +1056,13 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 					   cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc));
+			/* if(rc == -EINVAL)
+				old_style_set_eof_via_write(xid, pTcon, 
+						full_path, 
+						attrs->ia_size,
+						cifs_sb->local_nls,
+						cifs_sb->mnt_cifs_flags &
+						  CIFS_MOUNT_MAP_SPECIAL_CHR);*/
 		}
 
 		/* Server is ok setting allocation size implicitly - no need
-- 
cgit v1.2.3


From e30dcf3a1905b4d2154f95db5fdfdf69691b4f0e Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 20 Sep 2005 20:49:16 -0700
Subject: [CIFS] Add support for legacy servers part eight. Write fixes for
 Windows ME, and do not set ctime unless explicitly requested with atime
 and/or mtime (it gets thrown away by most servers anyway as there is no way
 to set this via posix).

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/CHANGES   |  2 ++
 fs/cifs/cifsfs.c  |  2 +-
 fs/cifs/cifssmb.c | 15 ++++++-----
 fs/cifs/inode.c   | 78 ++++++++++++++++++++++++++++++++++++++-----------------
 4 files changed, 66 insertions(+), 31 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 8b55e56cf1fe..47ae68b51847 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -2,6 +2,8 @@ Version 1.37
 ------------
 Fix readdir caching when unlink removes file in current search buffer,
 and this is followed by a rewind search to just before the deleted entry.
+Do not attempt to set ctime unless atime and/or mtime change requested
+(most servers throw it away anyway).
 
 Version 1.36
 ------------
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 43fb2aafa528..f738c8b19e3b 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -256,7 +256,7 @@ cifs_alloc_inode(struct super_block *sb)
 	cifs_inode->clientCanCacheAll = FALSE;
 	cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE;
 	cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
-
+	cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;
 	INIT_LIST_HEAD(&cifs_inode->openFileList);
 	return &cifs_inode->vfs_inode;
 }
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 575b2281518d..f72a61df3c68 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1072,7 +1072,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 	if (bytes_sent > count)
 		bytes_sent = count;
 	pSMB->DataOffset =
-	    cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
+		cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
 	if(buf)
 	    memcpy(pSMB->Data,buf,bytes_sent);
 	else if(ubuf) {
@@ -1080,20 +1080,23 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 			cifs_buf_release(pSMB);
 			return -EFAULT;
 		}
-	} else {
+	} else if (count != 0) {
 		/* No buffer */
 		cifs_buf_release(pSMB);
 		return -EINVAL;
+	} /* else setting file size with write of zero bytes */
+	if(wct == 14)
+		byte_count = bytes_sent + 1; /* pad */
+	else /* wct == 12 */ {
+		byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
 	}
-
-	byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
 	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
 	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
-	pSMB->hdr.smb_buf_length += bytes_sent+1;
+	pSMB->hdr.smb_buf_length += byte_count;
 
 	if(wct == 14)
 		pSMB->ByteCount = cpu_to_le16(byte_count);
-	else { /* old style write has byte count 4 bytes earlier */
+	else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
 		struct smb_com_writex_req * pSMBW = 
 			(struct smb_com_writex_req *)pSMB;
 		pSMBW->ByteCount = cpu_to_le16(byte_count);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 6e82e1ae03b4..ca3af4eafcb2 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1030,14 +1030,15 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 					/* now that we found one valid file
 					   handle no sense continuing to loop
 					   trying others, so break here */
-					/* if(rc == -EINVAL) {
+					if(rc == -EINVAL) {
 						int bytes_written;
 						rc = CIFSSMBWrite(xid, pTcon,
 							nfid, 0,
 							attrs->ia_size, 
-							&bytes_written,
-							NULL, NULL, long_op);
-					} */
+							&bytes_written, NULL,
+							NULL, 1 /* 45 sec */);
+						cFYI(1,("wrt seteof rc %d",rc));
+					}
 					break;
 				}
 			}
@@ -1055,14 +1056,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 					   cifs_sb->local_nls, 
 					   cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
-			cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc));
-			/* if(rc == -EINVAL)
-				old_style_set_eof_via_write(xid, pTcon, 
-						full_path, 
-						attrs->ia_size,
-						cifs_sb->local_nls,
-						cifs_sb->mnt_cifs_flags &
-						  CIFS_MOUNT_MAP_SPECIAL_CHR);*/
+			cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
+			if(rc == -EINVAL) {
+				__u16 netfid;
+				int oplock = FALSE;
+
+				rc = SMBLegacyOpen(xid, pTcon, full_path,
+					FILE_OPEN,
+					SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
+					CREATE_NOT_DIR, &netfid, &oplock,
+					NULL, cifs_sb->local_nls,
+					cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+				if (rc==0) {
+					int bytes_written;
+					rc = CIFSSMBWrite(xid, pTcon,
+							netfid, 0,
+							attrs->ia_size,
+							&bytes_written, NULL,
+							NULL, 1 /* 45 sec */);
+					cFYI(1,("wrt seteof rc %d",rc));
+					CIFSSMBClose(xid, pTcon, netfid);
+				}
+
+			}
 		}
 
 		/* Server is ok setting allocation size implicitly - no need
@@ -1075,24 +1092,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 			rc = vmtruncate(direntry->d_inode, attrs->ia_size);
 			cifs_truncate_page(direntry->d_inode->i_mapping,
 					   direntry->d_inode->i_size);
-		}
+		} else 
+			goto cifs_setattr_exit;
 	}
 	if (attrs->ia_valid & ATTR_UID) {
-		cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
+		cFYI(1, ("UID changed to %d", attrs->ia_uid));
 		uid = attrs->ia_uid;
-		/* entry->uid = cpu_to_le16(attr->ia_uid); */
 	}
 	if (attrs->ia_valid & ATTR_GID) {
-		cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
+		cFYI(1, ("GID changed to %d", attrs->ia_gid));
 		gid = attrs->ia_gid;
-		/* entry->gid = cpu_to_le16(attr->ia_gid); */
 	}
 
 	time_buf.Attributes = 0;
 	if (attrs->ia_valid & ATTR_MODE) {
-		cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
+		cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode));
 		mode = attrs->ia_mode;
-		/* entry->mode = cpu_to_le16(attr->ia_mode); */
 	}
 
 	if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
@@ -1132,18 +1147,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
 	} else
 		time_buf.LastWriteTime = 0;
-
-	if (attrs->ia_valid & ATTR_CTIME) {
+	/* Do not set ctime explicitly unless other time
+	   stamps are changed explicitly (i.e. by utime()
+	   since we would then have a mix of client and
+	   server times */
+	   
+	if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
 		set_time = TRUE;
-		cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */
+		/* Although Samba throws this field away
+		it may be useful to Windows - but we do
+		not want to set ctime unless some other
+		timestamp is changing */
+		cFYI(1, ("CIFS - CTIME changed "));
 		time_buf.ChangeTime =
 		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
 	} else
 		time_buf.ChangeTime = 0;
 
 	if (set_time || time_buf.Attributes) {
-		/* BB what if setting one attribute fails (such as size) but
-		   time setting works? */
 		time_buf.CreationTime = 0;	/* do not change */
 		/* In the future we should experiment - try setting timestamps
 		   via Handle (SetFileInfo) instead of by path */
@@ -1182,12 +1203,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
         	        		&time_buf, cifs_sb->local_nls); */
 			}
 		}
+		/* Even if error on time set, no sense failing the call if
+		the server would set the time to a reasonable value anyway,
+		and this check ensures that we are not being called from
+		sys_utimes in which case we ought to fail the call back to
+		the user when the server rejects the call */
+		if((rc) && (attrs->ia_valid &&
+			 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
+			rc = 0;
 	}
 
 	/* do not need local check to inode_check_ok since the server does
 	   that */
 	if (!rc)
 		rc = inode_setattr(direntry->d_inode, attrs);
+cifs_setattr_exit:
 	kfree(full_path);
 	FreeXid(xid);
 	return rc;
-- 
cgit v1.2.3


From 2096243885ee34b78cb57ce835e07c8536a67d2a Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 21 Sep 2005 22:05:57 -0700
Subject: [CIFS] Add support for legacy servers part nine.  statfs (df and du)
 is now functional, and the length check is fixed so readdir does not throw a
 warning message when windows me messes up the response to FindFirst of an
 empty dir (with only . and ..).

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/CHANGES     |  3 +-
 fs/cifs/cifsfs.c    |  4 +++
 fs/cifs/cifspdu.h   |  8 +++++
 fs/cifs/cifsproto.h |  2 ++
 fs/cifs/cifssmb.c   | 95 +++++++++++++++++++++++++++++++++++++++++++++++++----
 fs/cifs/misc.c      |  3 +-
 fs/cifs/netmisc.c   |  2 +-
 7 files changed, 107 insertions(+), 10 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 47ae68b51847..661b45906d09 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -3,7 +3,8 @@ Version 1.37
 Fix readdir caching when unlink removes file in current search buffer,
 and this is followed by a rewind search to just before the deleted entry.
 Do not attempt to set ctime unless atime and/or mtime change requested
-(most servers throw it away anyway).
+(most servers throw it away anyway). Fix length check of received smbs
+to be more accurate.
 
 Version 1.36
 ------------
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index f738c8b19e3b..1f97d39100ee 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -205,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
 #endif /* CIFS_EXPERIMENTAL */
 	rc = CIFSSMBQFSInfo(xid, pTcon, buf);
 
+	/* Old Windows servers do not support level 103, retry with level 
+	   one if old server failed the previous call */ 
+	if(rc)
+		rc = SMBOldQFSInfo(xid, pTcon, buf);
 	/*     
 	   int f_type;
 	   __fsid_t f_fsid;
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index cf466595b0d4..3fa37790bea2 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1683,6 +1683,14 @@ typedef struct {
 	__le32 BytesPerSector;
 } FILE_SYSTEM_INFO;		/* size info, level 0x103 */
 
+typedef struct {
+	__le32 fsid;
+	__le32 SectorsPerAllocationUnit;
+	__le32 TotalAllocationUnits;
+	__le32 FreeAllocationUnits;
+	__le16  BytesPerSector;
+} FILE_SYSTEM_ALLOC_INFO;
+
 typedef struct {
 	__le16 MajorVersionNumber;
 	__le16 MinorVersionNumber;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6943f7c6de08..0bace385e97a 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -133,6 +133,8 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 			int remap);
 extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
 			struct kstatfs *FSData);
+extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
+			struct kstatfs *FSData);
 extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
 			__u64 cap);
 
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f72a61df3c68..daf717e6b6eb 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3215,6 +3215,92 @@ GetDFSRefExit:
 	return rc;
 }
 
+/* Query File System Info such as free space to old servers such as Win 9x */
+int
+SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
+{
+/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_ALLOC_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, byte_count;
+
+	cFYI(1, ("OldQFSInfo"));
+oldQFSInfoRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		(void **) &pSMBr);
+	if (rc)
+		return rc;
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 2;     /* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+	struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
+	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);
+	if (rc) {
+		cFYI(1, ("Send error in QFSInfo = %d", rc));
+	} else {                /* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < 18))
+			rc = -EIO;      /* bad smb */
+		else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			cFYI(1,("qfsinf resp BCC: %d  Offset %d",
+				 pSMBr->ByteCount, data_offset));
+
+			response_data =
+				(FILE_SYSTEM_ALLOC_INFO *) 
+				(((char *) &pSMBr->hdr.Protocol) + data_offset);
+			FSData->f_bsize =
+				le16_to_cpu(response_data->BytesPerSector) *
+				le32_to_cpu(response_data->
+					SectorsPerAllocationUnit);
+			FSData->f_blocks =
+				le32_to_cpu(response_data->TotalAllocationUnits);
+			FSData->f_bfree = FSData->f_bavail =
+				le32_to_cpu(response_data->FreeAllocationUnits);
+			cFYI(1,
+			     ("Blocks: %lld  Free: %lld Block size %ld",
+			      (unsigned long long)FSData->f_blocks,
+			      (unsigned long long)FSData->f_bfree,
+			      FSData->f_bsize));
+		}
+	}
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto oldQFSInfoRetry;
+
+	return rc;
+}
+
 int
 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
 {
@@ -3236,7 +3322,7 @@ QFSInfoRetry:
 	params = 2;	/* level */
 	pSMB->TotalDataCount = 0;
 	pSMB->MaxParameterCount = cpu_to_le16(2);
-	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(1000);
 	pSMB->MaxSetupCount = 0;
 	pSMB->Reserved = 0;
 	pSMB->Flags = 0;
@@ -3259,17 +3345,14 @@ QFSInfoRetry:
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	if (rc) {
-		cERROR(1, ("Send error in QFSInfo = %d", rc));
+		cFYI(1, ("Send error in QFSInfo = %d", rc));
 	} else {		/* decode response */
                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-		if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
+		if (rc || (pSMBr->ByteCount < 24))
 			rc = -EIO;	/* bad smb */
 		else {
 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-			cFYI(1,
-				("Decoding qfsinfo response.  BCC: %d  Offset %d",
-				pSMBr->ByteCount, data_offset));
 
 			response_data =
 			    (FILE_SYSTEM_INFO
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index fafbdbfa63a1..26b35b55f31b 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -450,13 +450,12 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
 
 	if ((4 + len != smbCalcSize(smb))
 	    || (4 + len != (unsigned int)length)) {
-		return 0;
-	} else {
 		cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
 		cERROR(1,
 		       ("bad smb size detected. The Mid=%d", smb->Mid));
 		return 1;
 	}
+	return 0;
 }
 int
 is_valid_oplock_break(struct smb_hdr *buf)
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 873b812c0f40..32efa32774d2 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -868,7 +868,7 @@ unsigned int
 smbCalcSize(struct smb_hdr *ptr)
 {
 	return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
-		BCC(ptr));
+		2 /* size of the bcc field itself */ + BCC(ptr));
 }
 
 /* The following are taken from fs/ntfs/util.c */
-- 
cgit v1.2.3


From 70ca734a14366b634224a1e4586d43b36b65ab67 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 22 Sep 2005 16:32:06 -0700
Subject: [CIFS] Various minor bigendian fixes and sparse level 2 warning
 message fixes Most important of these fixes mapchars on bigendian and a few
 statfs fields

Signed-off-by: Shaggy (shaggy@austin.ibm.com)
Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/CHANGES     |  3 ++-
 fs/cifs/cifspdu.h   |  2 +-
 fs/cifs/cifsproto.h |  1 +
 fs/cifs/cifssmb.c   | 24 ++++++++++++++----------
 fs/cifs/connect.c   | 38 +++++++++++++++++++++++++-------------
 fs/cifs/misc.c      | 12 +++++++-----
 fs/cifs/netmisc.c   |  9 ++++++++-
 fs/cifs/transport.c |  4 ++--
 8 files changed, 60 insertions(+), 33 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 661b45906d09..535177238020 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -4,7 +4,8 @@ Fix readdir caching when unlink removes file in current search buffer,
 and this is followed by a rewind search to just before the deleted entry.
 Do not attempt to set ctime unless atime and/or mtime change requested
 (most servers throw it away anyway). Fix length check of received smbs
-to be more accurate.
+to be more accurate. Fix big endian problem with mapchars mount option,
+and with a field returned by statfs.
 
 Version 1.36
 ------------
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 3fa37790bea2..193f06eb43f9 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -697,7 +697,7 @@ typedef struct smb_com_openx_req {
 	__le32 EndOfFile;
 	__le32 Timeout;
 	__le32 Reserved;
-	__u16  ByteCount;  /* file name follows */
+	__le16  ByteCount;  /* file name follows */
 	char   fileName[1];
 } OPENX_REQ;
 
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0bace385e97a..dc5a6a6ff2f9 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -56,6 +56,7 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
 extern int is_valid_oplock_break(struct smb_hdr *smb);
 extern int is_size_safe_to_change(struct cifsInodeInfo *);
 extern unsigned int smbCalcSize(struct smb_hdr *ptr);
+extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
 			enum securityEnum *secType);
 extern int cifs_inet_pton(int, char * source, void *dst);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index daf717e6b6eb..52caac063a77 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -779,7 +779,7 @@ OldOpenRetry:
 	/* BB FIXME END BB */
 
 	pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
-	pSMB->OpenFunction = convert_disposition(openDisposition);
+	pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
 	count += name_len;
 	pSMB->hdr.smb_buf_length += count;
 
@@ -808,10 +808,12 @@ OldOpenRetry:
 			pfile_info->LastAccessTime = 0; /* BB fixme */
 			pfile_info->LastWriteTime = 0; /* BB fixme */
 			pfile_info->ChangeTime = 0;  /* BB fixme */
-			pfile_info->Attributes = pSMBr->FileAttributes; 
+			pfile_info->Attributes =
+				cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
 			/* the file_info buf is endian converted by caller */
-			pfile_info->AllocationSize = pSMBr->EndOfFile;
-			pfile_info->EndOfFile = pSMBr->EndOfFile;
+			pfile_info->AllocationSize =
+				cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
+			pfile_info->EndOfFile = pfile_info->AllocationSize;
 			pfile_info->NumberOfLinks = cpu_to_le32(1);
 		}
 	}
@@ -2390,9 +2392,11 @@ QInfRetry:
 		cFYI(1, ("Send error in QueryInfo = %d", rc));
 	} else if (pFinfo) {            /* decode response */
 		memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
-		pFinfo->AllocationSize = (__le64) pSMBr->size;
-		pFinfo->EndOfFile = (__le64) pSMBr->size;
-		pFinfo->Attributes = (__le32) pSMBr->attr;
+		pFinfo->AllocationSize =
+			cpu_to_le64(le32_to_cpu(pSMBr->size));
+		pFinfo->EndOfFile = pFinfo->AllocationSize;
+		pFinfo->Attributes =
+			cpu_to_le32(le16_to_cpu(pSMBr->attr));
 	} else
 		rc = -EIO; /* bad buffer passed in */
 
@@ -3722,16 +3726,16 @@ QFSPosixRetry:
 					le64_to_cpu(response_data->TotalBlocks);
 			FSData->f_bfree =
 			    le64_to_cpu(response_data->BlocksAvail);
-			if(response_data->UserBlocksAvail == -1) {
+			if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
 				FSData->f_bavail = FSData->f_bfree;
 			} else {
 				FSData->f_bavail =
 					le64_to_cpu(response_data->UserBlocksAvail);
 			}
-			if(response_data->TotalFileNodes != -1)
+			if(response_data->TotalFileNodes != cpu_to_le64(-1))
 				FSData->f_files =
 					le64_to_cpu(response_data->TotalFileNodes);
-			if(response_data->FreeFileNodes != -1)
+			if(response_data->FreeFileNodes != cpu_to_le64(-1))
 				FSData->f_ffree =
 					le64_to_cpu(response_data->FreeFileNodes);
 		}
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 196976049c00..e27e5ad8b591 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -303,12 +303,12 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
 	byte_count += total_in_buf2;
 	BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
 
-	byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
+	byte_count = pTargetSMB->smb_buf_length;
 	byte_count += total_in_buf2;
 
 	/* BB also add check that we are not beyond maximum buffer size */
 		
-	pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
+	pTargetSMB->smb_buf_length = byte_count;
 
 	if(remaining == total_in_buf2) {
 		cFYI(1,("found the last secondary response"));
@@ -333,7 +333,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 	struct cifsSesInfo *ses;
 	struct task_struct *task_to_wake = NULL;
 	struct mid_q_entry *mid_entry;
-	char *temp;
+	char temp;
 	int isLargeBuf = FALSE;
 	int isMultiRsp;
 	int reconnect;
@@ -435,22 +435,32 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 			continue;
 		}
 
-		/* the right amount was read from socket - 4 bytes */
+		/* The right amount was read from socket - 4 bytes */
+		/* so we can now interpret the length field */
 
+		/* the first byte big endian of the length field,
+		is actually not part of the length but the type
+		with the most common, zero, as regular data */
+		temp = *((char *) smb_buffer);
+
+		/* Note that FC 1001 length is big endian on the wire, 
+		but we convert it here so it is always manipulated
+		as host byte order */
 		pdu_length = ntohl(smb_buffer->smb_buf_length);
-		cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
+		smb_buffer->smb_buf_length = pdu_length;
+
+		cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
 
-		temp = (char *) smb_buffer;
-		if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
+		if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
 			continue; 
-		} else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
+		} else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
 			cFYI(1,("Good RFC 1002 session rsp"));
 			continue;
-		} else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
+		} else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
 			/* we get this from Windows 98 instead of 
 			   an error on SMB negprot response */
 			cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
-				temp[4]));
+				pdu_length));
 			if(server->tcpStatus == CifsNew) {
 				/* if nack on negprot (rather than 
 				ret of smb negprot error) reconnecting
@@ -472,9 +482,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 				wake_up(&server->response_q);
 				continue;
 			}
-		} else if (temp[0] != (char) 0) {
+		} else if (temp != (char) 0) {
 			cERROR(1,("Unknown RFC 1002 frame"));
-			cifs_dump_mem(" Received Data: ", temp, length);
+			cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
+				      length);
 			cifs_reconnect(server);
 			csocket = server->ssocket;
 			continue;
@@ -609,7 +620,8 @@ multi_t2_fnd:
 		} else if ((is_valid_oplock_break(smb_buffer) == FALSE)
 		    && (isMultiRsp == FALSE)) {                          
 			cERROR(1, ("No task to wake, unknown frame rcvd!"));
-			cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
+			cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
+				      sizeof(struct smb_hdr));
 		}
 	} /* end while !EXITING */
 
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 26b35b55f31b..8a0edd695f84 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -419,7 +419,7 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
 int
 checkSMB(struct smb_hdr *smb, __u16 mid, int length)
 {
-	__u32 len = be32_to_cpu(smb->smb_buf_length);
+	__u32 len = smb->smb_buf_length;
 	cFYI(0,
 	     ("Entering checkSMB with Length: %x, smb_buf_length: %x ",
 	      length, len));
@@ -448,9 +448,9 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
 	if (checkSMBhdr(smb, mid))
 		return 1;
 
-	if ((4 + len != smbCalcSize(smb))
+	if ((4 + len != smbCalcSize_LE(smb))
 	    || (4 + len != (unsigned int)length)) {
-		cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
+		cERROR(1, ("smbCalcSize %x ", smbCalcSize_LE(smb)));
 		cERROR(1,
 		       ("bad smb size detected. The Mid=%d", smb->Mid));
 		return 1;
@@ -672,6 +672,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
 	int i,j,charlen;
 	int len_remaining = maxlen;
 	char src_char;
+	__u16 temp;
 
 	if(!mapChars) 
 		return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp);
@@ -708,13 +709,14 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
 				break;*/
 			default:
 				charlen = cp->char2uni(source+i,
-					len_remaining, target+j);
+					len_remaining, &temp);
 				/* if no match, use question mark, which
 				at least in some cases servers as wild card */
 				if(charlen < 1) {
 					target[j] = cpu_to_le16(0x003f);
 					charlen = 1;
-				}
+				} else
+					target[j] = cpu_to_le16(temp);
 				len_remaining -= charlen;
 				/* character may take more than one byte in the
 				   the source string, but will take exactly two
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 32efa32774d2..29e6efc5597c 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -868,7 +868,14 @@ unsigned int
 smbCalcSize(struct smb_hdr *ptr)
 {
 	return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
-		2 /* size of the bcc field itself */ + BCC(ptr));
+		2 /* size of the bcc field */ + BCC(ptr));
+}
+
+unsigned int
+smbCalcSize_LE(struct smb_hdr *ptr)
+{
+	return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
+		2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr)));
 }
 
 /* The following are taken from fs/ntfs/util.c */
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index d5e0c4018f92..9e8e85a8d186 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -414,7 +414,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 	spin_lock(&GlobalMid_Lock);
 	if (midQ->resp_buf) {
 		spin_unlock(&GlobalMid_Lock);
-		receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
+		receive_len = midQ->resp_buf->smb_buf_length;
 	} else {
 		cERROR(1,("No response buffer"));
 		if(midQ->midState == MID_REQUEST_SUBMITTED) {
@@ -665,7 +665,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 	spin_lock(&GlobalMid_Lock);
 	if (midQ->resp_buf) {
 		spin_unlock(&GlobalMid_Lock);
-		receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
+		receive_len = midQ->resp_buf->smb_buf_length;
 	} else {
 		cERROR(1,("No response buffer"));
 		if(midQ->midState == MID_REQUEST_SUBMITTED) {
-- 
cgit v1.2.3


From 3e84469d0101456caceffc6b22218a49017fcd3f Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 3 Oct 2005 13:37:24 -0700
Subject: [CIFS] Add writepages support to shrink memory usage on writes,
 eliminate the double copy, and improve cifs write performance and help the
 server by upping the typical write size from 4K to 16K (or even larger if
 wsize set explicitly)  for servers which support this. Part 1 of 2

Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French  <sfrench@us.ibm.com>
---
 fs/cifs/cifsproto.h |  5 ++-
 fs/cifs/cifssmb.c   | 41 ++++++++++-------------
 fs/cifs/connect.c   |  4 +++
 fs/cifs/file.c      | 16 ++++++---
 fs/cifs/transport.c | 95 +++++++++++++++++++++++++++++++----------------------
 5 files changed, 89 insertions(+), 72 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index dc5a6a6ff2f9..fb3e76043c50 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -48,8 +48,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
 			struct smb_hdr * /* out */ ,
 			int * /* bytes returned */ , const int long_op);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
-			struct smb_hdr * /* input */ , int hdr_len,
-			const char * /* SMB data to send */ , int data_len,
+			struct kvec *, int /* nvec */,
 			int * /* bytes returned */ , const int long_op);
 extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
 extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
@@ -241,7 +240,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 			const int netfid, const unsigned int count,
 			const __u64 offset, unsigned int *nbytes, 
-			const char *buf,const int long_op);
+			struct kvec *iov, const int nvec, const int long_op);
 extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName, __u64 * inode_number,
 			const struct nls_table *nls_codepage, 
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 52caac063a77..365949c14646 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -125,6 +125,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 				rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
 					, nls_codepage);
 				up(&tcon->ses->sesSem);
+				/* BB FIXME add code to check if wsize needs
+				   update due to negotiated smb buffer size
+				   shrinking */
 				if(rc == 0)
 					atomic_inc(&tconInfoReconnectCount);
 
@@ -220,6 +223,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 				rc = CIFSTCon(0, tcon->ses, tcon->treeName,
 					      tcon, nls_codepage);
 				up(&tcon->ses->sesSem);
+				/* BB FIXME add code to check if wsize needs
+				update due to negotiated smb buffer size
+				shrinking */
 				if(rc == 0)
 					atomic_inc(&tconInfoReconnectCount);
 
@@ -1128,15 +1134,13 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 int
 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 	     const int netfid, const unsigned int count,
-	     const __u64 offset, unsigned int *nbytes, const char *buf,
-	     const int long_op)
+	     const __u64 offset, unsigned int *nbytes, struct kvec *iov,
+	     int n_vec, const int long_op)
 {
 	int rc = -EACCES;
 	WRITE_REQ *pSMB = NULL;
 	int bytes_returned;
 	int smb_hdr_len;
-	__u32 bytes_sent;
-	__u16 byte_count;
 
 	cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
 	rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
@@ -1154,31 +1158,20 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 	pSMB->WriteMode = 0;
 	pSMB->Remaining = 0;
 
-	/* Can increase buffer size if buffer is big enough in some cases - ie 
-	can send more if LARGE_WRITE_X capability returned by the server and if
-	our buffer is big enough or if we convert to iovecs on socket writes
-	and eliminate the copy to the CIFS buffer */
-	if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
-		bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
-	} else {
-		bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
-			 & ~0xFF;
-	}
-
-	if (bytes_sent > count)
-		bytes_sent = count;
 	pSMB->DataOffset =
 	    cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
 
-	byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
-	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
-	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
+	pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
+	pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
 	smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
-	pSMB->hdr.smb_buf_length += bytes_sent+1;
-	pSMB->ByteCount = cpu_to_le16(byte_count);
+	pSMB->hdr.smb_buf_length += count+1;
+	pSMB->ByteCount = cpu_to_le16(count + 1);
+
+	iov[0].iov_base = pSMB;
+	iov[0].iov_len = smb_hdr_len + 4;
 
-	rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
-			  buf, bytes_sent, &bytes_returned, long_op);
+	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned,
+			  long_op);
 	cifs_stats_inc(&tcon->num_writes);
 	if (rc) {
 		cFYI(1, ("Send error in write = %d", rc));
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index e27e5ad8b591..f05d9e2016d5 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1891,6 +1891,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 				}
 			}
 		}
+		if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
+			cifs_sb->wsize = min(cifs_sb->wsize,
+					     (tcon->ses->server->maxBuf -
+					      MAX_CIFS_HDR_SIZE));
 	}
 
 	/* volume_info.password is freed above when existing session found
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 3766db2bb7f2..941108352547 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -849,13 +849,19 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 			/* BB FIXME We can not sign across two buffers yet */
 			if((experimEnabled) && ((pTcon->ses->server->secMode & 
 			 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) {
+				struct kvec iov[2];
+				unsigned int len;
+
+				len = min(cifs_sb->wsize,
+					  write_size - total_written);
+				/* iov[0] is reserved for smb header */
+				iov[1].iov_base = (char *)write_data +
+						  total_written;
+				iov[1].iov_len = len;
 				rc = CIFSSMBWrite2(xid, pTcon,
-						open_file->netfid,
-						min_t(const int, cifs_sb->wsize,
-						    write_size - total_written),
+						open_file->netfid, len,
 						*poffset, &bytes_written,
-						write_data + total_written, 
-						long_op);
+						iov, 1, long_op);
 			} else
 			/* BB FIXME fixup indentation of line below */
 #endif			
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 9e8e85a8d186..38b3b2463ae4 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -147,16 +147,19 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
 	   Flags2 is converted in SendReceive */
 
 	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
-	cFYI(1, ("Sending smb of length %d ", smb_buf_length));
+	cFYI(1, ("Sending smb of length %d", smb_buf_length));
 	dump_smb(smb_buffer, len);
 
 	while (len > 0) {
 		rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
 		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
 			i++;
-			if(i > 60) {
+		/* smaller timeout here than send2 since smaller size */
+		/* Although it may not be required, this also is smaller 
+		   oplock break time */  
+			if(i > 30) {
 				cERROR(1,
-				   ("sends on sock %p stuck for 30 seconds",
+				   ("sends on sock %p stuck for 15 seconds",
 				    ssocket));
 				rc = -EAGAIN;
 				break;
@@ -172,7 +175,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
 	}
 
 	if (rc < 0) {
-		cERROR(1,("Error %d sending data on socket to server.", rc));
+		cERROR(1,("Error %d sending data on socket to server", rc));
 	} else {
 		rc = 0;
 	}
@@ -182,22 +185,20 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 static int
-smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
-	 unsigned int smb_hdr_length, const char * data, unsigned int datalen,
-	 struct sockaddr *sin)
+smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
+	  struct sockaddr *sin)
 {
 	int rc = 0;
 	int i = 0;
 	struct msghdr smb_msg;
-	struct kvec iov[2];
-	unsigned len = smb_hdr_length + 4;
+	struct smb_hdr *smb_buffer = iov[0].iov_base;
+	unsigned int len = iov[0].iov_len;
+	unsigned int total_len;
+	int first_vec = 0;
 	
 	if(ssocket == NULL)
 		return -ENOTSOCK; /* BB eventually add reconnect code here */
-	iov[0].iov_base = smb_buffer;
-	iov[0].iov_len = len;
-	iov[1].iov_base = data;
-	iov[1].iov_len = datalen;
+
 	smb_msg.msg_name = sin;
 	smb_msg.msg_namelen = sizeof (struct sockaddr);
 	smb_msg.msg_control = NULL;
@@ -209,18 +210,23 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
 	   cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
 	   Flags2 is converted in SendReceive */
 
+
+	total_len = 0;
+	for (i = 0; i < n_vec; i++)
+		total_len += iov[i].iov_len;
+
 	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
-	cFYI(1, ("Sending smb:  hdrlen %d datalen %d",
-		 smb_hdr_length,datalen));
+	cFYI(1, ("Sending smb:  total_len %d", total_len));
 	dump_smb(smb_buffer, len);
 
-	while (len + datalen > 0) {
-		rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len);
+	while (total_len) {
+		rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
+				    n_vec - first_vec, total_len);
 		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
 			i++;
-			if(i > 60) {
+			if(i > 40) {
 				cERROR(1,
-				   ("sends on sock %p stuck for 30 seconds",
+				   ("sends on sock %p stuck for 20 seconds",
 				    ssocket));
 				rc = -EAGAIN;
 				break;
@@ -230,43 +236,52 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
 		}
 		if (rc < 0) 
 			break;
-		if(iov[0].iov_len > 0) {
-			if(rc >= len) {
-				iov[0].iov_len = 0;
-				rc -= len;
-				len = 0;
-			} else {  /* some of hdr was not sent */
-				len -= rc;
-				iov[0].iov_len -= rc;
-				iov[0].iov_base += rc;
-				continue;
-			}
+
+		if (rc >= total_len) {
+			WARN_ON(rc > total_len);
+			break;
+		}
+		if(rc == 0) {
+			/* should never happen, letting socket clear before
+			   retrying is our only obvious option here */
+			cERROR(1,("tcp sent no data");
+			msleep(500);
+			continue;
 		}
-		if((iov[0].iov_len == 0) && (rc > 0)){
-			iov[1].iov_base += rc;
-			iov[1].iov_len -= rc;
-			datalen -= rc;
+		total_len -= rc;
+		for (i = first_vec; i < n_vec; i++) {
+			if (iov[i].iov_len) {
+				if (rc > iov[i].iov_len) {
+					rc -= iov[i].iov_len;
+					iov[i].iov_len = 0;
+				} else {
+					iov[i].iov_base += rc;
+					iov[i].iov_len -= rc;
+					first_vec = i;
+					break;
+				}
+			}
 		}
 	}
 
 	if (rc < 0) {
-		cERROR(1,("Error %d sending data on socket to server.", rc));
-	} else {
+		cERROR(1,("Error %d sending data on socket to server", rc));
+	} else
 		rc = 0;
-	}
 
 	return rc;
 }
 
 int
 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
-	     struct smb_hdr *in_buf, int hdrlen, const char * data,
-	     int datalen, int *pbytes_returned, const int long_op)
+	     struct kvec *iov, int n_vec, int *pbytes_returned,
+	     const int long_op)
 {
 	int rc = 0;
 	unsigned int receive_len;
 	unsigned long timeout;
 	struct mid_q_entry *midQ;
+	struct smb_hdr *in_buf = iov[0].iov_base;
 
 	if (ses == NULL) {
 		cERROR(1,("Null smb session"));
@@ -364,7 +379,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 /* 	rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
-	rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen,
+	rc = smb_send2(ses->server->ssocket, iov, n_vec,
 		      (struct sockaddr *) &(ses->server->addr.sockAddr));
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
-- 
cgit v1.2.3


From 8cc64c6ecfef020d40829f3e1152aab006c13899 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 3 Oct 2005 13:49:43 -0700
Subject: [CIFS] Allow SMBWrite2 to work to older servers

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifssmb.c | 29 ++++++++++++++++++++++-------
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 365949c14646..41996a240149 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1139,11 +1139,15 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 {
 	int rc = -EACCES;
 	WRITE_REQ *pSMB = NULL;
-	int bytes_returned;
+	int bytes_returned, wct;
 	int smb_hdr_len;
 
 	cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
-	rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
+	if(tcon->ses->capabilities & CAP_LARGE_FILES)
+		wct = 14;
+	else
+		wct = 12;
+	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
 	if (rc)
 		return rc;
 	/* tcon and ses pointer are checked in smb_init */
@@ -1153,7 +1157,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 	pSMB->AndXCommand = 0xFF;	/* none */
 	pSMB->Fid = netfid;
 	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
-	pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+	if(wct == 14)
+		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+	else if((offset >> 32) > 0) /* can not handle this big offset for old */
+		return -EIO;
 	pSMB->Reserved = 0xFFFFFFFF;
 	pSMB->WriteMode = 0;
 	pSMB->Remaining = 0;
@@ -1164,9 +1171,17 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 	pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
 	pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
 	smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
-	pSMB->hdr.smb_buf_length += count+1;
-	pSMB->ByteCount = cpu_to_le16(count + 1);
-
+	if(wct == 14)
+		pSMB->hdr.smb_buf_length += count+1;
+	else /* wct == 12 */
+		pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
+	if(wct == 14)
+		pSMB->ByteCount = cpu_to_le16(count + 1);
+	else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
+		struct smb_com_writex_req * pSMBW =
+				(struct smb_com_writex_req *)pSMB;
+		pSMBW->ByteCount = cpu_to_le16(count + 5);
+	}
 	iov[0].iov_base = pSMB;
 	iov[0].iov_len = smb_hdr_len + 4;
 
@@ -1174,7 +1189,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 			  long_op);
 	cifs_stats_inc(&tcon->num_writes);
 	if (rc) {
-		cFYI(1, ("Send error in write = %d", rc));
+		cFYI(1, ("Send error Write2 = %d", rc));
 		*nbytes = 0;
 	} else {
 		WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
-- 
cgit v1.2.3


From 04c08816d693f010ce14b8f408c6228600053af0 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 3 Oct 2005 19:33:15 -0700
Subject: [CIFS] Missing parenthesis from error message in previous fix

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/transport.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 38b3b2463ae4..64c712629f27 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -244,7 +244,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
 		if(rc == 0) {
 			/* should never happen, letting socket clear before
 			   retrying is our only obvious option here */
-			cERROR(1,("tcp sent no data");
+			cERROR(1,("tcp sent no data"));
 			msleep(500);
 			continue;
 		}
-- 
cgit v1.2.3


From 6148a742b2bd76abfe0c1fc50dd747cb9f28cd6b Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 5 Oct 2005 12:23:19 -0700
Subject: CIFS: Create routine find_writable_file to reduce redundant code

Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifsproto.h |   1 +
 fs/cifs/file.c      | 112 ++++++++++++++++------------------------------------
 fs/cifs/inode.c     |  56 +++++++-------------------
 3 files changed, 50 insertions(+), 119 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index fb3e76043c50..d301149b1bb0 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -54,6 +54,7 @@ extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
 extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
 extern int is_valid_oplock_break(struct smb_hdr *smb);
 extern int is_size_safe_to_change(struct cifsInodeInfo *);
+extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
 extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 941108352547..94875455d7fa 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -904,6 +904,25 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 	return total_written;
 }
 
+static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
+{
+	struct cifsFileInfo *open_file;
+
+	read_lock(&GlobalSMBSeslock);
+	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
+		if (open_file->closePend)
+			continue;
+		if (open_file->pfile &&
+		    ((open_file->pfile->f_flags & O_RDWR) ||
+		     (open_file->pfile->f_flags & O_WRONLY))) {
+			read_unlock(&GlobalSMBSeslock);
+			return open_file;
+		}
+	}
+	read_unlock(&GlobalSMBSeslock);
+	return NULL;
+}
+
 static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 {
 	struct address_space *mapping = page->mapping;
@@ -914,10 +933,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	struct inode *inode;
-	struct cifsInodeInfo *cifsInode;
-	struct cifsFileInfo *open_file = NULL;
-	struct list_head *tmp;
-	struct list_head *tmp1;
+	struct cifsFileInfo *open_file;
 
 	if (!mapping || !mapping->host)
 		return -EFAULT;
@@ -945,49 +961,19 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 	if (mapping->host->i_size - offset < (loff_t)to)
 		to = (unsigned)(mapping->host->i_size - offset); 
 
-	cifsInode = CIFS_I(mapping->host);
-	read_lock(&GlobalSMBSeslock); 
-	/* BB we should start at the end */
-	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
-		open_file = list_entry(tmp, struct cifsFileInfo, flist);
-		if (open_file->closePend)
-			continue;
-		/* We check if file is open for writing first */
-		if ((open_file->pfile) && 
-		   ((open_file->pfile->f_flags & O_RDWR) || 
-			(open_file->pfile->f_flags & O_WRONLY))) {
-			read_unlock(&GlobalSMBSeslock);
-			bytes_written = cifs_write(open_file->pfile,
-						write_data, to-from,
-						&offset);
-			read_lock(&GlobalSMBSeslock);
+	open_file = find_writable_file(CIFS_I(mapping->host));
+	if (open_file) {
+		bytes_written = cifs_write(open_file->pfile, write_data,
+					   to-from, &offset);
 		/* Does mm or vfs already set times? */
-			inode->i_atime = 
-			inode->i_mtime = current_fs_time(inode->i_sb);
-			if ((bytes_written > 0) && (offset)) {
-				rc = 0;
-			} else if (bytes_written < 0) {
-				if (rc == -EBADF) {
-				/* have seen a case in which kernel seemed to
-				   have closed/freed a file even with writes
-				   active so we might as well see if there are
-				   other file structs to try for the same
-				   inode before giving up */
-					continue;
-				} else
-					rc = bytes_written;
-			}
-			break;  /* now that we found a valid file handle and
-				   tried to write to it we are done, no sense
-				   continuing to loop looking for another */
-		}
-		if (tmp->next == NULL) {
-			cFYI(1, ("File instance %p removed", tmp));
-			break;
+		inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
+		if ((bytes_written > 0) && (offset)) {
+			rc = 0;
+		} else if (bytes_written < 0) {
+			if (rc != -EBADF)
+				rc = bytes_written;
 		}
-	}
-	read_unlock(&GlobalSMBSeslock);
-	if (open_file == NULL) {
+	} else {
 		cFYI(1, ("No writeable filehandles for inode"));
 		rc = -EIO;
 	}
@@ -1604,40 +1590,12 @@ static int cifs_readpage(struct file *file, struct page *page)
    page caching in the current Linux kernel design */
 int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
 {
-	struct list_head *tmp;
-	struct list_head *tmp1;
-	struct cifsFileInfo *open_file = NULL;
-	int rc = TRUE;
-
-	if (cifsInode == NULL)
-		return rc;
-
-	read_lock(&GlobalSMBSeslock); 
-	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
-		open_file = list_entry(tmp, struct cifsFileInfo, flist);
-		if (open_file == NULL)
-			break;
-		if (open_file->closePend)
-			continue;
-	/* We check if file is open for writing,   
-	   BB we could supplement this with a check to see if file size
-	   changes have been flushed to server - ie inode metadata dirty */
-		if ((open_file->pfile) && 
-		    ((open_file->pfile->f_flags & O_RDWR) || 
-		    (open_file->pfile->f_flags & O_WRONLY))) {
-			rc = FALSE;
-			break;
-		}
-		if (tmp->next == NULL) {
-			cFYI(1, ("File instance %p removed", tmp));
-			break;
-		}
-	}
-	read_unlock(&GlobalSMBSeslock);
-	return rc;
+	if (cifsInode && find_writable_file(cifsInode))
+		return 0;
+	else
+		return 1;
 }
 
-
 static int cifs_prepare_write(struct file *file, struct page *page,
 	unsigned from, unsigned to)
 {
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index ca3af4eafcb2..49efdefcff7c 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -995,7 +995,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 	filemap_fdatawait(direntry->d_inode->i_mapping);
 
 	if (attrs->ia_valid & ATTR_SIZE) {
-		read_lock(&GlobalSMBSeslock);
 		/* To avoid spurious oplock breaks from server, in the case of
 		   inodes that we already have open, avoid doing path based
 		   setting of file size if we can do it by handle.
@@ -1003,49 +1002,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 		   when the local oplock break takes longer to flush
 		   writebehind data than the SMB timeout for the SetPathInfo
 		   request would allow */
-		list_for_each(tmp, &cifsInode->openFileList) {
-			open_file = list_entry(tmp, struct cifsFileInfo,
-					       flist);
-			/* We check if file is open for writing first */
-			if ((open_file->pfile) &&
-			    ((open_file->pfile->f_flags & O_RDWR) ||
-			    (open_file->pfile->f_flags & O_WRONLY))) {
-				if (open_file->invalidHandle == FALSE) {
-					/* we found a valid, writeable network
-					   file handle to use to try to set the
-					   file size */
-					__u16 nfid = open_file->netfid;
-					__u32 npid = open_file->pid;
-					read_unlock(&GlobalSMBSeslock);
-					found = TRUE;
-					rc = CIFSSMBSetFileSize(xid, pTcon,
-						attrs->ia_size, nfid, npid,
-						FALSE);
-					cFYI(1, ("SetFileSize by handle "
-						 "(setattrs) rc = %d", rc));
-					/* Do not need reopen and retry on
-					   EAGAIN since we will retry by
-					   pathname below */
-
-					/* now that we found one valid file
-					   handle no sense continuing to loop
-					   trying others, so break here */
-					if(rc == -EINVAL) {
-						int bytes_written;
-						rc = CIFSSMBWrite(xid, pTcon,
-							nfid, 0,
-							attrs->ia_size, 
-							&bytes_written, NULL,
-							NULL, 1 /* 45 sec */);
-						cFYI(1,("wrt seteof rc %d",rc));
-					}
-					break;
-				}
+		open_file = find_writable_file(cifsInode);
+		if (open_file) {
+			__u16 nfid = open_file->netfid;
+			__u32 npid = open_file->pid;
+			rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
+						nfid, npid, FALSE);
+			cFYI(1,("SetFSize for attrs rc = %d", rc));
+			if(rc == -EINVAL) {
+				int bytes_written;
+				rc = CIFSSMBWrite(xid, pTcon,
+						  nfid, 0, attrs->ia_size,
+						  &bytes_written, NULL, NULL,
+						  1 /* 45 seconds */);
+				cFYI(1,("Wrt seteof rc %d", rc));
 			}
 		}
-		if (found == FALSE)
-			read_unlock(&GlobalSMBSeslock);
-
 		if (rc != 0) {
 			/* Set file size by pathname rather than by handle
 			   either because no valid, writeable file handle for
-- 
cgit v1.2.3


From 37c0eb4677f733a773df6287b0f73f00274402e3 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 5 Oct 2005 14:50:29 -0700
Subject: CIFS: implement cifs_writepages to perform multi-page I/O

Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/file.c      | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/cifs/transport.c |  10 +--
 2 files changed, 190 insertions(+), 11 deletions(-)

diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 94875455d7fa..0473b221f643 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -21,11 +21,14 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <linux/fs.h>
+#include <linux/backing-dev.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
+#include <linux/mpage.h>
 #include <linux/pagemap.h>
 #include <linux/pagevec.h>
 #include <linux/smp_lock.h>
+#include <linux/writeback.h>
 #include <asm/div64.h>
 #include "cifsfs.h"
 #include "cifspdu.h"
@@ -916,6 +919,16 @@ static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
 		    ((open_file->pfile->f_flags & O_RDWR) ||
 		     (open_file->pfile->f_flags & O_WRONLY))) {
 			read_unlock(&GlobalSMBSeslock);
+			if(open_file->invalidHandle) {
+				rc = cifs_reopen_file(cifs_inode->vfs_inode, 
+						      open_file->pfile, FALSE);
+				/* if it fails, try another handle - might be */
+				/* dangerous to hold up writepages with retry */
+				if(rc) {
+					read_lock(&GlobalSMBSeslock);
+					continue;
+				}
+			}
 			return open_file;
 		}
 	}
@@ -982,20 +995,181 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 	return rc;
 }
 
-#if 0
+#ifdef CONFIG_CIFS_EXPERIMENTAL
 static int cifs_writepages(struct address_space *mapping,
-	struct writeback_control *wbc)
+			   struct writeback_control *wbc)
 {
-	int rc = -EFAULT;
+	struct backing_dev_info *bdi = mapping->backing_dev_info;
+	unsigned int bytes_to_write;
+	unsigned int bytes_written;
+	struct cifs_sb_info *cifs_sb;
+	int done = 0;
+	pgoff_t end = -1;
+	pgoff_t index;
+	int is_range = 0;
+	struct kvec iov[32];
+	int n_iov = 0;
+	pgoff_t next;
+	int nr_pages;
+	__u64 offset = 0;
+	struct cifsFileInfo *open_file = NULL;
+	struct page *page;
+	struct pagevec pvec;
+	int rc = 0;
+	int scanned = 0;
 	int xid;
 
+	cifs_sb = CIFS_SB(mapping->host->i_sb);
+	
+	/*
+	 * If wsize is smaller that the page cache size, default to writing
+	 * one page at a time via cifs_writepage
+	 */
+	if (cifs_sb->wsize < PAGE_CACHE_SIZE)
+		return generic_writepages(mapping, wbc);
+
+	/*
+	 * BB: Is this meaningful for a non-block-device file system?
+	 * If it is, we should test it again after we do I/O
+	 */
+	if (wbc->nonblocking && bdi_write_congested(bdi)) {
+		wbc->encountered_congestion = 1;
+		return 0;
+	}
+
 	xid = GetXid();
 
-	/* Find contiguous pages then iterate through repeating
-	   call 16K write then Setpageuptodate or if LARGE_WRITE_X
-	   support then send larger writes via kevec so as to eliminate
-	   a memcpy */
+	pagevec_init(&pvec, 0);
+	if (wbc->sync_mode == WB_SYNC_NONE)
+		index = mapping->writeback_index; /* Start from prev offset */
+	else {
+		index = 0;
+		scanned = 1;
+	}
+	if (wbc->start || wbc->end) {
+		index = wbc->start >> PAGE_CACHE_SHIFT;
+		end = wbc->end >> PAGE_CACHE_SHIFT;
+		is_range = 1;
+		scanned = 1;
+	}
+retry:
+	while (!done && (index <= end) &&
+	       (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+			PAGECACHE_TAG_DIRTY,
+			min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
+		int first;
+		unsigned int i;
+
+		if (!open_file) {
+			open_file = find_writable_file(CIFS_I(mapping->host));
+			if (!open_file) {
+				pagevec_release(&pvec);
+				cERROR(1, ("No writable handles for inode"));
+				return -EIO;
+			}
+		}
+
+		first = -1;
+		next = 0;
+		n_iov = 0;
+		bytes_to_write = 0;
+
+		for (i = 0; i < nr_pages; i++) {
+			page = pvec.pages[i];
+			/*
+			 * At this point we hold neither mapping->tree_lock nor
+			 * lock on the page itself: the page may be truncated or
+			 * invalidated (changing page->mapping to NULL), or even
+			 * swizzled back from swapper_space to tmpfs file
+			 * mapping
+			 */
+
+			if (first < 0)
+				lock_page(page);
+			else if (TestSetPageLocked(page))
+				break;
+
+			if (unlikely(page->mapping != mapping)) {
+				unlock_page(page);
+				break;
+			}
+
+			if (unlikely(is_range) && (page->index > end)) {
+				done = 1;
+				unlock_page(page);
+				break;
+			}
+
+			if (next && (page->index != next)) {
+				/* Not next consecutive page */
+				unlock_page(page);
+				break;
+			}
+
+			if (wbc->sync_mode != WB_SYNC_NONE)
+				wait_on_page_writeback(page);
+
+			if (PageWriteback(page) ||
+					!test_clear_page_dirty(page)) {
+				unlock_page(page);
+				break;
+			}
+			/*
+			 * BB can we get rid of this?  pages are held by pvec
+			 */
+			page_cache_get(page);
+
+			/* reserve iov[0] for the smb header */
+			n_iov++;
+			iov[n_iov].iov_base = kmap(page);
+			iov[n_iov].iov_len = PAGE_CACHE_SIZE;
+			bytes_to_write += PAGE_CACHE_SIZE;
+
+			if (first < 0) {
+				first = i;
+				offset = page_offset(page);
+			}
+			next = page->index + 1;
+			if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
+				break;
+		}
+		if (n_iov) {
+			rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
+					   open_file->netfid, bytes_to_write,
+					   offset, &bytes_written, iov, n_iov,
+					   1);
+			if (rc || bytes_written < bytes_to_write) {
+				cERROR(1,("CIFSSMBWrite2 returned %d, written = %x",
+					  rc, bytes_written));
+				set_bit(AS_EIO, &mapping->flags);
+				SetPageError(page);
+			}
+			for (i = 0; i < n_iov; i++) {
+				page = pvec.pages[first + i];
+				kunmap(page);
+				unlock_page(page);
+				page_cache_release(page);
+			}
+			if ((wbc->nr_to_write -= n_iov) <= 0)
+				done = 1;
+			index = next;
+		}
+		pagevec_release(&pvec);
+	}
+	if (!scanned && !done) {
+		/*
+		 * We hit the last page and there is more work to be done: wrap
+		 * back to the start of the file
+		 */
+		scanned = 1;
+		index = 0;
+		goto retry;
+	}
+	if (!is_range)
+		mapping->writeback_index = index;
+
 	FreeXid(xid);
+
 	return rc;
 }
 #endif
@@ -1635,6 +1809,9 @@ struct address_space_operations cifs_addr_ops = {
 	.readpage = cifs_readpage,
 	.readpages = cifs_readpages,
 	.writepage = cifs_writepage,
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+	.writepages = cifs_writepages,
+#endif
 	.prepare_write = cifs_prepare_write,
 	.commit_write = cifs_commit_write,
 	.set_page_dirty = __set_page_dirty_nobuffers,
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 64c712629f27..e104c1ad2da3 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -395,7 +395,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 	if (long_op == -1)
 		goto cifs_no_response_exit2;
 	else if (long_op == 2) /* writes past end of file can take loong time */
-		timeout = 300 * HZ;
+		timeout = 180 * HZ;
 	else if (long_op == 1)
 		timeout = 45 * HZ; /* should be greater than 
 			servers oplock break timeout (about 43 seconds) */
@@ -431,7 +431,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 		spin_unlock(&GlobalMid_Lock);
 		receive_len = midQ->resp_buf->smb_buf_length;
 	} else {
-		cERROR(1,("No response buffer"));
+		cERROR(1,("No response to cmd %d mid %d",
+			midQ->command, midQ->mid));
 		if(midQ->midState == MID_REQUEST_SUBMITTED) {
 			if(ses->server->tcpStatus == CifsExiting)
 				rc = -EHOSTDOWN;
@@ -646,7 +647,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 	if (long_op == -1)
 		goto cifs_no_response_exit;
 	else if (long_op == 2) /* writes past end of file can take loong time */
-		timeout = 300 * HZ;
+		timeout = 180 * HZ;
 	else if (long_op == 1)
 		timeout = 45 * HZ; /* should be greater than 
 			servers oplock break timeout (about 43 seconds) */
@@ -682,7 +683,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 		spin_unlock(&GlobalMid_Lock);
 		receive_len = midQ->resp_buf->smb_buf_length;
 	} else {
-		cERROR(1,("No response buffer"));
+		cERROR(1,("No response for cmd %d mid %d",
+			  midQ->command, midQ->mid));
 		if(midQ->midState == MID_REQUEST_SUBMITTED) {
 			if(ses->server->tcpStatus == CifsExiting)
 				rc = -EHOSTDOWN;
-- 
cgit v1.2.3


From 4a77118cd5018fec11bf86f6f8d659352ad9a92b Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 5 Oct 2005 15:14:33 -0700
Subject: CIFS: Allow wsize to exceed CIFSMaxBufSize

This allows cifs_writepages to send data in larger chunks from the page
cache, without requiring larger memory allocations in other cases.

Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/connect.c   |  2 +-
 fs/cifs/file.c      |  8 ++++++++
 fs/cifs/transport.c | 16 +---------------
 3 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f05d9e2016d5..31eb9a3bf627 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1740,7 +1740,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			cifs_sb->rsize = volume_info.rsize;
 		else
 			cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
-		if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
+		if(volume_info.wsize)
 			cifs_sb->wsize = volume_info.wsize;
 		else
 			cifs_sb->wsize = CIFSMaxBufSize; /* default */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 0473b221f643..0f66ae5b694b 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -925,6 +925,7 @@ static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
 				/* if it fails, try another handle - might be */
 				/* dangerous to hold up writepages with retry */
 				if(rc) {
+					cFYI(1,("failed on reopen file in wp"));
 					read_lock(&GlobalSMBSeslock);
 					continue;
 				}
@@ -1028,6 +1029,13 @@ static int cifs_writepages(struct address_space *mapping,
 	if (cifs_sb->wsize < PAGE_CACHE_SIZE)
 		return generic_writepages(mapping, wbc);
 
+	/* BB FIXME we do not have code to sign across multiple buffers yet,
+	   so go to older writepage style write which we can sign if needed */
+	if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
+		if(cifs_sb->tcon->ses->server->secMode &
+                          (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+			return generic_writepages(mapping, wbc);
+
 	/*
 	 * BB: Is this meaningful for a non-block-device file system?
 	 * If it is, we should test it again after we do I/O
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index e104c1ad2da3..c86b7077b92f 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -361,22 +361,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 		return -ENOMEM;
 	}
 
-	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
-		up(&ses->server->tcpSem);
-		cERROR(1,
-		       ("Illegal length, greater than maximum frame, %d ",
-			in_buf->smb_buf_length));
-		DeleteMidQEntry(midQ);
-		/* If not lock req, update # of requests on wire to server */
-		if(long_op < 3) {
-			atomic_dec(&ses->server->inFlight); 
-			wake_up(&ses->server->request_q);
-		}
-		return -EIO;
-	}
-
 /* BB FIXME */
-/* 	rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */
+/* 	rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
 	rc = smb_send2(ses->server->ssocket, iov, n_vec,
-- 
cgit v1.2.3


From dd99cd803d460576cf84f012786ff39814b73f7f Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 5 Oct 2005 19:32:49 -0700
Subject: [CIFS] cleanup sparse and compile errors in previous fix

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/file.c  | 5 +++--
 fs/cifs/inode.c | 2 --
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 0f66ae5b694b..39b23f4fa6c3 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -907,9 +907,10 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 	return total_written;
 }
 
-static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
+struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
 {
 	struct cifsFileInfo *open_file;
+	int rc;
 
 	read_lock(&GlobalSMBSeslock);
 	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
@@ -920,7 +921,7 @@ static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
 		     (open_file->pfile->f_flags & O_WRONLY))) {
 			read_unlock(&GlobalSMBSeslock);
 			if(open_file->invalidHandle) {
-				rc = cifs_reopen_file(cifs_inode->vfs_inode, 
+				rc = cifs_reopen_file(&cifs_inode->vfs_inode, 
 						      open_file->pfile, FALSE);
 				/* if it fails, try another handle - might be */
 				/* dangerous to hold up writepages with retry */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 49efdefcff7c..ff4d1cc7c248 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -962,7 +962,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 	struct cifsTconInfo *pTcon;
 	char *full_path = NULL;
 	int rc = -EACCES;
-	int found = FALSE;
 	struct cifsFileInfo *open_file = NULL;
 	FILE_BASIC_INFO time_buf;
 	int set_time = FALSE;
@@ -970,7 +969,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 	__u64 uid = 0xFFFFFFFFFFFFFFFFULL;
 	__u64 gid = 0xFFFFFFFFFFFFFFFFULL;
 	struct cifsInodeInfo *cifsInode;
-	struct list_head *tmp;
 
 	xid = GetXid();
 
-- 
cgit v1.2.3


From 131afd0b748e382c3a00355d3fa245801f929298 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Fri, 7 Oct 2005 09:51:05 -0700
Subject: [CIFS] /proc/fs/cifs debug code cleanup and new stats2

These changes to debug code and new stats are helpful in
debugging potential tcp performance/configuration problems under cifs.

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifs_debug.c | 16 ++++++++++++----
 fs/cifs/cifsglob.h   |  6 +++++-
 fs/cifs/transport.c  | 24 ++++++++++++++++++++++++
 3 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index f4c6544468ab..785239618d89 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -81,6 +81,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 	buf += length;
 	length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION);
 	buf += length;
+	length = sprintf(buf,"Active VFS Requests: %d\n", GlobalTotalActiveXid);
+	buf += length;
 	length = sprintf(buf, "Servers:");
 	buf += length;
 
@@ -97,7 +99,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 		} else {
 			length =
 			    sprintf(buf,
-				    "\n%d) Name: %s  Domain: %s Mounts: %d ServerOS: %s  \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t",
+				    "\n%d) Name: %s  Domain: %s Mounts: %d OS: %s  \n\tNOS: %s\tCapability: 0x%x\n\tSMB session status: %d\t",
 				i, ses->serverName, ses->serverDomain,
 				atomic_read(&ses->inUse),
 				ses->serverOS, ses->serverNOS,
@@ -105,12 +107,18 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 			buf += length;
 		}
 		if(ses->server) {
-			buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d",
+			buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d",
 				ses->server->tcpStatus,
 				atomic_read(&ses->server->socketUseCount),
 				ses->server->secMode,
 				atomic_read(&ses->server->inFlight));
-			
+
+#ifdef CONFIG_CIFS_STATS2
+			buf += sprintf(buf, "\tIn Send: %d In MaxReq Wait: %d",
+				atomic_read(&ses->server->inSend), 
+				atomic_read(&ses->server->num_waiters));
+#endif
+
 			length = sprintf(buf, "\nMIDs:\n");
 			buf += length;
 
@@ -149,7 +157,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 		dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
 		length =
 		    sprintf(buf,
-			    "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d",
+			    "\n%d) %s Uses: %d Type: %s DevInfo: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d",
 			    i, tcon->treeName,
 			    atomic_read(&tcon->useCount),
 			    tcon->nativeFileSystem,
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index cd421c76805e..729717281b40 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -123,13 +123,17 @@ struct TCP_Server_Info {
 	struct list_head pending_mid_q;
 	void *Server_NlsInfo;	/* BB - placeholder for future NLS info  */
 	unsigned short server_codepage;	/* codepage for the server    */
-	unsigned long ip_address;	/* IP addr for the server if known     */
+	unsigned long ip_address;	/* IP addr for the server if known */
 	enum protocolEnum protocolType;	
 	char versionMajor;
 	char versionMinor;
 	unsigned svlocal:1;	/* local server or remote */
 	atomic_t socketUseCount; /* number of open cifs sessions on socket */
 	atomic_t inFlight;  /* number of requests on the wire to server */
+#ifdef CONFIG_CIFS_STATS2
+	atomic_t inSend; /* requests trying to send */
+	atomic_t num_waiters;   /* blocked waiting to get in sendrecv */
+#endif
 	enum statusEnum tcpStatus; /* what we think the status is */
 	struct semaphore tcpSem;
 	struct task_struct *tsk;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index c86b7077b92f..893a6fef9853 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -307,9 +307,15 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 			if(atomic_read(&ses->server->inFlight) >= 
 					cifs_max_pending){
 				spin_unlock(&GlobalMid_Lock);
+#ifdef CONFIG_CIFS_STATS2
+				atomic_inc(&ses->server->num_waiters);
+#endif
 				wait_event(ses->server->request_q,
 					atomic_read(&ses->server->inFlight)
 					 < cifs_max_pending);
+#ifdef CONFIG_CIFS_STATS2
+				atomic_dec(&ses->server->num_waiters);
+#endif
 				spin_lock(&GlobalMid_Lock);
 			} else {
 				if(ses->server->tcpStatus == CifsExiting) {
@@ -365,8 +371,14 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 /* 	rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
+#ifdef CONFIG_CIFS_STATS2
+	atomic_inc(&ses->server->inSend);
+#endif
 	rc = smb_send2(ses->server->ssocket, iov, n_vec,
 		      (struct sockaddr *) &(ses->server->addr.sockAddr));
+#ifdef CONFIG_CIFS_STATS2
+	atomic_dec(&ses->server->inSend);
+#endif
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
 		up(&ses->server->tcpSem);
@@ -546,9 +558,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 			if(atomic_read(&ses->server->inFlight) >= 
 					cifs_max_pending){
 				spin_unlock(&GlobalMid_Lock);
+#ifdef CONFIG_CIFS_STATS2
+				atomic_inc(&ses->server->num_waiters);
+#endif
 				wait_event(ses->server->request_q,
 					atomic_read(&ses->server->inFlight)
 					 < cifs_max_pending);
+#ifdef CONFIG_CIFS_STATS2
+				atomic_dec(&ses->server->num_waiters);
+#endif
 				spin_lock(&GlobalMid_Lock);
 			} else {
 				if(ses->server->tcpStatus == CifsExiting) {
@@ -617,8 +635,14 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
+#ifdef CONFIG_CIFS_STATS2
+	atomic_inc(&ses->server->inSend);
+#endif
 	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
 		      (struct sockaddr *) &(ses->server->addr.sockAddr));
+#ifdef CONFIG_CIFS_STATS2
+	atomic_dec(&ses->server->inSend);
+#endif
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
 		up(&ses->server->tcpSem);
-- 
cgit v1.2.3


From 68058e757573d4e81550e74c5a03a29a29069ce7 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 10 Oct 2005 10:34:22 -0700
Subject: [CIFS] Reduce CIFS tcp congestion timeout (it was too long) and
 backoff ever longer amounts (up to 15 seconds).  This improves performance
 especially when using large wsize.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifs_debug.c |  4 ++--
 fs/cifs/cifsfs.c     | 16 +++++++++++++---
 fs/cifs/transport.c  | 13 +++++++------
 3 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 785239618d89..b7fb064f6548 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -114,7 +114,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 				atomic_read(&ses->server->inFlight));
 
 #ifdef CONFIG_CIFS_STATS2
-			buf += sprintf(buf, "\tIn Send: %d In MaxReq Wait: %d",
+			buf += sprintf(buf, " In Send: %d In MaxReq Wait: %d",
 				atomic_read(&ses->server->inSend), 
 				atomic_read(&ses->server->num_waiters));
 #endif
@@ -267,7 +267,7 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
 			atomic_read(&tcon->num_oplock_brks));
 		buf += item_length;
 		length += item_length;
-		item_length = sprintf(buf, "\nReads: %d Bytes %lld",
+		item_length = sprintf(buf, "\nReads:  %d Bytes %lld",
 			atomic_read(&tcon->num_reads),
 			(long long)(tcon->bytes_read));
 		buf += item_length;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 1f97d39100ee..e3177a031edc 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -405,6 +405,16 @@ static struct quotactl_ops cifs_quotactl_ops = {
 };
 #endif
 
+static void cifs_umount_begin(struct super_block * sblock)
+{
+	cERROR(1,("kill all tasks now - umount begin not implemented yet"));
+
+/* BB FIXME - finish BB */
+
+	return;
+}
+	
+
 static int cifs_remount(struct super_block *sb, int *flags, char *data)
 {
 	*flags |= MS_NODIRATIME;
@@ -422,7 +432,7 @@ struct super_operations cifs_super_ops = {
    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,
-/*    .umount_begin   = cifs_umount_begin, *//* consider adding in the future */
+/*	.umount_begin   = cifs_umount_begin, */ /* BB finish in the future */
 	.remount_fs = cifs_remount,
 };
 
@@ -790,9 +800,7 @@ static int cifs_oplock_thread(void * dummyarg)
 	do {
 		if(try_to_freeze()) 
 			continue;
-		set_current_state(TASK_INTERRUPTIBLE);
 		
-		schedule_timeout(1*HZ);  
 		spin_lock(&GlobalMid_Lock);
 		if(list_empty(&GlobalOplock_Q)) {
 			spin_unlock(&GlobalMid_Lock);
@@ -841,6 +849,8 @@ static int cifs_oplock_thread(void * dummyarg)
 				}
 			} else
 				spin_unlock(&GlobalMid_Lock);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);  /* yield in case q were corrupt */
 		}
 	} while(!signal_pending(current));
 	oplockThread = NULL;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 893a6fef9853..d9b11690746d 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -157,14 +157,14 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
 		/* smaller timeout here than send2 since smaller size */
 		/* Although it may not be required, this also is smaller 
 		   oplock break time */  
-			if(i > 30) {
+			if(i > 12) {
 				cERROR(1,
-				   ("sends on sock %p stuck for 15 seconds",
+				   ("sends on sock %p stuck for 7 seconds",
 				    ssocket));
 				rc = -EAGAIN;
 				break;
 			}
-			msleep(500);
+			msleep(1 << i);
 			continue;
 		}
 		if (rc < 0) 
@@ -224,14 +224,14 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
 				    n_vec - first_vec, total_len);
 		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
 			i++;
-			if(i > 40) {
+			if(i >= 14) {
 				cERROR(1,
-				   ("sends on sock %p stuck for 20 seconds",
+				   ("sends on sock %p stuck for 15 seconds",
 				    ssocket));
 				rc = -EAGAIN;
 				break;
 			}
-			msleep(500);
+			msleep(1 << i);
 			continue;
 		}
 		if (rc < 0) 
@@ -249,6 +249,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
 			continue;
 		}
 		total_len -= rc;
+		/* the line below resets i */
 		for (i = first_vec; i < n_vec; i++) {
 			if (iov[i].iov_len) {
 				if (rc > iov[i].iov_len) {
-- 
cgit v1.2.3


From 0ae0efada36219024e4e3008f16c993d5d091280 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 10 Oct 2005 10:57:19 -0700
Subject: [CIFS] Fix rsize calculation so that large readx flag is checked.

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifs_debug.c |  2 +-
 fs/cifs/connect.c    | 29 ++++++++++++++++++++++++-----
 fs/cifs/file.c       |  5 +++--
 3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index b7fb064f6548..6f7810992db3 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -267,7 +267,7 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
 			atomic_read(&tcon->num_oplock_brks));
 		buf += item_length;
 		length += item_length;
-		item_length = sprintf(buf, "\nReads:  %d Bytes %lld",
+		item_length = sprintf(buf, "\nReads:  %d Bytes: %lld",
 			atomic_read(&tcon->num_reads),
 			(long long)(tcon->bytes_read));
 		buf += item_length;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 31eb9a3bf627..d1c6acee620e 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -30,6 +30,7 @@
 #include <linux/mempool.h>
 #include <linux/delay.h>
 #include <linux/completion.h>
+#include <linux/pagevec.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include "cifspdu.h"
@@ -188,6 +189,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
 					server->server_RFC1001_name);
 		}
 		if(rc) {
+			cERROR(1,("reconnect error %d",rc));
 			msleep(3000);
 		} else {
 			atomic_inc(&tcpSesReconnectCount);
@@ -469,6 +471,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 			} else {
 				/* give server a second to
 				clean up before reconnect attempt */
+				cERROR(1,("sleep before reconnect"));
 				msleep(1000);
 				/* always try 445 first on reconnect
 				since we get NACK on some if we ever
@@ -556,6 +559,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 		dump_smb(smb_buffer, length);
 		if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
 			cERROR(1, ("Bad SMB Received "));
+			cifs_dump_mem("smb: ", smb_buffer, 48);
 			continue;
 		}
 
@@ -1383,7 +1387,9 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
 		the default. sock_setsockopt not used because it expects 
 		user space buffer */
 	(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
-
+	 cERROR(1,("sndbuf %d rcvbuf %d reset to 200K each",(*csocket)->sk->sk_sndbuf, (*csocket)->sk->sk_rcvbuf));
+	(*csocket)->sk->sk_sndbuf = 300 * 1024;
+	(*csocket)->sk->sk_rcvbuf = 200 * 1024;
 	/* send RFC1001 sessinit */
 
 	if(psin_server->sin_port == htons(RFC1001_PORT)) {
@@ -1736,11 +1742,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
     
 	/* search for existing tcon to this server share */
 	if (!rc) {
-		if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
+		if(volume_info.rsize > CIFSMaxBufSize) {
+			cERROR(1,("rsize %d too large, using MaxBufSize",
+				volume_info.rsize));
+			cifs_sb->rsize = CIFSMaxBufSize;
+		} else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
 			cifs_sb->rsize = volume_info.rsize;
-		else
-			cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
-		if(volume_info.wsize)
+		else /* default */
+			cifs_sb->rsize = CIFSMaxBufSize;
+
+		if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
+			cERROR(1,("wsize %d too large using 4096 instead",
+				  volume_info.wsize));
+			cifs_sb->wsize = 4096;
+		} else if(volume_info.wsize)
 			cifs_sb->wsize = volume_info.wsize;
 		else
 			cifs_sb->wsize = CIFSMaxBufSize; /* default */
@@ -1895,6 +1910,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			cifs_sb->wsize = min(cifs_sb->wsize,
 					     (tcon->ses->server->maxBuf -
 					      MAX_CIFS_HDR_SIZE));
+		if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
+                        cifs_sb->rsize = min(cifs_sb->rsize,
+                                             (tcon->ses->server->maxBuf -
+                                              MAX_CIFS_HDR_SIZE));
 	}
 
 	/* volume_info.password is freed above when existing session found
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 39b23f4fa6c3..11806c879c47 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -855,7 +855,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 				struct kvec iov[2];
 				unsigned int len;
 
-				len = min(cifs_sb->wsize,
+				len = min((size_t)cifs_sb->wsize,
 					  write_size - total_written);
 				/* iov[0] is reserved for smb header */
 				iov[1].iov_base = (char *)write_data +
@@ -920,7 +920,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
 		    ((open_file->pfile->f_flags & O_RDWR) ||
 		     (open_file->pfile->f_flags & O_WRONLY))) {
 			read_unlock(&GlobalSMBSeslock);
-			if(open_file->invalidHandle) {
+			if((open_file->invalidHandle) && 
+			   (!open_file->closePend)) {
 				rc = cifs_reopen_file(&cifs_inode->vfs_inode, 
 						      open_file->pfile, FALSE);
 				/* if it fails, try another handle - might be */
-- 
cgit v1.2.3


From 190fdeb84499a2dc046adae2eebfdda49e315e96 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 10 Oct 2005 11:48:26 -0700
Subject: [CIFS] Fix byte range locking to Windows when Windows server returns
 illegal RFC1001 length (which had caused the lock to block forever until
 killed).

---
 fs/cifs/CHANGES | 12 ++++++++++++
 fs/cifs/README  |  4 ++--
 fs/cifs/TODO    |  6 +++---
 fs/cifs/misc.c  | 22 +++++++++++++++-------
 4 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 535177238020..1c249a2abae3 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,15 @@
+Version 1.38
+------------
+Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket)
+to be smaller at first (but increasing) so large write performance performance
+over GigE is better.  Do not hang thread on illegal byte range lock response
+from Windows (Windows can send an RFC1001 size which does not match smb size) by
+allowing an SMBs TCP length to be up to a few bytes longer than it should be.
+wsize and rsize can now be larger than negotiated buffer size if server
+supports large readx/writex, even when directio mount flag not specified.
+Write size will in many cases now be 16K instead of 4K which greatly helps
+file copy performance on lightly loaded networks.
+
 Version 1.37
 ------------
 Fix readdir caching when unlink removes file in current search buffer,
diff --git a/fs/cifs/README b/fs/cifs/README
index 3b610d08dc1e..5d9a953888d9 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -294,8 +294,8 @@ A partial list of the supported mount options follows:
 		during the local client kernel build will be used.
 		If server does not support Unicode, this parameter is
 		unused.
-  rsize		default read size
-  wsize		default write size
+  rsize		default read size (usually 16K)
+  wsize		default write size (usually 16K, 32K is often better over GigE)
   rw		mount the network share read-write (note that the
 		server may still consider the share read-only)
   ro		mount network share read-only
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index 0593f6447319..c909298d11ed 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,4 +1,4 @@
-version 1.36 September 6, 2005
+version 1.37 October 9, 2005
 
 A Partial List of Missing Features
 ==================================
@@ -38,8 +38,8 @@ by unlocking all known byte range locks that we locked on the file.
 i) quota support (needs minor kernel change since quota calls
 to make it to network filesystems or deviceless filesystems)
 
-j) finish writepages support (multi-page write behind for improved
-performance) and syncpage. Started by Shaggy.
+j) investigate sync behavior (including syncpage) and check  
+for proper behavior of intr/nointr
 
 k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
 extra copy in/out of the socket buffers in some cases.
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 8a0edd695f84..eba1de917f2a 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -420,6 +420,7 @@ int
 checkSMB(struct smb_hdr *smb, __u16 mid, int length)
 {
 	__u32 len = smb->smb_buf_length;
+	__u32 clc_len;  /* calculated length */
 	cFYI(0,
 	     ("Entering checkSMB with Length: %x, smb_buf_length: %x ",
 	      length, len));
@@ -440,20 +441,27 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
 			cERROR(1,
 			       ("smb_buf_length greater than MaxBufSize"));
 		cERROR(1,
-		       ("bad smb detected. Illegal length. The mid=%d",
+		       ("bad smb detected. Illegal length. mid=%d",
 			smb->Mid));
 		return 1;
 	}
 
 	if (checkSMBhdr(smb, mid))
 		return 1;
-
-	if ((4 + len != smbCalcSize_LE(smb))
+	clc_len = smbCalcSize_LE(smb);
+	if ((4 + len != clc_len)
 	    || (4 + len != (unsigned int)length)) {
-		cERROR(1, ("smbCalcSize %x ", smbCalcSize_LE(smb)));
-		cERROR(1,
-		       ("bad smb size detected. The Mid=%d", smb->Mid));
-		return 1;
+		cERROR(1, ("Calculated size 0x%x vs actual length 0x%x",
+				clc_len, 4 + len));
+		cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid));
+		/* Windows XP can return a few bytes too much, presumably
+		an illegal pad, at the end of byte range lock responses 
+		so we allow for up to eight byte pad, as long as actual
+		received length is as long or longer than calculated length */
+		if((4+len > clc_len) && (len <= clc_len + 3))
+			return 0;
+		else
+			return 1;
 	}
 	return 0;
 }
-- 
cgit v1.2.3


From 02c37a6df558fb8768c4c8ae792e86e9abf2d733 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 10 Oct 2005 11:49:37 -0700
Subject: [CIFS] Update cifs version to 1.38

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifsfs.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 0f6d352ab813..4cdb29fdc8c2 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -97,5 +97,5 @@ extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 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.37"
+#define CIFS_VERSION   "1.38"
 #endif				/* _CIFSFS_H */
-- 
cgit v1.2.3


From 5e1253b50111220f06ee13bc4e555d89ff39176b Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 10 Oct 2005 14:06:37 -0700
Subject: [CIFS] Correct cifs tcp retry when some data sent before getting
 EAGAIN. Continue implementation of cifs umount begin to allow force unmounts
 of cifs mounts.

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifsfs.c    | 19 +++++++++++++++++--
 fs/cifs/transport.c |  3 +++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index e3177a031edc..fd5eae37f2a8 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -407,9 +407,24 @@ static struct quotactl_ops cifs_quotactl_ops = {
 
 static void cifs_umount_begin(struct super_block * sblock)
 {
-	cERROR(1,("kill all tasks now - umount begin not implemented yet"));
+	struct cifs_sb_info *cifs_sb;
 
-/* BB FIXME - finish BB */
+	cifs_sb = CIFS_SB(sb);
+	if(cifs_sb == NULL)
+		return -EIO;
+	if(cifs_sb->tcon == NULL)
+		return -EIO;
+	down(&tcon->tconSem);
+	if (atomic_read(&tcon->useCount) == 1)
+		tcon->tidStatus = CifsExiting;
+	up(&tcon->tconSem);
+
+	if((cifs->sb->tcon->ses) && (cifs_sb->tcon->ses->server))
+	{
+		cERROR(1,("wake up tasks now - umount begin not complete"));
+		wake_up_all(&server->request_q);
+	}
+/* BB FIXME - finish add checks for tidStatus BB */
 
 	return;
 }
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index d9b11690746d..d8865fbd876a 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -169,6 +169,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
 		}
 		if (rc < 0) 
 			break;
+		else
+			i = 0; /* reset i after each successful send */
 		iov.iov_base += rc;
 		iov.iov_len -= rc;
 		len -= rc;
@@ -263,6 +265,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
 				}
 			}
 		}
+		i = 0; /* in case we get ENOSPC on the next send */
 	}
 
 	if (rc < 0) {
-- 
cgit v1.2.3


From b387eaeb666f6a5e24990a1f4d6a0447ae14315d Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 10 Oct 2005 14:21:15 -0700
Subject: [CIFS] Do not shrink tcp sndbuf/rcvbuf from their defaults

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/connect.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index d1c6acee620e..177289771abe 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -189,7 +189,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
 					server->server_RFC1001_name);
 		}
 		if(rc) {
-			cERROR(1,("reconnect error %d",rc));
+			cFYI(1,("reconnect error %d",rc));
 			msleep(3000);
 		} else {
 			atomic_inc(&tcpSesReconnectCount);
@@ -471,7 +471,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 			} else {
 				/* give server a second to
 				clean up before reconnect attempt */
-				cERROR(1,("sleep before reconnect"));
 				msleep(1000);
 				/* always try 445 first on reconnect
 				since we get NACK on some if we ever
@@ -558,8 +557,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 
 		dump_smb(smb_buffer, length);
 		if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
-			cERROR(1, ("Bad SMB Received "));
-			cifs_dump_mem("smb: ", smb_buffer, 48);
+			cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
 			continue;
 		}
 
@@ -1386,12 +1384,16 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
 	/* Eventually check for other socket options to change from 
 		the default. sock_setsockopt not used because it expects 
 		user space buffer */
+	 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
+		 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
 	(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
-	 cERROR(1,("sndbuf %d rcvbuf %d reset to 200K each",(*csocket)->sk->sk_sndbuf, (*csocket)->sk->sk_rcvbuf));
-	(*csocket)->sk->sk_sndbuf = 300 * 1024;
-	(*csocket)->sk->sk_rcvbuf = 200 * 1024;
-	/* send RFC1001 sessinit */
+	/* make the bufsizes depend on wsize/rsize and max requests */
+	if((*csocket)->sk->sk_sndbuf < (200 * 1024))
+		(*csocket)->sk->sk_sndbuf = 200 * 1024;
+	if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
+		(*csocket)->sk->sk_rcvbuf = 140 * 1024;
 
+	/* send RFC1001 sessinit */
 	if(psin_server->sin_port == htons(RFC1001_PORT)) {
 		/* some servers require RFC1001 sessinit before sending
 		negprot - BB check reconnection in case where second 
-- 
cgit v1.2.3


From 9e2e85f82fa280e937ee42152e7cbaff78be01a2 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 10 Oct 2005 14:28:38 -0700
Subject: [CIFS] Fix minor build problem with previous changeset

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/cifsfs.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index fd5eae37f2a8..99e087d3554f 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -408,21 +408,24 @@ static struct quotactl_ops cifs_quotactl_ops = {
 static void cifs_umount_begin(struct super_block * sblock)
 {
 	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo * tcon;
 
 	cifs_sb = CIFS_SB(sb);
 	if(cifs_sb == NULL)
-		return -EIO;
-	if(cifs_sb->tcon == NULL)
-		return -EIO;
+		return;
+
+	tcon = cifs_sb->tcon;
+	if(tcon == NULL)
+		return;
 	down(&tcon->tconSem);
 	if (atomic_read(&tcon->useCount) == 1)
 		tcon->tidStatus = CifsExiting;
 	up(&tcon->tconSem);
 
-	if((cifs->sb->tcon->ses) && (cifs_sb->tcon->ses->server))
+	if(tcon->ses && tcon->ses->server)
 	{
 		cERROR(1,("wake up tasks now - umount begin not complete"));
-		wake_up_all(&server->request_q);
+		wake_up_all(&tcon->ses->server->request_q);
 	}
 /* BB FIXME - finish add checks for tidStatus BB */
 
-- 
cgit v1.2.3


From 34210f33025a3256b9ac3f0a182f02f1879140cb Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 10 Oct 2005 14:31:13 -0700
Subject: [CIFS] Still missing a line from previous fix

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifsfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 99e087d3554f..3bc9db522600 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -410,7 +410,7 @@ static void cifs_umount_begin(struct super_block * sblock)
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo * tcon;
 
-	cifs_sb = CIFS_SB(sb);
+	cifs_sb = CIFS_SB(sblock);
 	if(cifs_sb == NULL)
 		return;
 
-- 
cgit v1.2.3


From 4ca9c190d902caa7efb899a4c7fc8c6e6d926e95 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 10 Oct 2005 19:52:13 -0700
Subject: [CIFS] Fix oops in experimental notify code (when
 CONFIG_CIFS_EXPERIMENTAL was turned on).

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/CHANGES  | 3 ++-
 fs/cifs/README   | 2 ++
 fs/cifs/cifsfs.c | 4 ++++
 fs/cifs/fcntl.c  | 4 ++++
 4 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 1c249a2abae3..b2a938378bef 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -8,7 +8,8 @@ allowing an SMBs TCP length to be up to a few bytes longer than it should be.
 wsize and rsize can now be larger than negotiated buffer size if server
 supports large readx/writex, even when directio mount flag not specified.
 Write size will in many cases now be 16K instead of 4K which greatly helps
-file copy performance on lightly loaded networks.
+file copy performance on lightly loaded networks.  Fix oops in dnotify
+when experimental config flag enabled.
 
 Version 1.37
 ------------
diff --git a/fs/cifs/README b/fs/cifs/README
index 5d9a953888d9..e7a3ce62d71b 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -296,6 +296,8 @@ A partial list of the supported mount options follows:
 		unused.
   rsize		default read size (usually 16K)
   wsize		default write size (usually 16K, 32K is often better over GigE)
+		maximum wsize currently allowed by CIFS is 57344 (14 4096 byte
+		pages)
   rw		mount the network share read-write (note that the
 		server may still consider the share read-only)
   ro		mount network share read-only
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 3bc9db522600..d2d16a9c1f05 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -901,6 +901,10 @@ init_cifs(void)
 	INIT_LIST_HEAD(&GlobalSMBSessionList);
 	INIT_LIST_HEAD(&GlobalTreeConnectionList);
 	INIT_LIST_HEAD(&GlobalOplock_Q);
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+	INIT_LIST_HEAD(&GlobalDnotifyReqList);
+	INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
+#endif	
 /*
  *  Initialize Global counters
  */
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
index d527e2c76073..a7a47bb36bf3 100644
--- a/fs/cifs/fcntl.c
+++ b/fs/cifs/fcntl.c
@@ -78,6 +78,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
 	__u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES;
 	__u16 netfid;
 
+
+	if(experimEnabled == 0)
+		return 0;
+
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
-- 
cgit v1.2.3


From 1047abc159b4eb4ba4a7342a0969e16e9d4b4c69 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 11 Oct 2005 19:58:06 -0700
Subject: [CIFS] CIFS Stats improvements

New cifs_writepages routine was not updated bytes written in cifs stats.
Also added ability to clear /proc/fs/cifs/Stats by writing (0 or 1) to it.
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/CHANGES      |  2 +-
 fs/cifs/README       | 11 +++++++++--
 fs/cifs/cifs_debug.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/cifs/cifs_debug.h |  5 ++++-
 fs/cifs/cifsglob.h   |  6 +++++-
 fs/cifs/connect.c    |  3 +++
 fs/cifs/file.c       |  3 +++
 fs/cifs/netmisc.c    |  2 +-
 fs/cifs/transport.c  | 25 ++++++++++++++++++++++++-
 9 files changed, 98 insertions(+), 8 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index b2a938378bef..f554a70c9cf3 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -9,7 +9,7 @@ wsize and rsize can now be larger than negotiated buffer size if server
 supports large readx/writex, even when directio mount flag not specified.
 Write size will in many cases now be 16K instead of 4K which greatly helps
 file copy performance on lightly loaded networks.  Fix oops in dnotify
-when experimental config flag enabled.
+when experimental config flag enabled. Make cifsFYI more granular.
 
 Version 1.37
 ------------
diff --git a/fs/cifs/README b/fs/cifs/README
index e7a3ce62d71b..bb90941826ad 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -482,9 +482,16 @@ These experimental features and tracing can be enabled by changing flags in
 kernel, e.g.  insmod cifs).  To enable a feature set it to 1 e.g.  to enable 
 tracing to the kernel message log type: 
 
-	echo 1 > /proc/fs/cifs/cifsFYI
+	echo 7 > /proc/fs/cifs/cifsFYI
 	
-and for more extensive tracing including the start of smb requests and responses
+cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel
+logging of various informational messages.  2 enables logging of non-zero
+SMB return codes while 4 enables logging of requests that take longer
+than one second to complete (except for byte range lock requests). 
+Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the
+source code (typically by setting it in the beginning of cifsglob.h),
+and setting it to seven enables all three.  Finally, tracing
+the start of smb requests and responses can be enabled via:
 
 	echo 1 > /proc/fs/cifs/traceSMB
 
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 6f7810992db3..f4054d695f81 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -203,6 +203,49 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 }
 
 #ifdef CONFIG_CIFS_STATS
+
+static int
+cifs_stats_write(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+        char c;
+        int rc;
+	struct list_head *tmp;
+	struct cifsTconInfo *tcon;
+
+        rc = get_user(c, buffer);
+        if (rc)
+                return rc;
+
+        if (c == '1' || c == 'y' || c == 'Y') {
+		read_lock(&GlobalSMBSeslock);
+		list_for_each(tmp, &GlobalTreeConnectionList) {
+			tcon = list_entry(tmp, struct cifsTconInfo,
+					cifsConnectionList);
+			atomic_set(&tcon->num_smbs_sent, 0);
+			atomic_set(&tcon->num_writes, 0);
+			atomic_set(&tcon->num_reads, 0);
+			atomic_set(&tcon->num_oplock_brks, 0);
+			atomic_set(&tcon->num_opens, 0);
+			atomic_set(&tcon->num_closes, 0);
+			atomic_set(&tcon->num_deletes, 0);
+			atomic_set(&tcon->num_mkdirs, 0);
+			atomic_set(&tcon->num_rmdirs, 0);
+			atomic_set(&tcon->num_renames, 0);
+			atomic_set(&tcon->num_t2renames, 0);
+			atomic_set(&tcon->num_ffirst, 0);
+			atomic_set(&tcon->num_fnext, 0);
+			atomic_set(&tcon->num_fclose, 0);
+			atomic_set(&tcon->num_hardlinks, 0);
+			atomic_set(&tcon->num_symlinks, 0);
+			atomic_set(&tcon->num_locks, 0);
+		}
+		read_unlock(&GlobalSMBSeslock);
+	}
+
+        return count;
+}
+
 static int
 cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
 		  int count, int *eof, void *data)
@@ -365,8 +408,10 @@ cifs_proc_init(void)
 				cifs_debug_data_read, NULL);
 
 #ifdef CONFIG_CIFS_STATS
-	create_proc_read_entry("Stats", 0, proc_fs_cifs,
+	pde = create_proc_read_entry("Stats", 0, proc_fs_cifs,
 				cifs_stats_read, NULL);
+	if (pde)
+		pde->write_proc = cifs_stats_write;
 #endif
 	pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs,
 				cifsFYI_read, NULL);
@@ -483,6 +528,8 @@ cifsFYI_write(struct file *file, const char __user *buffer,
 		cifsFYI = 0;
 	else if (c == '1' || c == 'y' || c == 'Y')
 		cifsFYI = 1;
+	else if((c > '1') && (c <= '9'))
+		cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */
 
 	return count;
 }
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h
index bf24d2828f68..4304d9dcfb6c 100644
--- a/fs/cifs/cifs_debug.h
+++ b/fs/cifs/cifs_debug.h
@@ -26,6 +26,9 @@
 void cifs_dump_mem(char *label, void *data, int length);
 extern int traceSMB;		/* flag which enables the function below */
 void dump_smb(struct smb_hdr *, int);
+#define CIFS_INFO	0x01
+#define CIFS_RC  	0x02
+#define CIFS_TIMER	0x04
 
 /*
  *	debug ON
@@ -36,7 +39,7 @@ void dump_smb(struct smb_hdr *, int);
 
 /* information message: e.g., configuration, major event */
 extern int cifsFYI;
-#define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg)
+#define cifsfyi(format,arg...) if (cifsFYI & CIFS_INFO) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg)
 
 #define cFYI(button,prspec) if (button) cifsfyi prspec
 
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 729717281b40..839a55667c3c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -377,7 +377,11 @@ struct mid_q_entry {
 	__u16 mid;		/* multiplex id */
 	__u16 pid;		/* process id */
 	__u32 sequence_number;  /* for CIFS signing */
-	struct timeval when_sent;	/* time when smb sent */
+	unsigned long when_alloc;  /* when mid was created */
+#ifdef CONFIG_CIFS_STATS2
+	unsigned long when_sent; /* time when smb send finished */
+	unsigned long when_received; /* when demux complete (taken off wire) */
+#endif
 	struct cifsSesInfo *ses;	/* smb was sent to this server */
 	struct task_struct *tsk;	/* task waiting for response */
 	struct smb_hdr *resp_buf;	/* response buffer */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 177289771abe..a8f0cbada0f0 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -605,6 +605,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 multi_t2_fnd:
 				task_to_wake = mid_entry->tsk;
 				mid_entry->midState = MID_RESPONSE_RECEIVED;
+#ifdef CONFIG_CIFS_STATS2
+				mid_entry->when_received = jiffies;
+#endif
 				break;
 			}
 		}
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 11806c879c47..585a62aebd59 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1153,6 +1153,9 @@ retry:
 					  rc, bytes_written));
 				set_bit(AS_EIO, &mapping->flags);
 				SetPageError(page);
+			} else {
+				cifs_stats_bytes_written(cifs_sb->tcon,
+							 bytes_written);
 			}
 			for (i = 0; i < n_iov; i++) {
 				page = pvec.pages[first + i];
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 29e6efc5597c..f7814689844b 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -813,7 +813,7 @@ map_smb_to_linux_error(struct smb_hdr *smb)
 	if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
 		/* translate the newer STATUS codes to old style errors and then to POSIX errors */
 		__u32 err = le32_to_cpu(smb->Status.CifsError);
-		if(cifsFYI)
+		if(cifsFYI & CIFS_RC)
 			cifs_print_status(err);
 		ntstatus_to_dos(err, &smberrclass, &smberrcode);
 	} else {
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index d8865fbd876a..981ea0d8b9cd 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -59,7 +59,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
 		temp->pid = current->pid;
 		temp->command = smb_buffer->Command;
 		cFYI(1, ("For smb_command %d", temp->command));
-		do_gettimeofday(&temp->when_sent);
+	/*	do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
+		/* when mid allocated can be before when sent */
+		temp->when_alloc = jiffies;
 		temp->ses = ses;
 		temp->tsk = current;
 	}
@@ -75,6 +77,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
 static void
 DeleteMidQEntry(struct mid_q_entry *midEntry)
 {
+#ifdef CONFIG_CIFS_STATS2
+	unsigned long now;
+#endif
 	spin_lock(&GlobalMid_Lock);
 	midEntry->midState = MID_FREE;
 	list_del(&midEntry->qhead);
@@ -84,6 +89,22 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
 		cifs_buf_release(midEntry->resp_buf);
 	else
 		cifs_small_buf_release(midEntry->resp_buf);
+#ifdef CONFIG_CIFS_STATS2
+	now = jiffies;
+	/* commands taking longer than one second are indications that
+	   something is wrong, unless it is quite a slow link or server */
+	if((now - midEntry->when_alloc) > HZ) {
+		if((cifsFYI & CIFS_TIMER) && 
+		   (midEntry->command != SMB_COM_LOCKING_ANDX)) {
+			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
+			       midEntry->command, midEntry->mid);
+			printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
+			       now - midEntry->when_alloc,
+			       now - midEntry->when_sent,
+			       now - midEntry->when_received);
+		}
+	}
+#endif
 	mempool_free(midEntry, cifs_mid_poolp);
 }
 
@@ -382,6 +403,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 		      (struct sockaddr *) &(ses->server->addr.sockAddr));
 #ifdef CONFIG_CIFS_STATS2
 	atomic_dec(&ses->server->inSend);
+	midQ->when_sent = jiffies;
 #endif
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
@@ -646,6 +668,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 		      (struct sockaddr *) &(ses->server->addr.sockAddr));
 #ifdef CONFIG_CIFS_STATS2
 	atomic_dec(&ses->server->inSend);
+	midQ->when_sent = jiffies;
 #endif
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
-- 
cgit v1.2.3


From 47c786e79b46ef478a1123cb57c711ecb481cbfa Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 11 Oct 2005 20:03:18 -0700
Subject: [CIFS] Add null malloc response check in notify experimental code

Signed-off-by: Steve French (sfrench@us.ibm.com)
---
 fs/cifs/cifs_debug.c |  2 +-
 fs/cifs/cifssmb.c    | 32 +++++++++++++++++++-------------
 2 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index f4054d695f81..22a444a3fe4c 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -217,7 +217,7 @@ cifs_stats_write(struct file *file, const char __user *buffer,
         if (rc)
                 return rc;
 
-        if (c == '1' || c == 'y' || c == 'Y') {
+        if (c == '1' || c == 'y' || c == 'Y' || c == '0') {
 		read_lock(&GlobalSMBSeslock);
 		list_for_each(tmp, &GlobalTreeConnectionList) {
 			tcon = list_entry(tmp, struct cifsTconInfo,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 41996a240149..9312bfc56682 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -4294,20 +4294,26 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
 		cFYI(1, ("Error in Notify = %d", rc));
 	} else {
 		/* Add file to outstanding requests */
+		/* BB change to kmem cache alloc */	
 		dnotify_req = (struct dir_notify_req *) kmalloc(
-						sizeof(struct dir_notify_req), GFP_KERNEL);
-		dnotify_req->Pid = pSMB->hdr.Pid;
-		dnotify_req->PidHigh = pSMB->hdr.PidHigh;
-		dnotify_req->Mid = pSMB->hdr.Mid;
-		dnotify_req->Tid = pSMB->hdr.Tid;
-		dnotify_req->Uid = pSMB->hdr.Uid;
-		dnotify_req->netfid = netfid;
-		dnotify_req->pfile = pfile;
-		dnotify_req->filter = filter;
-		dnotify_req->multishot = multishot;
-		spin_lock(&GlobalMid_Lock);
-		list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList);
-		spin_unlock(&GlobalMid_Lock);
+						sizeof(struct dir_notify_req),
+						 GFP_KERNEL);
+		if(dnotify_req) {
+			dnotify_req->Pid = pSMB->hdr.Pid;
+			dnotify_req->PidHigh = pSMB->hdr.PidHigh;
+			dnotify_req->Mid = pSMB->hdr.Mid;
+			dnotify_req->Tid = pSMB->hdr.Tid;
+			dnotify_req->Uid = pSMB->hdr.Uid;
+			dnotify_req->netfid = netfid;
+			dnotify_req->pfile = pfile;
+			dnotify_req->filter = filter;
+			dnotify_req->multishot = multishot;
+			spin_lock(&GlobalMid_Lock);
+			list_add_tail(&dnotify_req->lhead, 
+					&GlobalDnotifyReqList);
+			spin_unlock(&GlobalMid_Lock);
+		} else 
+			rc = -ENOMEM;
 	}
 	cifs_buf_release(pSMB);
 	return rc;	
-- 
cgit v1.2.3


From 84d2f07e8e5e2424eec0f5acfef6792c924a0549 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Wed, 12 Oct 2005 15:32:05 -0700
Subject: CIFS: cifs_writepages should not write beyond end of file

Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/file.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 585a62aebd59..23af20d5af7c 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1011,6 +1011,7 @@ static int cifs_writepages(struct address_space *mapping,
 	pgoff_t index;
 	int is_range = 0;
 	struct kvec iov[32];
+	int len;
 	int n_iov = 0;
 	pgoff_t next;
 	int nr_pages;
@@ -1124,16 +1125,26 @@ retry:
 				unlock_page(page);
 				break;
 			}
+
+			if (page_offset(page) >= mapping->host->i_size) {
+				done = 1;
+				unlock_page(page);
+				break;
+			}
+
 			/*
 			 * BB can we get rid of this?  pages are held by pvec
 			 */
 			page_cache_get(page);
 
+			len = min(mapping->host->i_size - page_offset(page),
+				  (loff_t)PAGE_CACHE_SIZE);
+
 			/* reserve iov[0] for the smb header */
 			n_iov++;
 			iov[n_iov].iov_base = kmap(page);
-			iov[n_iov].iov_len = PAGE_CACHE_SIZE;
-			bytes_to_write += PAGE_CACHE_SIZE;
+			iov[n_iov].iov_len = len;
+			bytes_to_write += len;
 
 			if (first < 0) {
 				first = i;
-- 
cgit v1.2.3


From 23e7dd7d95f6fdc167a6d6ddea79ced0af33bbff Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 20 Oct 2005 13:44:56 -0700
Subject: [CIFS] Defer close of file handle slightly if there are pending
 writes that need to get in ahead of it that depend on that file handle. Fixes
 occassional bad file handle errors on write with heavy use multiple process
 cases.

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/CHANGES    |  6 ++++
 fs/cifs/cifsfs.h   |  2 +-
 fs/cifs/cifsglob.h |  1 +
 fs/cifs/file.c     | 88 +++++++++++++++++++++++++++++++++++++++---------------
 fs/cifs/inode.c    |  1 +
 5 files changed, 73 insertions(+), 25 deletions(-)

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index f554a70c9cf3..5bab24f59053 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,9 @@
+Version 1.39
+------------
+Defer close of a file handle slightly if pending writes depend on that file handle
+(this reduces the EBADF bad file handle errors that can be logged under heavy
+stress on writes).
+
 Version 1.38
 ------------
 Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket)
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 4cdb29fdc8c2..1223fa81dbd2 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -97,5 +97,5 @@ extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 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.38"
+#define CIFS_VERSION   "1.39"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 839a55667c3c..1ba08f8c5bc4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -299,6 +299,7 @@ struct cifsFileInfo {
 	struct inode * pInode; /* needed for oplock break */
 	unsigned closePend:1;	/* file is marked to close */
 	unsigned invalidHandle:1;  /* file closed via session abend */
+	atomic_t wrtPending;   /* handle in use - defer close */
 	struct semaphore fh_sem; /* prevents reopen race after dead ses*/
 	char * search_resume_name; /* BB removeme BB */
 	unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 23af20d5af7c..da4f5e10b3cc 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -29,6 +29,7 @@
 #include <linux/pagevec.h>
 #include <linux/smp_lock.h>
 #include <linux/writeback.h>
+#include <linux/delay.h>
 #include <asm/div64.h>
 #include "cifsfs.h"
 #include "cifspdu.h"
@@ -50,6 +51,11 @@ static inline struct cifsFileInfo *cifs_init_private(
 	private_data->pInode = inode;
 	private_data->invalidHandle = FALSE;
 	private_data->closePend = FALSE;
+	/* we have to track num writers to the inode, since writepages
+	does not tell us which handle the write is for so there can
+	be a close (overlapping with write) of the filehandle that
+	cifs_writepages chose to use */
+	atomic_set(&private_data->wrtPending,0); 
 
 	return private_data;
 }
@@ -473,6 +479,20 @@ int cifs_close(struct inode *inode, struct file *file)
 			/* no sense reconnecting to close a file that is
 			   already closed */
 			if (pTcon->tidStatus != CifsNeedReconnect) {
+				int timeout = 2;
+				while((atomic_read(&pSMBFile->wrtPending) != 0)
+					 && (timeout < 1000) ) {
+					/* Give write a better chance to get to
+					server ahead of the close.  We do not
+					want to add a wait_q here as it would
+					increase the memory utilization as
+					the struct would be in each open file,
+					but this should give enough time to 
+					clear the socket */
+					cERROR(1,("close with pending writes"));
+					msleep(timeout);
+					timeout *= 4;
+				} 
 				write_unlock(&file->f_owner.lock);
 				rc = CIFSSMBClose(xid, pTcon,
 						  pSMBFile->netfid);
@@ -919,9 +939,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
 		if (open_file->pfile &&
 		    ((open_file->pfile->f_flags & O_RDWR) ||
 		     (open_file->pfile->f_flags & O_WRONLY))) {
+			atomic_inc(&open_file->wrtPending);
 			read_unlock(&GlobalSMBSeslock);
 			if((open_file->invalidHandle) && 
-			   (!open_file->closePend)) {
+			   (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
 				rc = cifs_reopen_file(&cifs_inode->vfs_inode, 
 						      open_file->pfile, FALSE);
 				/* if it fails, try another handle - might be */
@@ -929,6 +950,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
 				if(rc) {
 					cFYI(1,("failed on reopen file in wp"));
 					read_lock(&GlobalSMBSeslock);
+					/* can not use this handle, no write
+					pending on this one after all */
+					atomic_dec
+					     (&open_file->wrtPending);
 					continue;
 				}
 			}
@@ -981,6 +1006,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 	if (open_file) {
 		bytes_written = cifs_write(open_file->pfile, write_data,
 					   to-from, &offset);
+		atomic_dec(&open_file->wrtPending);
 		/* Does mm or vfs already set times? */
 		inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
 		if ((bytes_written > 0) && (offset)) {
@@ -1016,7 +1042,7 @@ static int cifs_writepages(struct address_space *mapping,
 	pgoff_t next;
 	int nr_pages;
 	__u64 offset = 0;
-	struct cifsFileInfo *open_file = NULL;
+	struct cifsFileInfo *open_file;
 	struct page *page;
 	struct pagevec pvec;
 	int rc = 0;
@@ -1071,15 +1097,6 @@ retry:
 		int first;
 		unsigned int i;
 
-		if (!open_file) {
-			open_file = find_writable_file(CIFS_I(mapping->host));
-			if (!open_file) {
-				pagevec_release(&pvec);
-				cERROR(1, ("No writable handles for inode"));
-				return -EIO;
-			}
-		}
-
 		first = -1;
 		next = 0;
 		n_iov = 0;
@@ -1155,18 +1172,32 @@ retry:
 				break;
 		}
 		if (n_iov) {
-			rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
-					   open_file->netfid, bytes_to_write,
-					   offset, &bytes_written, iov, n_iov,
-					   1);
-			if (rc || bytes_written < bytes_to_write) {
-				cERROR(1,("CIFSSMBWrite2 returned %d, written = %x",
-					  rc, bytes_written));
-				set_bit(AS_EIO, &mapping->flags);
-				SetPageError(page);
+			/* Search for a writable handle every time we call
+			 * CIFSSMBWrite2.  We can't rely on the last handle
+			 * we used to still be valid
+			 */
+			open_file = find_writable_file(CIFS_I(mapping->host));
+			if (!open_file) {
+				cERROR(1, ("No writable handles for inode"));
+				rc = -EBADF;
 			} else {
-				cifs_stats_bytes_written(cifs_sb->tcon,
-							 bytes_written);
+				rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
+						   open_file->netfid,
+						   bytes_to_write, offset,
+						   &bytes_written, iov, n_iov,
+						   1);
+				atomic_dec(&open_file->wrtPending);
+				if (rc || bytes_written < bytes_to_write) {
+					cERROR(1,("Write2 ret %d, written = %d",
+						  rc, bytes_written));
+					/* BB what if continued retry is
+					   requested via mount flags? */
+					set_bit(AS_EIO, &mapping->flags);
+					SetPageError(page);
+				} else {
+					cifs_stats_bytes_written(cifs_sb->tcon,
+								 bytes_written);
+				}
 			}
 			for (i = 0; i < n_iov; i++) {
 				page = pvec.pages[first + i];
@@ -1788,9 +1819,18 @@ static int cifs_readpage(struct file *file, struct page *page)
    page caching in the current Linux kernel design */
 int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
 {
-	if (cifsInode && find_writable_file(cifsInode))
+	struct cifsFileInfo *open_file = NULL;
+
+	if (cifsInode)
+		open_file =  find_writable_file(cifsInode);
+ 
+	if(open_file) {
+		/* there is not actually a write pending so let
+		this handle go free and allow it to
+		be closable if needed */
+		atomic_dec(&open_file->wrtPending);
 		return 0;
-	else
+	} else
 		return 1;
 }
 
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index ff4d1cc7c248..912d401600f6 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1006,6 +1006,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 			__u32 npid = open_file->pid;
 			rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
 						nfid, npid, FALSE);
+			atomic_dec(&open_file->wrtPending);
 			cFYI(1,("SetFSize for attrs rc = %d", rc));
 			if(rc == -EINVAL) {
 				int bytes_written;
-- 
cgit v1.2.3


From 0753ca7bc2b876dd136e9db11a20f85cbe4e08b1 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Thu, 27 Oct 2005 13:55:12 -0700
Subject: [CIFS] Change pragma pack(1) to attribute(packed) to allow cifs on
 arm to access unaligned structures coming in off the wire

gcc on arm processors generates very odd code with pragma pack specified -
although it does pack the structures in some sense - it does not allow you
to access unaligned elements in nested structures at the right offset as other
architectures do.  Oddly enough though, specifying the structures as packed
the long way - one by one with the packed attribute does work.  Rather than
fighting over whether this is a gcc bug or some obscure side effect
of pragma pack, it is easier to do what most (all but 96 other places in
the kernel) do - and replace pragma pack with dozens of attribute(packed)
structure qualifiers.  Much more verbose ... but at least it works.

Signed-off-by: David Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>  CG: -----------------------------------------------------------------------
---
 fs/cifs/cifspdu.h    | 343 ++++++++++++++++++++++++++-------------------------
 fs/cifs/ntlmssp.h    |  12 +-
 fs/cifs/rfc1002pdu.h |  13 +-
 3 files changed, 182 insertions(+), 186 deletions(-)

diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 193f06eb43f9..48a05b9df7eb 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -80,7 +80,7 @@
 #define NT_TRANSACT_GET_USER_QUOTA    0x07
 #define NT_TRANSACT_SET_USER_QUOTA    0x08
 
-#define MAX_CIFS_HDR_SIZE 256	/* chained NTCreateXReadX will probably be biggest */
+#define MAX_CIFS_HDR_SIZE 256	/* is future chained NTCreateXReadX bigger? */
 
 /* internal cifs vfs structures */
 /*****************************************************************
@@ -133,10 +133,11 @@
 /*
  * SMB flag definitions 
  */
-#define SMBFLG_EXTD_LOCK 0x01	/* server supports lock-read write-unlock primitives */
+#define SMBFLG_EXTD_LOCK 0x01	/* server supports lock-read write-unlock smb */
 #define SMBFLG_RCV_POSTED 0x02	/* obsolete */
 #define SMBFLG_RSVD 0x04
-#define SMBFLG_CASELESS 0x08	/* all pathnames treated as caseless (off implies case sensitive file handling requested) */
+#define SMBFLG_CASELESS 0x08	/* all pathnames treated as caseless (off
+				implies case sensitive file handling request) */
 #define SMBFLG_CANONICAL_PATH_FORMAT 0x10	/* obsolete */
 #define SMBFLG_OLD_OPLOCK 0x20	/* obsolete */
 #define SMBFLG_OLD_OPLOCK_NOTIFY 0x40	/* obsolete */
@@ -145,7 +146,8 @@
 /*
  * SMB flag2 definitions 
  */
-#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1)	/* can send long (non-8.3) path names in response */
+#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1)	/* can send long (non-8.3) 
+						   path names in response */
 #define SMBFLG2_KNOWS_EAS cpu_to_le16(2)
 #define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4)
 #define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40)
@@ -164,32 +166,32 @@
  * file and can have any suitable combination of the following values:
  */
 
-#define FILE_READ_DATA        0x00000001	/* Data can be read from the file   */
-#define FILE_WRITE_DATA       0x00000002	/* Data can be written to the file  */
-#define FILE_APPEND_DATA      0x00000004	/* Data can be appended to the file */
-#define FILE_READ_EA          0x00000008	/* Extended attributes associated   */
-					 /* with the file can be read        */
-#define FILE_WRITE_EA         0x00000010	/* Extended attributes associated   */
-					 /* with the file can be written     */
-#define FILE_EXECUTE          0x00000020	/*Data can be read into memory from */
-					 /* the file using system paging I/O */
+#define FILE_READ_DATA        0x00000001  /* Data can be read from the file   */
+#define FILE_WRITE_DATA       0x00000002  /* Data can be written to the file  */
+#define FILE_APPEND_DATA      0x00000004  /* Data can be appended to the file */
+#define FILE_READ_EA          0x00000008  /* Extended attributes associated   */
+					  /* with the file can be read        */
+#define FILE_WRITE_EA         0x00000010  /* Extended attributes associated   */
+					  /* with the file can be written     */
+#define FILE_EXECUTE          0x00000020  /*Data can be read into memory from */
+					  /* the file using system paging I/O */
 #define FILE_DELETE_CHILD     0x00000040
-#define FILE_READ_ATTRIBUTES  0x00000080	/* Attributes associated with the   */
-					 /* file can be read                 */
-#define FILE_WRITE_ATTRIBUTES 0x00000100	/* Attributes associated with the   */
-					 /* file can be written              */
-#define DELETE                0x00010000	/* The file can be deleted          */
-#define READ_CONTROL          0x00020000	/* The access control list and      */
-					 /* ownership associated with the    */
-					 /* file can be read                 */
-#define WRITE_DAC             0x00040000	/* The access control list and      */
-					 /* ownership associated with the    */
-					 /* file can be written.             */
-#define WRITE_OWNER           0x00080000	/* Ownership information associated */
-					 /* with the file can be written     */
-#define SYNCHRONIZE           0x00100000	/* The file handle can waited on to */
-					 /* synchronize with the completion  */
-					 /* of an input/output request       */
+#define FILE_READ_ATTRIBUTES  0x00000080  /* Attributes associated with the   */
+					  /* file can be read                 */
+#define FILE_WRITE_ATTRIBUTES 0x00000100  /* Attributes associated with the   */
+					  /* file can be written              */
+#define DELETE                0x00010000  /* The file can be deleted          */
+#define READ_CONTROL          0x00020000  /* The access control list and      */
+					  /* ownership associated with the    */
+					  /* file can be read                 */
+#define WRITE_DAC             0x00040000  /* The access control list and      */
+					  /* ownership associated with the    */
+					  /* file can be written.             */
+#define WRITE_OWNER           0x00080000  /* Ownership information associated */
+					  /* with the file can be written     */
+#define SYNCHRONIZE           0x00100000  /* The file handle can waited on to */
+					  /* synchronize with the completion  */
+					  /* of an input/output request       */
 #define GENERIC_ALL           0x10000000
 #define GENERIC_EXECUTE       0x20000000
 #define GENERIC_WRITE         0x40000000
@@ -197,7 +199,7 @@
 					 /* In summary - Relevant file       */
 					 /* access flags from CIFS are       */
 					 /* file_read_data, file_write_data  */
-					 /* file_execute, file_read_attributes */
+					 /* file_execute, file_read_attributes*/
 					 /* write_dac, and delete.           */
 
 /*
@@ -242,7 +244,8 @@
 #define ATTR_SPARSE    0x0200
 #define ATTR_REPARSE   0x0400
 #define ATTR_COMPRESSED 0x0800
-#define ATTR_OFFLINE    0x1000	/* ie file not immediately available - offline storage */
+#define ATTR_OFFLINE    0x1000	/* ie file not immediately available - 
+					on offline storage */
 #define ATTR_NOT_CONTENT_INDEXED 0x2000
 #define ATTR_ENCRYPTED  0x4000
 #define ATTR_POSIX_SEMANTICS 0x01000000
@@ -309,10 +312,10 @@
 #define GETU16(var)  (*((__u16 *)var))	/* BB check for endian issues */
 #define GETU32(var)  (*((__u32 *)var))	/* BB check for endian issues */
 
-#pragma pack(1)
-
 struct smb_hdr {
-	__u32 smb_buf_length;	/* big endian on wire *//* BB length is only two or three bytes - with one or two byte type preceding it but that is always zero - we could mask the type byte off just in case BB */
+	__u32 smb_buf_length;	/* big endian on wire *//* BB length is only two
+		or three bytes - with one or two byte type preceding it that are
+		zero - we could mask the type byte off just in case BB */
 	__u8 Protocol[4];
 	__u8 Command;
 	union {
@@ -320,9 +323,9 @@ struct smb_hdr {
 			__u8 ErrorClass;
 			__u8 Reserved;
 			__le16 Error;
-		} DosError;
+		} __attribute__((packed)) DosError;
 		__le32 CifsError;
-	} Status;
+	} __attribute__((packed)) Status;
 	__u8 Flags;
 	__le16 Flags2;		/* note: le */
 	__le16 PidHigh;
@@ -330,16 +333,16 @@ struct smb_hdr {
 		struct {
 			__le32 SequenceNumber;  /* le */
 			__u32 Reserved; /* zero */
-		} Sequence;
+		} __attribute__((packed)) Sequence;
 		__u8 SecuritySignature[8];	/* le */
-	} Signature;
+	} __attribute__((packed)) Signature;
 	__u8 pad[2];
 	__u16 Tid;
 	__le16 Pid;
 	__u16 Uid;
 	__u16 Mid;
 	__u8 WordCount;
-};
+} __attribute__((packed));
 /* given a pointer to an smb_hdr retrieve the value of byte count */
 #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
 #define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
@@ -391,7 +394,7 @@ typedef struct negotiate_req {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__le16 ByteCount;
 	unsigned char DialectsArray[1];
-} NEGOTIATE_REQ;
+} __attribute__((packed)) NEGOTIATE_REQ;
 
 typedef struct negotiate_rsp {
 	struct smb_hdr hdr;	/* wct = 17 */
@@ -409,16 +412,16 @@ typedef struct negotiate_rsp {
 	__u8 EncryptionKeyLength;
 	__u16 ByteCount;
 	union {
-		unsigned char EncryptionKey[1];	/* if cap extended security is off */
+		unsigned char EncryptionKey[1];	/* cap extended security off */
 		/* followed by Domain name - if extended security is off */
 		/* followed by 16 bytes of server GUID */
-		/* followed by security blob if cap_extended_security negotiated */
+		/* then security blob if cap_extended_security negotiated */
 		struct {
 			unsigned char GUID[16];
 			unsigned char SecurityBlob[1];
-		} extended_response;
-	} u;
-} NEGOTIATE_RSP;
+		} __attribute__((packed)) extended_response;
+	} __attribute__((packed)) u;
+} __attribute__((packed)) NEGOTIATE_RSP;
 
 /* SecurityMode bits */
 #define SECMODE_USER          0x01	/* off indicates share level security */
@@ -464,7 +467,8 @@ typedef union smb_com_session_setup_andx {
 		unsigned char SecurityBlob[1];	/* followed by */
 		/* STRING NativeOS */
 		/* STRING NativeLanMan */
-	} req;			/* NTLM request format (with extended security */
+	} __attribute__((packed)) req;	/* NTLM request format (with 
+					extended security */
 
 	struct {		/* request format */
 		struct smb_hdr hdr;	/* wct = 13 */
@@ -475,18 +479,19 @@ typedef union smb_com_session_setup_andx {
 		__le16 MaxMpxCount;
 		__le16 VcNumber;
 		__u32 SessionKey;
-		__le16 CaseInsensitivePasswordLength;	/* ASCII password length */
-		__le16 CaseSensitivePasswordLength;	/* Unicode password length */
+		__le16 CaseInsensitivePasswordLength; /* ASCII password len */
+		__le16 CaseSensitivePasswordLength; /* Unicode password length*/
 		__u32 Reserved;	/* see below */
 		__le32 Capabilities;
 		__le16 ByteCount;
-		unsigned char CaseInsensitivePassword[1];	/* followed by: */
+		unsigned char CaseInsensitivePassword[1];     /* followed by: */
 		/* unsigned char * CaseSensitivePassword; */
 		/* STRING AccountName */
 		/* STRING PrimaryDomain */
 		/* STRING NativeOS */
 		/* STRING NativeLanMan */
-	} req_no_secext;	/* NTLM request format (without extended security */
+	} __attribute__((packed)) req_no_secext; /* NTLM request format (without
+							extended security */
 
 	struct {		/* default (NTLM) response format */
 		struct smb_hdr hdr;	/* wct = 4 */
@@ -500,7 +505,7 @@ typedef union smb_com_session_setup_andx {
 /*      unsigned char  * NativeOS;      */
 /*	unsigned char  * NativeLanMan;  */
 /*      unsigned char  * PrimaryDomain; */
-	} resp;			/* NTLM response format (with or without extended security */
+	} __attribute__((packed)) resp;			/* NTLM response format (with or without extended security */
 
 	struct {		/* request format */
 		struct smb_hdr hdr;	/* wct = 10 */
@@ -519,7 +524,7 @@ typedef union smb_com_session_setup_andx {
 		/* STRING PrimaryDomain */
 		/* STRING NativeOS */
 		/* STRING NativeLanMan */
-	} old_req;		/* pre-NTLM (LANMAN2.1) request format */
+	} __attribute__((packed)) old_req;		/* pre-NTLM (LANMAN2.1) request format */
 
 	struct {		/* default (NTLM) response format */
 		struct smb_hdr hdr;	/* wct = 3 */
@@ -531,8 +536,8 @@ typedef union smb_com_session_setup_andx {
 		unsigned char NativeOS[1];	/* followed by */
 /*	unsigned char * NativeLanMan; */
 /*      unsigned char * PrimaryDomain; */
-	} old_resp;		/* pre-NTLM (LANMAN2.1) response format */
-} SESSION_SETUP_ANDX;
+	} __attribute__((packed)) old_resp;		/* pre-NTLM (LANMAN2.1) response format */
+} __attribute__((packed)) SESSION_SETUP_ANDX;
 
 #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
 
@@ -542,7 +547,8 @@ typedef union smb_com_session_setup_andx {
 #define CAP_NT_SMBS            0x00000010
 #define CAP_STATUS32           0x00000040
 #define CAP_LEVEL_II_OPLOCKS   0x00000080
-#define CAP_NT_FIND            0x00000200	/* reserved should be zero (presumably because NT_SMBs implies the same thing) */
+#define CAP_NT_FIND            0x00000200	/* reserved should be zero 
+				(because NT_SMBs implies the same thing?) */
 #define CAP_BULK_TRANSFER      0x20000000
 #define CAP_EXTENDED_SECURITY  0x80000000
 
@@ -560,7 +566,7 @@ typedef struct smb_com_tconx_req {
 	unsigned char Password[1];	/* followed by */
 /* STRING Path    *//* \\server\share name */
 	/* STRING Service */
-} TCONX_REQ;
+} __attribute__((packed)) TCONX_REQ;
 
 typedef struct smb_com_tconx_rsp {
 	struct smb_hdr hdr;	/* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */
@@ -571,13 +577,14 @@ typedef struct smb_com_tconx_rsp {
 	__u16 ByteCount;
 	unsigned char Service[1];	/* always ASCII, not Unicode */
 	/* STRING NativeFileSystem */
-} TCONX_RSP;
+} __attribute__((packed)) TCONX_RSP;
 
 /* tree connect Flags */
 #define DISCONNECT_TID          0x0001
 #define TCON_EXTENDED_SECINFO   0x0008
 /* OptionalSupport bits */
-#define SMB_SUPPORT_SEARCH_BITS 0x0001	/* must have bits (exclusive searches suppt. */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001	/* "must have" directory search bits
+					 (exclusive searches supported) */
 #define SMB_SHARE_IS_IN_DFS     0x0002
 
 typedef struct smb_com_logoff_andx_req {
@@ -586,7 +593,7 @@ typedef struct smb_com_logoff_andx_req {
 	__u8 AndXReserved;
 	__u16 AndXOffset;
 	__u16 ByteCount;
-} LOGOFF_ANDX_REQ;
+} __attribute__((packed)) LOGOFF_ANDX_REQ;
 
 typedef struct smb_com_logoff_andx_rsp {
 	struct smb_hdr hdr;	/* wct = 2 */
@@ -594,36 +601,36 @@ typedef struct smb_com_logoff_andx_rsp {
 	__u8 AndXReserved;
 	__u16 AndXOffset;
 	__u16 ByteCount;
-} LOGOFF_ANDX_RSP;
+} __attribute__((packed)) LOGOFF_ANDX_RSP;
 
 typedef union smb_com_tree_disconnect {	/* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */
 	struct {
 		struct smb_hdr hdr;	/* wct = 0 */
 		__u16 ByteCount;	/* bcc = 0 */
-	} req;
+	} __attribute__((packed)) req;
 	struct {
 		struct smb_hdr hdr;	/* wct = 0 */
 		__u16 ByteCount;	/* bcc = 0 */
-	} resp;
-} TREE_DISCONNECT;
+	} __attribute__((packed)) resp;
+} __attribute__((packed)) TREE_DISCONNECT;
 
 typedef struct smb_com_close_req {
 	struct smb_hdr hdr;	/* wct = 3 */
 	__u16 FileID;
 	__u32 LastWriteTime;	/* should be zero */
 	__u16 ByteCount;	/* 0 */
-} CLOSE_REQ;
+} __attribute__((packed)) CLOSE_REQ;
 
 typedef struct smb_com_close_rsp {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__u16 ByteCount;	/* bct = 0 */
-} CLOSE_RSP;
+} __attribute__((packed)) CLOSE_RSP;
 
 typedef struct smb_com_findclose_req {
 	struct smb_hdr hdr; /* wct = 1 */
 	__u16 FileID;
 	__u16 ByteCount;    /* 0 */
-} FINDCLOSE_REQ;
+} __attribute__((packed)) FINDCLOSE_REQ;
 
 /* OpenFlags */
 #define REQ_MORE_INFO      0x00000001  /* legacy (OPEN_AND_X) only */
@@ -650,7 +657,7 @@ typedef struct smb_com_open_req {	/* also handles create */
 	__u8 SecurityFlags;
 	__le16 ByteCount;
 	char fileName[1];
-} OPEN_REQ;
+} __attribute__((packed)) OPEN_REQ;
 
 /* open response: oplock levels */
 #define OPLOCK_NONE  	 0
@@ -680,7 +687,7 @@ typedef struct smb_com_open_rsp {
 	__le16 DeviceState;
 	__u8 DirectoryFlag;
 	__u16 ByteCount;	/* bct = 0 */
-} OPEN_RSP;
+} __attribute__((packed)) OPEN_RSP;
 
 /* format of legacy open request */
 typedef struct smb_com_openx_req {
@@ -699,7 +706,7 @@ typedef struct smb_com_openx_req {
 	__le32 Reserved;
 	__le16  ByteCount;  /* file name follows */
 	char   fileName[1];
-} OPENX_REQ;
+} __attribute__((packed)) OPENX_REQ;
 
 typedef struct smb_com_openx_rsp {
 	struct smb_hdr	hdr;	/* wct = 15 */
@@ -717,7 +724,7 @@ typedef struct smb_com_openx_rsp {
 	__u32  FileId;
 	__u16  Reserved;
 	__u16  ByteCount;
-} OPENX_RSP; 
+} __attribute__((packed)) OPENX_RSP; 
 
 /* Legacy write request for older servers */
 typedef struct smb_com_writex_req {
@@ -736,7 +743,7 @@ typedef struct smb_com_writex_req {
         __le16 ByteCount;
         __u8 Pad;               /* BB check for whether padded to DWORD boundary and optimum performance here */
         char Data[0];
-} WRITEX_REQ;
+} __attribute__((packed)) WRITEX_REQ;
 
 typedef struct smb_com_write_req {
 	struct smb_hdr hdr;	/* wct = 14 */
@@ -755,7 +762,7 @@ typedef struct smb_com_write_req {
 	__le16 ByteCount;
 	__u8 Pad;		/* BB check for whether padded to DWORD boundary and optimum performance here */
 	char Data[0];
-} WRITE_REQ;
+} __attribute__((packed)) WRITE_REQ;
 
 typedef struct smb_com_write_rsp {
 	struct smb_hdr hdr;	/* wct = 6 */
@@ -767,7 +774,7 @@ typedef struct smb_com_write_rsp {
 	__le16 CountHigh;
 	__u16  Reserved;
 	__u16 ByteCount;
-} WRITE_RSP;
+} __attribute__((packed)) WRITE_RSP;
 
 /* legacy read request for older servers */
 typedef struct smb_com_readx_req {
@@ -782,7 +789,7 @@ typedef struct smb_com_readx_req {
         __le32 Reserved;
         __le16 Remaining;
         __le16 ByteCount;
-} READX_REQ;
+} __attribute__((packed)) READX_REQ;
 
 typedef struct smb_com_read_req {
 	struct smb_hdr hdr;	/* wct = 12 */
@@ -797,7 +804,7 @@ typedef struct smb_com_read_req {
 	__le16 Remaining;
 	__le32 OffsetHigh;
 	__le16 ByteCount;
-} READ_REQ;
+} __attribute__((packed)) READ_REQ;
 
 typedef struct smb_com_read_rsp {
 	struct smb_hdr hdr;	/* wct = 12 */
@@ -814,7 +821,7 @@ typedef struct smb_com_read_rsp {
 	__u16 ByteCount;
 	__u8 Pad;		/* BB check for whether padded to DWORD boundary and optimum performance here */
 	char Data[1];
-} READ_RSP;
+} __attribute__((packed)) READ_RSP;
 
 typedef struct locking_andx_range {
 	__le16 Pid;
@@ -823,7 +830,7 @@ typedef struct locking_andx_range {
 	__le32 OffsetLow;
 	__le32 LengthHigh;
 	__le32 LengthLow;
-} LOCKING_ANDX_RANGE;
+} __attribute__((packed)) LOCKING_ANDX_RANGE;
 
 #define LOCKING_ANDX_SHARED_LOCK     0x01
 #define LOCKING_ANDX_OPLOCK_RELEASE  0x02
@@ -844,7 +851,7 @@ typedef struct smb_com_lock_req {
 	__le16 NumberOfLocks;
 	__le16 ByteCount;
 	LOCKING_ANDX_RANGE Locks[1];
-} LOCK_REQ;
+} __attribute__((packed)) LOCK_REQ;
 
 
 typedef struct cifs_posix_lock {
@@ -854,7 +861,7 @@ typedef struct cifs_posix_lock {
 	__le64	start;
 	__le64	length;
 	/* BB what about additional owner info to identify network client */
-} CIFS_POSIX_LOCK;
+} __attribute__((packed)) CIFS_POSIX_LOCK;
 
 typedef struct smb_com_lock_rsp {
 	struct smb_hdr hdr;	/* wct = 2 */
@@ -862,7 +869,7 @@ typedef struct smb_com_lock_rsp {
 	__u8 AndXReserved;
 	__le16 AndXOffset;
 	__u16 ByteCount;
-} LOCK_RSP;
+} __attribute__((packed)) LOCK_RSP;
 
 typedef struct smb_com_rename_req {
 	struct smb_hdr hdr;	/* wct = 1 */
@@ -872,7 +879,7 @@ typedef struct smb_com_rename_req {
 	unsigned char OldFileName[1];
 	/* followed by __u8 BufferFormat2 */
 	/* followed by NewFileName */
-} RENAME_REQ;
+} __attribute__((packed)) RENAME_REQ;
 
 	/* copy request flags */
 #define COPY_MUST_BE_FILE      0x0001
@@ -892,7 +899,7 @@ typedef struct smb_com_copy_req {
 	unsigned char OldFileName[1];
 	/* followed by __u8 BufferFormat2 */
 	/* followed by NewFileName string */
-} COPY_REQ;
+} __attribute__((packed)) COPY_REQ;
 
 typedef struct smb_com_copy_rsp {
 	struct smb_hdr hdr;     /* wct = 1 */
@@ -900,7 +907,7 @@ typedef struct smb_com_copy_rsp {
 	__u16 ByteCount;    /* may be zero */
 	__u8 BufferFormat;  /* 0x04 - only present if errored file follows */
 	unsigned char ErrorFileName[1]; /* only present if error in copy */
-} COPY_RSP;
+} __attribute__((packed)) COPY_RSP;
 
 #define CREATE_HARD_LINK		0x103
 #define MOVEFILE_COPY_ALLOWED		0x0002
@@ -916,12 +923,12 @@ typedef struct smb_com_nt_rename_req {	/* A5 - also used for create hardlink */
 	unsigned char OldFileName[1];
 	/* followed by __u8 BufferFormat2 */
 	/* followed by NewFileName */
-} NT_RENAME_REQ;
+} __attribute__((packed)) NT_RENAME_REQ;
 
 typedef struct smb_com_rename_rsp {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__u16 ByteCount;	/* bct = 0 */
-} RENAME_RSP;
+} __attribute__((packed)) RENAME_RSP;
 
 typedef struct smb_com_delete_file_req {
 	struct smb_hdr hdr;	/* wct = 1 */
@@ -929,43 +936,43 @@ typedef struct smb_com_delete_file_req {
 	__le16 ByteCount;
 	__u8 BufferFormat;	/* 4 = ASCII */
 	unsigned char fileName[1];
-} DELETE_FILE_REQ;
+} __attribute__((packed)) DELETE_FILE_REQ;
 
 typedef struct smb_com_delete_file_rsp {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__u16 ByteCount;	/* bct = 0 */
-} DELETE_FILE_RSP;
+} __attribute__((packed)) DELETE_FILE_RSP;
 
 typedef struct smb_com_delete_directory_req {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__le16 ByteCount;
 	__u8 BufferFormat;	/* 4 = ASCII */
 	unsigned char DirName[1];
-} DELETE_DIRECTORY_REQ;
+} __attribute__((packed)) DELETE_DIRECTORY_REQ;
 
 typedef struct smb_com_delete_directory_rsp {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__u16 ByteCount;	/* bct = 0 */
-} DELETE_DIRECTORY_RSP;
+} __attribute__((packed)) DELETE_DIRECTORY_RSP;
 
 typedef struct smb_com_create_directory_req {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__le16 ByteCount;
 	__u8 BufferFormat;	/* 4 = ASCII */
 	unsigned char DirName[1];
-} CREATE_DIRECTORY_REQ;
+} __attribute__((packed)) CREATE_DIRECTORY_REQ;
 
 typedef struct smb_com_create_directory_rsp {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__u16 ByteCount;	/* bct = 0 */
-} CREATE_DIRECTORY_RSP;
+} __attribute__((packed)) CREATE_DIRECTORY_RSP;
 
 typedef struct smb_com_query_information_req {
 	struct smb_hdr hdr;     /* wct = 0 */
 	__le16 ByteCount;	/* 1 + namelen + 1 */
 	__u8 BufferFormat;      /* 4 = ASCII */
 	unsigned char FileName[1];
-} QUERY_INFORMATION_REQ;
+} __attribute__((packed)) QUERY_INFORMATION_REQ;
 
 typedef struct smb_com_query_information_rsp {
 	struct smb_hdr hdr;     /* wct = 10 */
@@ -974,7 +981,7 @@ typedef struct smb_com_query_information_rsp {
 	__le32 size;
 	__u16  reserved[5];
 	__le16 ByteCount;	/* bcc = 0 */
-} QUERY_INFORMATION_RSP;
+} __attribute__((packed)) QUERY_INFORMATION_RSP;
 
 typedef struct smb_com_setattr_req {
 	struct smb_hdr hdr; /* wct = 8 */
@@ -985,12 +992,12 @@ typedef struct smb_com_setattr_req {
 	__u16  ByteCount;
 	__u8   BufferFormat; /* 4 = ASCII */
 	unsigned char fileName[1];
-} SETATTR_REQ;
+} __attribute__((packed)) SETATTR_REQ;
 
 typedef struct smb_com_setattr_rsp {
 	struct smb_hdr hdr;     /* wct = 0 */
 	__u16 ByteCount;        /* bct = 0 */
-} SETATTR_RSP;
+} __attribute__((packed)) SETATTR_RSP;
 
 /* empty wct response to setattr */
 
@@ -1020,7 +1027,7 @@ typedef struct smb_com_transaction_ioctl_req {
 	__le16 ByteCount;
 	__u8 Pad[3];
 	__u8 Data[1];
-} TRANSACT_IOCTL_REQ;
+} __attribute__((packed)) TRANSACT_IOCTL_REQ;
 
 typedef struct smb_com_transaction_ioctl_rsp {
 	struct smb_hdr hdr;	/* wct = 19 */
@@ -1037,7 +1044,7 @@ typedef struct smb_com_transaction_ioctl_rsp {
 	__le16 ReturnedDataLen;
 	__u16 ByteCount;
 	__u8 Pad[3];
-} TRANSACT_IOCTL_RSP;
+} __attribute__((packed)) TRANSACT_IOCTL_RSP;
 
 typedef struct smb_com_transaction_change_notify_req {
 	struct smb_hdr hdr;     /* wct = 23 */
@@ -1061,7 +1068,7 @@ typedef struct smb_com_transaction_change_notify_req {
 	__le16 ByteCount;
 /* __u8 Pad[3];*/
 /*	__u8 Data[1];*/
-} TRANSACT_CHANGE_NOTIFY_REQ;
+} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ;
 
 typedef struct smb_com_transaction_change_notify_rsp {
 	struct smb_hdr hdr;	/* wct = 18 */
@@ -1077,7 +1084,7 @@ typedef struct smb_com_transaction_change_notify_rsp {
 	__u8 SetupCount;   /* 0 */
 	__u16 ByteCount;
 	/* __u8 Pad[3]; */
-} TRANSACT_CHANGE_NOTIFY_RSP;
+} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_RSP;
 /* Completion Filter flags for Notify */
 #define FILE_NOTIFY_CHANGE_FILE_NAME    0x00000001
 #define FILE_NOTIFY_CHANGE_DIR_NAME     0x00000002
@@ -1108,7 +1115,7 @@ struct file_notify_information {
 	__le32 Action;
 	__le32 FileNameLength;
 	__u8  FileName[0];
-}; 
+} __attribute__((packed)); 
 
 struct reparse_data {
 	__u32	ReparseTag;
@@ -1119,7 +1126,7 @@ struct reparse_data {
 	__u16	TargetNameOffset;
 	__u16	TargetNameLen;
 	char	LinkNamesBuf[1];
-};
+} __attribute__((packed));
 
 struct cifs_quota_data {
 	__u32	rsrvd1;  /* 0 */
@@ -1129,7 +1136,7 @@ struct cifs_quota_data {
 	__u64	soft_limit;
 	__u64	hard_limit;
 	char	sid[1];  /* variable size? */
-};
+} __attribute__((packed));
 
 /* quota sub commands */
 #define QUOTA_LIST_CONTINUE	    0
@@ -1155,12 +1162,12 @@ struct trans2_req {
 	__u8 Reserved3;
 	__le16 SubCommand; /* 1st setup word - SetupCount words follow */
 	__le16 ByteCount;
-};
+} __attribute__((packed));
 
 struct smb_t2_req {
 	struct smb_hdr hdr;
 	struct trans2_req t2_req;
-};
+} __attribute__((packed));
 
 struct trans2_resp {
 	/* struct smb_hdr hdr precedes. Note wct = 10 + setup count */
@@ -1179,12 +1186,12 @@ struct trans2_resp {
 	__u16 ByteCount;
 	__u16 Reserved2;*/	
 	/* data area follows */
-};
+} __attribute__((packed));
 
 struct smb_t2_rsp {
 	struct smb_hdr hdr;
 	struct trans2_resp t2_rsp;
-};
+} __attribute__((packed));
 
 /* PathInfo/FileInfo infolevels */
 #define SMB_INFO_STANDARD                   1
@@ -1271,14 +1278,14 @@ typedef struct smb_com_transaction2_qpi_req {
 	__le16 InformationLevel;
 	__u32 Reserved4;
 	char FileName[1];
-} TRANSACTION2_QPI_REQ;
+} __attribute__((packed)) TRANSACTION2_QPI_REQ;
 
 typedef struct smb_com_transaction2_qpi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
 	struct trans2_resp t2;
 	__u16 ByteCount;
 	__u16 Reserved2;	/* parameter word reserved - present for infolevels > 100 */
-} TRANSACTION2_QPI_RSP;
+} __attribute__((packed)) TRANSACTION2_QPI_RSP;
 
 typedef struct smb_com_transaction2_spi_req {
 	struct smb_hdr hdr;	/* wct = 15 */
@@ -1304,21 +1311,21 @@ typedef struct smb_com_transaction2_spi_req {
 	__le16 InformationLevel;
 	__u32 Reserved4;
 	char FileName[1];
-} TRANSACTION2_SPI_REQ;
+} __attribute__((packed)) TRANSACTION2_SPI_REQ;
 
 typedef struct smb_com_transaction2_spi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
 	struct trans2_resp t2;
 	__u16 ByteCount;
 	__u16 Reserved2;	/* parameter word reserved - present for infolevels > 100 */
-} TRANSACTION2_SPI_RSP;
+} __attribute__((packed)) TRANSACTION2_SPI_RSP;
 
 struct set_file_rename {
 	__le32 overwrite;   /* 1 = overwrite dest */
 	__u32 root_fid;   /* zero */
 	__le32 target_name_len;
 	char  target_name[0];  /* Must be unicode */
-};
+} __attribute__((packed));
 
 struct smb_com_transaction2_sfi_req {
 	struct smb_hdr hdr;	/* wct = 15 */
@@ -1344,7 +1351,7 @@ struct smb_com_transaction2_sfi_req {
 	__u16 Fid;
 	__le16 InformationLevel;
 	__u16 Reserved4;	
-};
+} __attribute__((packed));
 
 struct smb_com_transaction2_sfi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
@@ -1352,7 +1359,7 @@ struct smb_com_transaction2_sfi_rsp {
 	__u16 ByteCount;
 	__u16 Reserved2;	/* parameter word reserved - 
 					present for infolevels > 100 */
-};
+} __attribute__((packed));
 
 struct smb_t2_qfi_req {
         struct	smb_hdr hdr;
@@ -1360,7 +1367,7 @@ struct smb_t2_qfi_req {
 	__u8	Pad;
 	__u16	Fid;
 	__le16	InformationLevel;
-};
+} __attribute__((packed));
 
 struct smb_t2_qfi_rsp {
         struct smb_hdr hdr;     /* wct = 10 + SetupCount */
@@ -1368,7 +1375,7 @@ struct smb_t2_qfi_rsp {
         __u16 ByteCount;
         __u16 Reserved2;        /* parameter word reserved - 
 					present for infolevels > 100 */
-};
+} __attribute__((packed));
 
 /*
  * Flags on T2 FINDFIRST and FINDNEXT 
@@ -1410,13 +1417,13 @@ typedef struct smb_com_transaction2_ffirst_req {
 	__le16 InformationLevel;
 	__le32 SearchStorageType;
 	char FileName[1];
-} TRANSACTION2_FFIRST_REQ;
+} __attribute__((packed)) TRANSACTION2_FFIRST_REQ;
 
 typedef struct smb_com_transaction2_ffirst_rsp {
 	struct smb_hdr hdr;	/* wct = 10 */
 	struct trans2_resp t2;
 	__u16 ByteCount;
-} TRANSACTION2_FFIRST_RSP;
+} __attribute__((packed)) TRANSACTION2_FFIRST_RSP;
 
 typedef struct smb_com_transaction2_ffirst_rsp_parms {
 	__u16 SearchHandle;
@@ -1424,7 +1431,7 @@ typedef struct smb_com_transaction2_ffirst_rsp_parms {
 	__le16 EndofSearch;
 	__le16 EAErrorOffset;
 	__le16 LastNameOffset;
-} T2_FFIRST_RSP_PARMS;
+} __attribute__((packed)) T2_FFIRST_RSP_PARMS;
 
 typedef struct smb_com_transaction2_fnext_req {
 	struct smb_hdr hdr;	/* wct = 15 */
@@ -1452,20 +1459,20 @@ typedef struct smb_com_transaction2_fnext_req {
 	__u32 ResumeKey;
 	__le16 SearchFlags;
 	char ResumeFileName[1];
-} TRANSACTION2_FNEXT_REQ;
+} __attribute__((packed)) TRANSACTION2_FNEXT_REQ;
 
 typedef struct smb_com_transaction2_fnext_rsp {
 	struct smb_hdr hdr;	/* wct = 10 */
 	struct trans2_resp t2;
 	__u16 ByteCount;
-} TRANSACTION2_FNEXT_RSP;
+} __attribute__((packed)) TRANSACTION2_FNEXT_RSP;
 
 typedef struct smb_com_transaction2_fnext_rsp_parms {
 	__le16 SearchCount;
 	__le16 EndofSearch;
 	__le16 EAErrorOffset;
 	__le16 LastNameOffset;
-} T2_FNEXT_RSP_PARMS;
+} __attribute__((packed)) T2_FNEXT_RSP_PARMS;
 
 /* QFSInfo Levels */
 #define SMB_INFO_ALLOCATION         1
@@ -1502,14 +1509,14 @@ typedef struct smb_com_transaction2_qfsi_req {
 	__le16 ByteCount;
 	__u8 Pad;
 	__le16 InformationLevel;
-} TRANSACTION2_QFSI_REQ;
+} __attribute__((packed)) TRANSACTION2_QFSI_REQ;
 
 typedef struct smb_com_transaction_qfsi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
 	struct trans2_resp t2;
 	__u16 ByteCount;
 	__u8 Pad;		/* may be three bytes *//* followed by data area */
-} TRANSACTION2_QFSI_RSP;
+} __attribute__((packed)) TRANSACTION2_QFSI_RSP;
 
 
 /* SETFSInfo Levels */
@@ -1539,13 +1546,13 @@ typedef struct smb_com_transaction2_setfsi_req {
 	__le16 ClientUnixMajor; /* Data start. */
 	__le16 ClientUnixMinor;
 	__le64 ClientUnixCap;   /* Data end */
-} TRANSACTION2_SETFSI_REQ;
+} __attribute__((packed)) TRANSACTION2_SETFSI_REQ;
 
 typedef struct smb_com_transaction2_setfsi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 */
 	struct trans2_resp t2;
 	__u16 ByteCount;
-} TRANSACTION2_SETFSI_RSP;
+} __attribute__((packed)) TRANSACTION2_SETFSI_RSP;
 
 
 typedef struct smb_com_transaction2_get_dfs_refer_req {
@@ -1570,7 +1577,7 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
 	__u8 Pad[3];		/* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */
 	__le16 MaxReferralLevel;
 	char RequestFileName[1];
-} TRANSACTION2_GET_DFS_REFER_REQ;
+} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ;
 
 typedef struct dfs_referral_level_3 {
 	__le16 VersionNumber;
@@ -1582,7 +1589,7 @@ typedef struct dfs_referral_level_3 {
 	__le16 DfsPathOffset;
 	__le16 DfsAlternatePathOffset;
 	__le16 NetworkAddressOffset;
-} REFERRAL3;
+} __attribute__((packed)) REFERRAL3;
 
 typedef struct smb_com_transaction_get_dfs_refer_rsp {
 	struct smb_hdr hdr;	/* wct = 10 */
@@ -1595,7 +1602,7 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp {
 	__u16 Pad2;
 	REFERRAL3 referrals[1];	/* array of level 3 dfs_referral structures */
 	/* followed by the strings pointed to by the referral structures */
-} TRANSACTION2_GET_DFS_REFER_RSP;
+} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP;
 
 /* DFS Flags */
 #define DFSREF_REFERRAL_SERVER  0x0001
@@ -1649,7 +1656,7 @@ struct serverInfo {
 	unsigned char versionMinor;
 	unsigned long type;
 	unsigned int commentOffset;
-};
+} __attribute__((packed));
 
 /*
  * The following structure is the format of the data returned on a NetShareEnum
@@ -1661,27 +1668,27 @@ struct shareInfo {
 	char pad;
 	unsigned short type;
 	unsigned int commentOffset;
-};
+} __attribute__((packed));
 
 struct aliasInfo {
 	char aliasName[9];
 	char pad;
 	unsigned int commentOffset;
 	unsigned char type[2];
-};
+} __attribute__((packed));
 
 struct aliasInfo92 {
 	int aliasNameOffset;
 	int serverNameOffset;
 	int shareNameOffset;
-};
+} __attribute__((packed));
 
 typedef struct {
 	__le64 TotalAllocationUnits;
 	__le64 FreeAllocationUnits;
 	__le32 SectorsPerAllocationUnit;
 	__le32 BytesPerSector;
-} FILE_SYSTEM_INFO;		/* size info, level 0x103 */
+} __attribute__((packed)) FILE_SYSTEM_INFO;		/* size info, level 0x103 */
 
 typedef struct {
 	__le32 fsid;
@@ -1689,13 +1696,13 @@ typedef struct {
 	__le32 TotalAllocationUnits;
 	__le32 FreeAllocationUnits;
 	__le16  BytesPerSector;
-} FILE_SYSTEM_ALLOC_INFO;
+} __attribute__((packed)) FILE_SYSTEM_ALLOC_INFO;
 
 typedef struct {
 	__le16 MajorVersionNumber;
 	__le16 MinorVersionNumber;
 	__le64 Capability;
-} FILE_SYSTEM_UNIX_INFO;	/* Unix extensions info, level 0x200 */
+} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO;	/* Unix extensions info, level 0x200 */
 
 /* Version numbers for CIFS UNIX major and minor. */
 #define CIFS_UNIX_MAJOR_VERSION 1
@@ -1730,7 +1737,7 @@ typedef struct {
 	__le64 FileSysIdentifier;   /* fsid */
 	/* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */
 	/* NB flags can come from FILE_SYSTEM_DEVICE_INFO call   */
-} FILE_SYSTEM_POSIX_INFO;
+} __attribute__((packed)) FILE_SYSTEM_POSIX_INFO;
 
 /* DeviceType Flags */
 #define FILE_DEVICE_CD_ROM              0x00000002
@@ -1755,14 +1762,14 @@ typedef struct {
 typedef struct {
 	__le32 DeviceType;
 	__le32 DeviceCharacteristics;
-} FILE_SYSTEM_DEVICE_INFO;	/* device info, level 0x104 */
+} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO;	/* device info, level 0x104 */
 
 typedef struct {
 	__le32 Attributes;
 	__le32 MaxPathNameComponentLength;
 	__le32 FileSystemNameLen;
 	char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */
-} FILE_SYSTEM_ATTRIBUTE_INFO;
+} __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO;
 
 /******************************************************************************/
 /* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */
@@ -1789,7 +1796,7 @@ typedef struct { /* data block encoding of response to level 263 QPathInfo */
 	__le32 AlignmentRequirement;
 	__le32 FileNameLength;
 	char FileName[1];
-} FILE_ALL_INFO;		/* level 0x107 QPathInfo */
+} __attribute__((packed)) FILE_ALL_INFO;		/* level 0x107 QPathInfo */
 
 /* defines for enumerating possible values of the Unix type field below */
 #define UNIX_FILE      0
@@ -1813,11 +1820,11 @@ typedef struct {
 	__u64 UniqueId;
 	__le64 Permissions;
 	__le64 Nlinks;
-} FILE_UNIX_BASIC_INFO;		/* level 0x200 QPathInfo */
+} __attribute__((packed)) FILE_UNIX_BASIC_INFO;		/* level 0x200 QPathInfo */
 
 typedef struct {
 	char LinkDest[1];
-} FILE_UNIX_LINK_INFO;		/* level 0x201 QPathInfo */
+} __attribute__((packed)) FILE_UNIX_LINK_INFO;		/* level 0x201 QPathInfo */
 
 /* The following three structures are needed only for
 	setting time to NT4 and some older servers via
@@ -1826,13 +1833,13 @@ typedef struct {
 	__u16 Day:5;
 	__u16 Month:4;
 	__u16 Year:7;
-} SMB_DATE;
+} __attribute__((packed)) SMB_DATE;
 
 typedef struct {
 	__u16 TwoSeconds:5;
 	__u16 Minutes:6;
 	__u16 Hours:5;
-} SMB_TIME;
+} __attribute__((packed)) SMB_TIME;
 
 typedef struct {
 	__le16 CreationDate; /* SMB Date see above */
@@ -1845,7 +1852,7 @@ typedef struct {
 	__le32 AllocationSize;
 	__le16 Attributes; /* verify not u32 */
 	__le32 EASize;
-} FILE_INFO_STANDARD;  /* level 1 SetPath/FileInfo */
+} __attribute__((packed)) FILE_INFO_STANDARD;  /* level 1 SetPath/FileInfo */
 
 typedef struct {
 	__le64 CreationTime;
@@ -1854,19 +1861,19 @@ typedef struct {
 	__le64 ChangeTime;
 	__le32 Attributes;
 	__u32 Pad;
-} FILE_BASIC_INFO;		/* size info, level 0x101 */
+} __attribute__((packed)) FILE_BASIC_INFO;		/* size info, level 0x101 */
 
 struct file_allocation_info {
 	__le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
-};	/* size used on disk, level 0x103 for set, 0x105 for query */
+} __attribute__((packed));	/* size used on disk, level 0x103 for set, 0x105 for query */
 
 struct file_end_of_file_info {
 	__le64 FileSize;		/* offset to end of file */
-};	/* size info, level 0x104 for set, 0x106 for query */
+} __attribute__((packed));	/* size info, level 0x104 for set, 0x106 for query */
 
 struct file_alt_name_info {
 	__u8   alt_name[1];
-};      /* level 0x0108 */
+} __attribute__((packed));      /* level 0x0108 */
 
 struct file_stream_info {
 	__le32 number_of_streams;  /* BB check sizes and verify location */
@@ -1883,7 +1890,7 @@ struct file_compression_info {
 	__u8   ch_shift;
 	__u8   cl_shift;
 	__u8   pad[3];
-};      /* level 0x10b */
+} __attribute__((packed));      /* level 0x10b */
 
 /* POSIX ACL set/query path info structures */
 #define CIFS_ACL_VERSION 1
@@ -1891,7 +1898,7 @@ struct cifs_posix_ace { /* access control entry (ACE) */
 	__u8  cifs_e_tag;
 	__u8  cifs_e_perm;
 	__le64 cifs_uid; /* or gid */
-}; 
+} __attribute__((packed)); 
 
 struct cifs_posix_acl { /* access conrol list  (ACL) */
 	__le16	version;
@@ -1900,7 +1907,7 @@ struct cifs_posix_acl { /* access conrol list  (ACL) */
 	struct cifs_posix_ace ace_array[0];
 	/* followed by
 	struct cifs_posix_ace default_ace_arraay[] */
-};  /* level 0x204 */
+} __attribute__((packed));  /* level 0x204 */
 
 /* types of access control entries already defined in posix_acl.h */
 /* #define CIFS_POSIX_ACL_USER_OBJ	 0x01
@@ -1919,15 +1926,15 @@ struct cifs_posix_acl { /* access conrol list  (ACL) */
 
 struct file_internal_info {
 	__u64  UniqueId; /* inode number */
-};      /* level 0x3ee */
+} __attribute__((packed));      /* level 0x3ee */
 struct file_mode_info {
 	__le32	Mode;
-};      /* level 0x3f8 */
+} __attribute__((packed));      /* level 0x3f8 */
 
 struct file_attrib_tag {
 	__le32 Attribute;
 	__le32 ReparseTag;
-};      /* level 0x40b */
+} __attribute__((packed));      /* level 0x40b */
 
 
 /********************************************************/
@@ -1951,7 +1958,7 @@ typedef struct {
 	__le64 Permissions;
 	__le64 Nlinks;
 	char FileName[1];
-} FILE_UNIX_INFO; /* level 0x202 */
+} __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */
 
 typedef struct {
 	__le32 NextEntryOffset;
@@ -1965,7 +1972,7 @@ typedef struct {
 	__le32 ExtFileAttributes;
 	__le32 FileNameLength;
 	char FileName[1];
-} FILE_DIRECTORY_INFO;   /* level 0x101 FF response data area */
+} __attribute__((packed)) FILE_DIRECTORY_INFO;   /* level 0x101 FF response data area */
 
 typedef struct {
 	__le32 NextEntryOffset;
@@ -1980,7 +1987,7 @@ typedef struct {
 	__le32 FileNameLength;
 	__le32 EaSize; /* length of the xattrs */
 	char FileName[1];
-} FILE_FULL_DIRECTORY_INFO;   /* level 0x102 FF response data area */
+} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO;   /* level 0x102 FF response data area */
 
 typedef struct {
 	__le32 NextEntryOffset;
@@ -1997,7 +2004,7 @@ typedef struct {
 	__le32 Reserved;
 	__u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
 	char FileName[1];
-} SEARCH_ID_FULL_DIR_INFO;   /* level 0x105 FF response data area */
+} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO;   /* level 0x105 FF response data area */
 
 typedef struct {
 	__le32 NextEntryOffset;
@@ -2015,18 +2022,18 @@ typedef struct {
 	__u8   Reserved;
 	__u8   ShortName[12];
 	char FileName[1];
-} FILE_BOTH_DIRECTORY_INFO;   /* level 0x104 FF response data area */
+} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO;   /* level 0x104 FF response data area */
 
 
 struct gea {
 	unsigned char name_len;
 	char name[1];
-};
+} __attribute__((packed));
 
 struct gealist {
 	unsigned long list_len;
 	struct gea list[1];
-};
+} __attribute__((packed));
 
 struct fea {
 	unsigned char EA_flags;
@@ -2034,21 +2041,21 @@ struct fea {
 	__le16 value_len;
 	char name[1];
 	/* optionally followed by value */
-};
+} __attribute__((packed));
 /* flags for _FEA.fEA */
 #define FEA_NEEDEA         0x80	/* need EA bit */
 
 struct fealist {
 	__le32 list_len;
 	struct fea list[1];
-};
+} __attribute__((packed));
 
 /* used to hold an arbitrary blob of data */
 struct data_blob {
 	__u8 *data;
 	size_t length;
 	void (*free) (struct data_blob * data_blob);
-};
+} __attribute__((packed));
 
 
 #ifdef CONFIG_CIFS_POSIX
@@ -2151,7 +2158,7 @@ struct xsymlink {
 	char cr2;        /* \n */
 /* if room left, then end with \n then 0x20s by convention but not required */
 	char path[1024];  
-};
+} __attribute__((packed));
 
 typedef struct file_xattr_info {
 	/* BB do we need another field for flags? BB */
@@ -2159,7 +2166,7 @@ typedef struct file_xattr_info {
 	__u32 xattr_value_len;
 	char  xattr_name[0];
 	/* followed by xattr_value[xattr_value_len], no pad */
-} FILE_XATTR_INFO;	/* extended attribute, info level 0x205 */
+} __attribute__((packed)) FILE_XATTR_INFO;	/* extended attribute, info level 0x205 */
 
 
 /* flags for chattr command */
@@ -2185,10 +2192,8 @@ typedef struct file_xattr_info {
 typedef struct file_chattr_info {
 	__le64	mask; /* list of all possible attribute bits */
 	__le64	mode; /* list of actual attribute bits on this inode */
-} FILE_CHATTR_INFO;  /* ext attributes (chattr, chflags) level 0x206 */
+} __attribute__((packed)) FILE_CHATTR_INFO;  /* ext attributes (chattr, chflags) level 0x206 */
 
 #endif 
 
-#pragma pack()			/* resume default structure packing */
-
 #endif				/* _CIFSPDU_H */
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h
index 6facb41117a3..803389b64a2c 100644
--- a/fs/cifs/ntlmssp.h
+++ b/fs/cifs/ntlmssp.h
@@ -19,8 +19,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
  */
 
-#pragma pack(1)
-
 #define NTLMSSP_SIGNATURE "NTLMSSP"
 /* Message Types */
 #define NtLmNegotiate     cpu_to_le32(1)
@@ -63,7 +61,7 @@ typedef struct _SECURITY_BUFFER {
 	__le16 Length;
 	__le16 MaximumLength;
 	__le32 Buffer;		/* offset to buffer */
-} SECURITY_BUFFER;
+} __attribute__((packed)) SECURITY_BUFFER;
 
 typedef struct _NEGOTIATE_MESSAGE {
 	__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
@@ -73,7 +71,7 @@ typedef struct _NEGOTIATE_MESSAGE {
 	SECURITY_BUFFER WorkstationName;	/* RFC 1001 and ASCII */
 	char DomainString[0];
 	/* followed by WorkstationString */
-} NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
+} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
 
 typedef struct _CHALLENGE_MESSAGE {
 	__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
@@ -83,7 +81,7 @@ typedef struct _CHALLENGE_MESSAGE {
 	__u8 Challenge[CIFS_CRYPTO_KEY_SIZE];
 	__u8 Reserved[8];
 	SECURITY_BUFFER TargetInfoArray;
-} CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
+} __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
 
 typedef struct _AUTHENTICATE_MESSAGE {
 	__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
@@ -96,6 +94,4 @@ typedef struct _AUTHENTICATE_MESSAGE {
 	SECURITY_BUFFER SessionKey;
 	__le32 NegotiateFlags;
 	char UserString[0];
-} AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
-
-#pragma pack()			/* resume default structure packing */
+} __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
diff --git a/fs/cifs/rfc1002pdu.h b/fs/cifs/rfc1002pdu.h
index 806c0ed06da9..9222033cad8e 100644
--- a/fs/cifs/rfc1002pdu.h
+++ b/fs/cifs/rfc1002pdu.h
@@ -21,8 +21,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
  */
 
-#pragma pack(1)
-
 /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */
 
 	/* RFC 1002 session packet types */
@@ -48,17 +46,17 @@ struct rfc1002_session_packet {
 			__u8 calling_len;
 			__u8 calling_name[32];
 			__u8 scope2; /* null */
-		} session_req;
+		} __attribute__((packed)) session_req;
 		struct {
 			__u32 retarget_ip_addr;
 			__u16 port;
-		} retarget_resp;
+		} __attribute__((packed)) retarget_resp;
 		__u8 neg_ses_resp_error_code;
 		/* POSITIVE_SESSION_RESPONSE packet does not include trailer.
 		SESSION_KEEP_ALIVE packet also does not include a trailer.
 		Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */
-	} trailer;
-};
+	} __attribute__((packed)) trailer;
+} __attribute__((packed));
 
 /* Negative Session Response error codes */
 #define RFC1002_NOT_LISTENING_CALLED  0x80 /* not listening on called name */
@@ -74,6 +72,3 @@ server netbios name). Currently server names are resolved only via DNS
 (tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/
 
 #define DEFAULT_CIFS_CALLED_NAME  "*SMBSERVER      "
-
-#pragma pack()		/* resume default structure packing */
-                                                             
-- 
cgit v1.2.3


From 7f28570185f98bfa83f775756ced79e9f22b6d93 Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Tue, 1 Nov 2005 10:22:55 -0800
Subject: Export __pagevec_release and pagevec_lookup_tag

These are needed to implement cifs_writepages

Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 mm/swap.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/mm/swap.c b/mm/swap.c
index 96387e20184a..154ae13d8b7e 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -259,6 +259,8 @@ void __pagevec_release(struct pagevec *pvec)
 	pagevec_reinit(pvec);
 }
 
+EXPORT_SYMBOL(__pagevec_release);
+
 /*
  * pagevec_release() for pages which are known to not be on the LRU
  *
@@ -387,6 +389,7 @@ unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
 	return pagevec_count(pvec);
 }
 
+EXPORT_SYMBOL(pagevec_lookup_tag);
 
 #ifdef CONFIG_SMP
 /*
-- 
cgit v1.2.3