bk://cifs.bkbits.net/linux-2.5cifs
stevef@smfhome.smfdom|ChangeSet|20041222181136|33493 stevef

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/12/22 12:11:36-06:00 stevef@smfhome.smfdom 
#   [CIFS] Fix whitespace
#   
#   Signed-off-by:  Steve French (sfrench@us.ibm.com)
# 
# fs/cifs/cifssmb.c
#   2004/12/22 12:11:27-06:00 stevef@smfhome.smfdom +3 -3
#   Fix whitespace
# 
# ChangeSet
#   2004/12/21 11:08:59-06:00 sfrench@sambaltcdom.austin.ibm.com 
#   [CIFS] Enable reads over 64K by setting large read and write capability at SMB session negotiation
#   
#   Signed-off-by: Steve French (sfrench@us.ibm.com)
# 
# fs/cifs/connect.c
#   2004/12/21 11:08:51-06:00 sfrench@sambaltcdom.austin.ibm.com +1 -1
#   Enable reads over 64K by setting large read and write capability at SMB session negotiation
# 
# ChangeSet
#   2004/12/19 10:19:16-06:00 sfrench@sambaltcdom.austin.ibm.com 
#   [CIFS] Fix set of mount option rsize so it can be set above negotiated buffer size.
#   
#   Signed-off-by: Steve French (sfrench@us.ibm.com)
# 
# fs/cifs/connect.c
#   2004/12/19 10:19:08-06:00 sfrench@sambaltcdom.austin.ibm.com +1 -1
#   Fix set of mount option rsize so it can be set above negotiated buffer size.
# 
# ChangeSet
#   2004/12/18 16:01:31-06:00 sfrench@sambaltcdom.austin.ibm.com 
#   check rc of copy_to_user (pointed out by John Cherry)
#   fix wsize mount parm so it works to control writes
#   allow reads bigger than 64K (although Samba does not handle them yet).
#   
#   Signed-off-by: Steve French (sfrench@us.ibm.com)
# 
# fs/cifs/file.c
#   2004/12/18 16:01:12-06:00 sfrench@sambaltcdom.austin.ibm.com +14 -10
#   check rc of copy_to_user to fix warning pointed out by John Cherry
# 
# fs/cifs/connect.c
#   2004/12/18 16:01:12-06:00 sfrench@sambaltcdom.austin.ibm.com +2 -2
#   adjust wsize default, and fix wsize mount parm so it is used
# 
# fs/cifs/cifssmb.c
#   2004/12/18 16:01:12-06:00 sfrench@sambaltcdom.austin.ibm.com +39 -22
#   misc large read/write fixes, for sizes > 64K
# 
# fs/cifs/cifspdu.h
#   2004/12/18 16:01:11-06:00 sfrench@sambaltcdom.austin.ibm.com +2 -2
#   Definition of write frame missing high offset of count field.
# 
diff -Nru a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
--- a/fs/cifs/cifspdu.h	2005-01-02 23:07:51 -08:00
+++ b/fs/cifs/cifspdu.h	2005-01-02 23:07:51 -08:00
@@ -568,7 +568,6 @@
 #define SMB_SHARE_IS_IN_DFS     0x0002
 
 typedef struct smb_com_logoff_andx_req {
-
 	struct smb_hdr hdr;	/* wct = 2 */
 	__u8 AndXCommand;
 	__u8 AndXReserved;
@@ -695,7 +694,8 @@
 	__le16 AndXOffset;
 	__le16 Count;
 	__le16 Remaining;
-	__le32 Reserved;
+	__le16 CountHigh;
+	__u16  Reserved;
 	__u16 ByteCount;
 } WRITE_RSP;
 
diff -Nru a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
--- a/fs/cifs/cifssmb.c	2005-01-02 23:07:51 -08:00
+++ b/fs/cifs/cifssmb.c	2005-01-02 23:07:51 -08:00
@@ -802,6 +802,8 @@
 	char *pReadData = NULL;
 	int bytes_returned;
 
+	cFYI(1,("Reading %d bytes on fid %d",count,netfid));
+
 	*nbytes = 0;
 	rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
@@ -817,8 +819,8 @@
 	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
 	pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
 	pSMB->Remaining = 0;
-	pSMB->MaxCount = cpu_to_le16(count);
-	pSMB->MaxCountHigh = 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 */
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
@@ -826,8 +828,11 @@
 	if (rc) {
 		cERROR(1, ("Send error in read = %d", rc));
 	} else {
-		__u16 data_length = le16_to_cpu(pSMBr->DataLength);
+		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)) {
@@ -868,9 +873,10 @@
 	WRITE_REQ *pSMB = NULL;
 	WRITE_RSP *pSMBr = NULL;
 	int bytes_returned;
-	unsigned bytes_sent;
+	__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,
 		      (void **) &pSMBr);
 	if (rc)
@@ -886,31 +892,41 @@
 	pSMB->Reserved = 0xFFFFFFFF;
 	pSMB->WriteMode = 0;
 	pSMB->Remaining = 0;
-	/* BB can relax this if buffer is big enough in some cases - ie we can 
-	send more  if LARGE_WRITE_X capability returned by the server and if
+
+	/* Can increase buffer size if buffer is big enough in some cases - ie we 
+	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 */
-	bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
+	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);
-    if(buf)
+	if(buf)
 	    memcpy(pSMB->Data,buf,bytes_sent);
-	else if(ubuf)
-		copy_from_user(pSMB->Data,ubuf,bytes_sent);
-    else {
+	else if(ubuf) {
+		if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
+			if(pSMB)
+				cifs_buf_release(pSMB);
+			return -EFAULT;
+		}
+	} else {
 		/* No buffer */
 		if(pSMB)
 			cifs_buf_release(pSMB);
 		return -EINVAL;
 	}
 
-	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);
+	pSMB->hdr.smb_buf_length += bytes_sent+1;
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
@@ -918,8 +934,11 @@
 	if (rc) {
 		cFYI(1, ("Send error in write = %d", rc));
 		*nbytes = 0;
-	} else
-		*nbytes = le16_to_cpu(pSMBr->Count);
+	} else {
+		*nbytes = le16_to_cpu(pSMBr->CountHigh);
+		*nbytes = (*nbytes) << 16;
+		*nbytes += le16_to_cpu(pSMBr->Count);
+	}
 
 	if (pSMB)
 		cifs_buf_release(pSMB);
@@ -1913,14 +1932,13 @@
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
 			cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
-				/* BB fixme find define for this maxpathcomponent */
 				, nls_codepage);
 		name_len++;     /* trailing null */
 		name_len *= 2;
 		pSMB->FileName[name_len] = 0;
 		pSMB->FileName[name_len+1] = 0;
 	} else {                /* BB improve the check for buffer overruns BB */
-		name_len = strnlen(searchName, PATH_MAX /* BB fixme */);
+		name_len = strnlen(searchName, PATH_MAX);
 		name_len++;     /* trailing null */
 		strncpy(pSMB->FileName, searchName, name_len);
 	}
@@ -1996,10 +2014,9 @@
                       (void **) &pSMBr);
 	if (rc)
 		return rc;
-                                                                                                               	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
 			cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
-				/* BB fixme find define for this maxpathcomponent */
 				, nls_codepage);
 		name_len++;     /* trailing null */
 		name_len *= 2;
@@ -2051,9 +2068,9 @@
 setACLerrorExit:
 	if (pSMB)
 		cifs_buf_release(pSMB);
-                                                                                                            	if (rc == -EAGAIN)
+	if (rc == -EAGAIN)
 		goto setAclRetry;
-                                                                                                           	return rc;
+	return rc;
 }
 
 #endif
@@ -2072,7 +2089,7 @@
 	int name_len;
 	__u16 params, byte_count;
 
-/* cFYI(1, ("In QPathInfo path %s", searchName)); */ /* BB fixme BB */
+/* cFYI(1, ("In QPathInfo path %s", searchName)); */
 QPathInfoRetry:
 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c
--- a/fs/cifs/connect.c	2005-01-02 23:07:51 -08:00
+++ b/fs/cifs/connect.c	2005-01-02 23:07:51 -08:00
@@ -1410,14 +1410,14 @@
     
 	/* search for existing tcon to this server share */
 	if (!rc) {
-		if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+		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) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+		if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
 			cifs_sb->wsize = volume_info.wsize;
 		else
-			cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
+			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)"));
@@ -1591,7 +1591,7 @@
 	if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
 		smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
-	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS;
+	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
 	if (ses->capabilities & CAP_UNICODE) {
 		smb_buffer->Flags2 |= SMBFLG2_UNICODE;
 		capabilities |= CAP_UNICODE;
diff -Nru a/fs/cifs/file.c b/fs/cifs/file.c
--- a/fs/cifs/file.c	2005-01-02 23:07:51 -08:00
+++ b/fs/cifs/file.c	2005-01-02 23:07:51 -08:00
@@ -680,10 +680,10 @@
 			}
 
 			rc = CIFSSMBWrite(xid, pTcon,
-				  open_file->netfid,
-				  write_size - total_written, *poffset,
-				  &bytes_written,
-				  NULL, write_data + total_written, long_op);
+				open_file->netfid,
+				min_t(const int,cifs_sb->wsize,write_size - total_written),
+				*poffset, &bytes_written,
+				NULL, write_data + total_written, long_op);
 		}
 		if (rc || (bytes_written == 0)) {
 			if (total_written)
@@ -799,10 +799,10 @@
 			}
 
 			rc = CIFSSMBWrite(xid, pTcon,
-				  open_file->netfid,
-				  write_size - total_written, *poffset,
-				  &bytes_written,
-				  write_data + total_written, NULL, long_op);
+				 open_file->netfid,
+				 min_t(const int,cifs_sb->wsize,write_size - total_written),
+				 *poffset,&bytes_written,
+				 write_data + total_written, NULL, long_op);
 		}
 		if (rc || (bytes_written == 0)) {
 			if (total_written)
@@ -1164,8 +1164,12 @@
 				 &bytes_read, &smb_read_data);
 
 			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
-			copy_to_user(current_offset,smb_read_data + 4/* RFC1001 hdr*/
-				+ le16_to_cpu(pSMBr->DataOffset), bytes_read);
+			if(copy_to_user(current_offset,smb_read_data + 4/* RFC1001 hdr*/
+				+ le16_to_cpu(pSMBr->DataOffset), bytes_read)) {
+				rc = -EFAULT;
+				FreeXid(xid);
+				return rc;
+            }
 			if(smb_read_data) {
 				cifs_buf_release(smb_read_data);
 				smb_read_data = NULL;