Browse Source

[CIFS] Avoid extra large buffer allocation (and memcpy) in cifs_readpages

Signed-off-by: Steve French <sfrench@us.ibm.com>
Steve French 19 years ago
parent
commit
ec637e3ffb
11 changed files with 156 additions and 108 deletions
  1. 19 20
      fs/cifs/cifs_debug.c
  2. 3 2
      fs/cifs/cifsfs.c
  3. 7 1
      fs/cifs/cifsglob.h
  4. 5 1
      fs/cifs/cifspdu.h
  5. 8 6
      fs/cifs/cifsproto.h
  6. 58 35
      fs/cifs/cifssmb.c
  7. 1 1
      fs/cifs/connect.c
  8. 32 20
      fs/cifs/file.c
  9. 3 2
      fs/cifs/inode.c
  10. 1 1
      fs/cifs/misc.c
  11. 19 19
      fs/cifs/transport.c

+ 19 - 20
fs/cifs/cifs_debug.c

@@ -401,8 +401,8 @@ static read_proc_t ntlmv2_enabled_read;
 static write_proc_t ntlmv2_enabled_write;
 static write_proc_t ntlmv2_enabled_write;
 static read_proc_t packet_signing_enabled_read;
 static read_proc_t packet_signing_enabled_read;
 static write_proc_t packet_signing_enabled_write;
 static write_proc_t packet_signing_enabled_write;
-static read_proc_t quotaEnabled_read;
-static write_proc_t quotaEnabled_write;
+static read_proc_t experimEnabled_read;
+static write_proc_t experimEnabled_write;
 static read_proc_t linuxExtensionsEnabled_read;
 static read_proc_t linuxExtensionsEnabled_read;
 static write_proc_t linuxExtensionsEnabled_write;
 static write_proc_t linuxExtensionsEnabled_write;
 
 
@@ -442,9 +442,9 @@ cifs_proc_init(void)
 		pde->write_proc = oplockEnabled_write;
 		pde->write_proc = oplockEnabled_write;
 
 
 	pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs,
 	pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs,
-				quotaEnabled_read, NULL);
+				experimEnabled_read, NULL);
 	if (pde)
 	if (pde)
-		pde->write_proc = quotaEnabled_write;
+		pde->write_proc = experimEnabled_write;
 
 
 	pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs,
 	pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs,
 				linuxExtensionsEnabled_read, NULL);
 				linuxExtensionsEnabled_read, NULL);
@@ -586,14 +586,13 @@ oplockEnabled_write(struct file *file, const char __user *buffer,
 }
 }
 
 
 static int
 static int
-quotaEnabled_read(char *page, char **start, off_t off,
+experimEnabled_read(char *page, char **start, off_t off,
                    int count, int *eof, void *data)
                    int count, int *eof, void *data)
 {
 {
         int len;
         int len;
 
 
         len = sprintf(page, "%d\n", experimEnabled);
         len = sprintf(page, "%d\n", experimEnabled);
-/* could also check if quotas are enabled in kernel
-	as a whole first */
+
         len -= off;
         len -= off;
         *start = page + off;
         *start = page + off;
 
 
@@ -608,21 +607,23 @@ quotaEnabled_read(char *page, char **start, off_t off,
         return len;
         return len;
 }
 }
 static int
 static int
-quotaEnabled_write(struct file *file, const char __user *buffer,
+experimEnabled_write(struct file *file, const char __user *buffer,
                     unsigned long count, void *data)
                     unsigned long count, void *data)
 {
 {
-        char c;
-        int rc;
+	char c;
+	int rc;
 
 
-        rc = get_user(c, buffer);
-        if (rc)
-                return rc;
-        if (c == '0' || c == 'n' || c == 'N')
-                experimEnabled = 0;
-        else if (c == '1' || c == 'y' || c == 'Y')
-                experimEnabled = 1;
+	rc = get_user(c, buffer);
+	if (rc)
+		return rc;
+	if (c == '0' || c == 'n' || c == 'N')
+		experimEnabled = 0;
+	else if (c == '1' || c == 'y' || c == 'Y')
+		experimEnabled = 1;
+	else if (c == '2')
+		experimEnabled = 2;
 
 
-        return count;
+	return count;
 }
 }
 
 
 static int
 static int
@@ -632,8 +633,6 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off,
         int len;
         int len;
 
 
         len = sprintf(page, "%d\n", linuxExtEnabled);
         len = sprintf(page, "%d\n", linuxExtEnabled);
-/* could also check if quotas are enabled in kernel
-	as a whole first */
         len -= off;
         len -= off;
         *start = page + off;
         *start = page + off;
 
 

+ 3 - 2
fs/cifs/cifsfs.c

@@ -733,7 +733,7 @@ cifs_init_request_bufs(void)
 		kmem_cache_destroy(cifs_req_cachep);
 		kmem_cache_destroy(cifs_req_cachep);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
-	/* 256 (MAX_CIFS_HDR_SIZE bytes is enough for most SMB responses and
+	/* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and
 	almost all handle based requests (but not write response, nor is it
 	almost all handle based requests (but not write response, nor is it
 	sufficient for path based requests).  A smaller size would have
 	sufficient for path based requests).  A smaller size would have
 	been more efficient (compacting multiple slab items on one 4k page) 
 	been more efficient (compacting multiple slab items on one 4k page) 
@@ -742,7 +742,8 @@ cifs_init_request_bufs(void)
 	efficient to alloc 1 per page off the slab compared to 17K (5page) 
 	efficient to alloc 1 per page off the slab compared to 17K (5page) 
 	alloc of large cifs buffers even when page debugging is on */
 	alloc of large cifs buffers even when page debugging is on */
 	cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq",
 	cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq",
-			MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+			MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN, 
+			NULL, NULL);
 	if (cifs_sm_req_cachep == NULL) {
 	if (cifs_sm_req_cachep == NULL) {
 		mempool_destroy(cifs_req_poolp);
 		mempool_destroy(cifs_req_poolp);
 		kmem_cache_destroy(cifs_req_cachep);
 		kmem_cache_destroy(cifs_req_cachep);

+ 7 - 1
fs/cifs/cifsglob.h

@@ -285,6 +285,7 @@ struct cifs_search_info {
 	unsigned endOfSearch:1;
 	unsigned endOfSearch:1;
 	unsigned emptyDir:1;
 	unsigned emptyDir:1;
 	unsigned unicode:1;
 	unsigned unicode:1;
+	unsigned smallBuf:1; /* so we know which buf_release function to call */
 };
 };
 
 
 struct cifsFileInfo {
 struct cifsFileInfo {
@@ -420,7 +421,12 @@ struct dir_notify_req {
 #define   MID_RESPONSE_RECEIVED 4
 #define   MID_RESPONSE_RECEIVED 4
 #define   MID_RETRY_NEEDED      8 /* session closed while this request out */
 #define   MID_RETRY_NEEDED      8 /* session closed while this request out */
 #define   MID_NO_RESP_NEEDED 0x10
 #define   MID_NO_RESP_NEEDED 0x10
-#define   MID_SMALL_BUFFER   0x20 /* 112 byte response buffer instead of 4K */
+
+/* Types of response buffer returned from SendReceive2 */
+#define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
+#define   CIFS_SMALL_BUFFER     1
+#define   CIFS_LARGE_BUFFER     2
+#define   CIFS_IOVEC            4    /* array of response buffers */
 
 
 /*
 /*
  *****************************************************************
  *****************************************************************

+ 5 - 1
fs/cifs/cifspdu.h

@@ -80,7 +80,11 @@
 #define NT_TRANSACT_GET_USER_QUOTA    0x07
 #define NT_TRANSACT_GET_USER_QUOTA    0x07
 #define NT_TRANSACT_SET_USER_QUOTA    0x08
 #define NT_TRANSACT_SET_USER_QUOTA    0x08
 
 
-#define MAX_CIFS_HDR_SIZE 256	/* is future chained NTCreateXReadX bigger? */
+#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */
+/* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */
+/* among the requests (NTCreateX response is bigger with wct of 34) */
+#define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */
+#define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */
 
 
 /* internal cifs vfs structures */
 /* internal cifs vfs structures */
 /*****************************************************************
 /*****************************************************************

+ 8 - 6
fs/cifs/cifsproto.h

@@ -49,7 +49,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
 			int * /* bytes returned */ , const int long_op);
 			int * /* bytes returned */ , const int long_op);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
 extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
 			struct kvec *, int /* nvec to send */, 
 			struct kvec *, int /* nvec to send */, 
-			int * /* bytes returned */ , const int long_op);
+			int * /* type of buf returned */ , const int long_op);
 extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
 extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
 extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
 extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
 extern int is_valid_oplock_break(struct smb_hdr *smb);
 extern int is_valid_oplock_break(struct smb_hdr *smb);
@@ -93,11 +93,12 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 			const struct nls_table *);
 			const struct nls_table *);
 
 
 extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
 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, const char dirsep);
+		const char *searchName, const struct nls_table *nls_codepage,
+		__u16 *searchHandle, struct cifs_search_info * psrch_inf, 
+		int map, const char dirsep);
 
 
 extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
-            __u16 searchHandle, struct cifs_search_info * psrch_inf);
+		__u16 searchHandle, struct cifs_search_info * psrch_inf);
 
 
 extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
 extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
 			const __u16 search_handle);
 			const __u16 search_handle);
@@ -230,8 +231,9 @@ extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
 			const int smb_file_id);
 			const int smb_file_id);
 
 
 extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
-			const int netfid, unsigned int count,
-			const __u64 lseek, unsigned int *nbytes, char **buf);
+                        const int netfid, unsigned int count,
+                        const __u64 lseek, unsigned int *nbytes, char **buf,
+			int * return_buf_type);
 extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 			const int netfid, const unsigned int count,
 			const int netfid, const unsigned int count,
 			const __u64 lseek, unsigned int *nbytes,
 			const __u64 lseek, unsigned int *nbytes,

+ 58 - 35
fs/cifs/cifssmb.c

@@ -958,21 +958,19 @@ openRetry:
 	return rc;
 	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 */
-
 int
 int
 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
-	    const int netfid, const unsigned int count,
-	    const __u64 lseek, unsigned int *nbytes, char **buf)
+            const int netfid, const unsigned int count,
+            const __u64 lseek, unsigned int *nbytes, char **buf,
+	    int * pbuf_type)
 {
 {
 	int rc = -EACCES;
 	int rc = -EACCES;
 	READ_REQ *pSMB = NULL;
 	READ_REQ *pSMB = NULL;
 	READ_RSP *pSMBr = NULL;
 	READ_RSP *pSMBr = NULL;
 	char *pReadData = NULL;
 	char *pReadData = NULL;
-	int bytes_returned;
 	int wct;
 	int wct;
+	int resp_buf_type = 0;
+	struct kvec iov[1];
 
 
 	cFYI(1,("Reading %d bytes on fid %d",count,netfid));
 	cFYI(1,("Reading %d bytes on fid %d",count,netfid));
 	if(tcon->ses->capabilities & CAP_LARGE_FILES)
 	if(tcon->ses->capabilities & CAP_LARGE_FILES)
@@ -981,8 +979,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 		wct = 10; /* old style read */
 		wct = 10; /* old style read */
 
 
 	*nbytes = 0;
 	*nbytes = 0;
-	rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
-		      (void **) &pSMBr);
+	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
 	if (rc)
 	if (rc)
 		return rc;
 		return rc;
 
 
@@ -990,13 +987,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 	if (tcon->ses->server == NULL)
 	if (tcon->ses->server == NULL)
 		return -ECONNABORTED;
 		return -ECONNABORTED;
 
 
-	pSMB->AndXCommand = 0xFF;	/* none */
+	pSMB->AndXCommand = 0xFF;       /* none */
 	pSMB->Fid = netfid;
 	pSMB->Fid = netfid;
 	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
 	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
 	if(wct == 12)
 	if(wct == 12)
 		pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
 		pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
-        else if((lseek >> 32) > 0) /* can not handle this big offset for old */
-                return -EIO;
+	else if((lseek >> 32) > 0) /* can not handle this big offset for old */
+		return -EIO;
 
 
 	pSMB->Remaining = 0;
 	pSMB->Remaining = 0;
 	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
 	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
@@ -1005,14 +1002,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 		pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
 		pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
 	else {
 	else {
 		/* old style read */
 		/* old style read */
-		struct smb_com_readx_req * pSMBW = 
+		struct smb_com_readx_req * pSMBW =
 			(struct smb_com_readx_req *)pSMB;
 			(struct smb_com_readx_req *)pSMB;
-		pSMBW->ByteCount = 0;	
+		pSMBW->ByteCount = 0;
 	}
 	}
-	
-	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+	iov[0].iov_base = (char *)pSMB;
+	iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
+	rc = SendReceive2(xid, tcon->ses, iov, 
+			  1 /* num iovecs */,
+			  &resp_buf_type, 0); 
 	cifs_stats_inc(&tcon->num_reads);
 	cifs_stats_inc(&tcon->num_reads);
+	pSMBr = (READ_RSP *)iov[0].iov_base;
 	if (rc) {
 	if (rc) {
 		cERROR(1, ("Send error in read = %d", rc));
 		cERROR(1, ("Send error in read = %d", rc));
 	} else {
 	} else {
@@ -1022,33 +1023,43 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 		*nbytes = data_length;
 		*nbytes = data_length;
 
 
 		/*check that DataLength would not go beyond end of SMB */
 		/*check that DataLength would not go beyond end of SMB */
-		if ((data_length > CIFSMaxBufSize) 
+		if ((data_length > CIFSMaxBufSize)
 				|| (data_length > count)) {
 				|| (data_length > count)) {
 			cFYI(1,("bad length %d for count %d",data_length,count));
 			cFYI(1,("bad length %d for count %d",data_length,count));
 			rc = -EIO;
 			rc = -EIO;
 			*nbytes = 0;
 			*nbytes = 0;
 		} else {
 		} else {
-			pReadData =
-			    (char *) (&pSMBr->hdr.Protocol) +
+			pReadData = (char *) (&pSMBr->hdr.Protocol) +
 			    le16_to_cpu(pSMBr->DataOffset);
 			    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(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)
 			if(*buf)
-			    memcpy(*buf,pReadData,data_length);
+				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 
+	cifs_small_buf_release(pSMB);
+	if(*buf) {
+		if(resp_buf_type == CIFS_SMALL_BUFFER)
+			cifs_small_buf_release(iov[0].iov_base);
+		else if(resp_buf_type == CIFS_LARGE_BUFFER)
+			cifs_buf_release(iov[0].iov_base);
+	} else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ {
+		*buf = iov[0].iov_base;
+		if(resp_buf_type == CIFS_SMALL_BUFFER)
+			*pbuf_type = CIFS_SMALL_BUFFER;
+		else if(resp_buf_type == CIFS_LARGE_BUFFER)
+			*pbuf_type = CIFS_LARGE_BUFFER;
+	}
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls
 		since file handle passed in no longer valid */
 		since file handle passed in no longer valid */
 	return rc;
 	return rc;
 }
 }
 
 
+
 int
 int
 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 	     const int netfid, const unsigned int count,
 	     const int netfid, const unsigned int count,
@@ -1163,10 +1174,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 {
 {
 	int rc = -EACCES;
 	int rc = -EACCES;
 	WRITE_REQ *pSMB = NULL;
 	WRITE_REQ *pSMB = NULL;
-	int bytes_returned, wct;
+	int wct;
 	int smb_hdr_len;
 	int smb_hdr_len;
+	int resp_buf_type = 0;
 
 
-	/* BB removeme BB */
 	cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
 	cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
 
 
 	if(tcon->ses->capabilities & CAP_LARGE_FILES)
 	if(tcon->ses->capabilities & CAP_LARGE_FILES)
@@ -1209,22 +1220,34 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 		pSMBW->ByteCount = cpu_to_le16(count + 5);
 		pSMBW->ByteCount = cpu_to_le16(count + 5);
 	}
 	}
 	iov[0].iov_base = pSMB;
 	iov[0].iov_base = pSMB;
-	iov[0].iov_len = smb_hdr_len + 4;
+	if(wct == 14)
+		iov[0].iov_len = smb_hdr_len + 4;
+	else /* wct == 12 pad bigger by four bytes */
+		iov[0].iov_len = smb_hdr_len + 8;
+	
 
 
-	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned,
+	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
 			  long_op);
 			  long_op);
 	cifs_stats_inc(&tcon->num_writes);
 	cifs_stats_inc(&tcon->num_writes);
 	if (rc) {
 	if (rc) {
 		cFYI(1, ("Send error Write2 = %d", rc));
 		cFYI(1, ("Send error Write2 = %d", rc));
 		*nbytes = 0;
 		*nbytes = 0;
+	} else if(resp_buf_type == 0) {
+		/* presumably this can not happen, but best to be safe */
+		rc = -EIO;
+		*nbytes = 0;
 	} else {
 	} else {
-		WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
+		WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
 		*nbytes = le16_to_cpu(pSMBr->CountHigh);
 		*nbytes = le16_to_cpu(pSMBr->CountHigh);
 		*nbytes = (*nbytes) << 16;
 		*nbytes = (*nbytes) << 16;
 		*nbytes += le16_to_cpu(pSMBr->Count);
 		*nbytes += le16_to_cpu(pSMBr->Count);
 	} 
 	} 
 
 
 	cifs_small_buf_release(pSMB);
 	cifs_small_buf_release(pSMB);
+	if(resp_buf_type == CIFS_SMALL_BUFFER)
+		cifs_small_buf_release(iov[0].iov_base);
+	else if(resp_buf_type == CIFS_LARGE_BUFFER)
+		cifs_buf_release(iov[0].iov_base);
 
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls 
 		since file handle passed in no longer valid */
 		since file handle passed in no longer valid */

+ 1 - 1
fs/cifs/connect.c

@@ -514,7 +514,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 		/* else length ok */
 		/* else length ok */
 		reconnect = 0;
 		reconnect = 0;
 
 
-		if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
+		if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
 			isLargeBuf = TRUE;
 			isLargeBuf = TRUE;
 			memcpy(bigbuf, smallbuf, 4);
 			memcpy(bigbuf, smallbuf, 4);
 			smb_buffer = bigbuf;
 			smb_buffer = bigbuf;

+ 32 - 20
fs/cifs/file.c

@@ -555,13 +555,13 @@ int cifs_closedir(struct inode *inode, struct file *file)
 		}
 		}
 		ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
 		ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
 		if (ptmp) {
 		if (ptmp) {
-   /* BB removeme BB */	cFYI(1, ("freeing smb buf in srch struct in closedir"));
+			cFYI(1, ("closedir free smb buf in srch struct"));
 			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
 			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
 			cifs_buf_release(ptmp);
 			cifs_buf_release(ptmp);
 		}
 		}
 		ptmp = pCFileStruct->search_resume_name;
 		ptmp = pCFileStruct->search_resume_name;
 		if (ptmp) {
 		if (ptmp) {
-   /* BB removeme BB */	cFYI(1, ("freeing resume name in closedir"));
+			cFYI(1, ("closedir free resume name"));
 			pCFileStruct->search_resume_name = NULL;
 			pCFileStruct->search_resume_name = NULL;
 			kfree(ptmp);
 			kfree(ptmp);
 		}
 		}
@@ -871,8 +871,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 					break;
 					break;
 			}
 			}
 			/* BB FIXME We can not sign across two buffers yet */
 			/* BB FIXME We can not sign across two buffers yet */
-			if((experimEnabled) && ((pTcon->ses->server->secMode & 
-			 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) {
+			if((pTcon->ses->server->secMode & 
+			 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) {
 				struct kvec iov[2];
 				struct kvec iov[2];
 				unsigned int len;
 				unsigned int len;
 
 
@@ -1424,6 +1424,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 		rc = -EAGAIN;
 		rc = -EAGAIN;
 		smb_read_data = NULL;
 		smb_read_data = NULL;
 		while (rc == -EAGAIN) {
 		while (rc == -EAGAIN) {
+			int buf_type = CIFS_NO_BUFFER;
 			if ((open_file->invalidHandle) && 
 			if ((open_file->invalidHandle) && 
 			    (!open_file->closePend)) {
 			    (!open_file->closePend)) {
 				rc = cifs_reopen_file(file->f_dentry->d_inode,
 				rc = cifs_reopen_file(file->f_dentry->d_inode,
@@ -1432,20 +1433,22 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
 					break;
 					break;
 			}
 			}
 			rc = CIFSSMBRead(xid, pTcon,
 			rc = CIFSSMBRead(xid, pTcon,
-					open_file->netfid,
-					current_read_size, *poffset,
-					&bytes_read, &smb_read_data);
+					 open_file->netfid,
+					 current_read_size, *poffset,
+					 &bytes_read, &smb_read_data,
+					 &buf_type);
 			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
 			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
 			if (copy_to_user(current_offset, 
 			if (copy_to_user(current_offset, 
 					 smb_read_data + 4 /* RFC1001 hdr */
 					 smb_read_data + 4 /* RFC1001 hdr */
 					 + le16_to_cpu(pSMBr->DataOffset), 
 					 + le16_to_cpu(pSMBr->DataOffset), 
 					 bytes_read)) {
 					 bytes_read)) {
 				rc = -EFAULT;
 				rc = -EFAULT;
-				FreeXid(xid);
-				return rc;
-            }
+			}
 			if (smb_read_data) {
 			if (smb_read_data) {
-				cifs_buf_release(smb_read_data);
+				if(buf_type == CIFS_SMALL_BUFFER)
+					cifs_small_buf_release(smb_read_data);
+				else if(buf_type == CIFS_LARGE_BUFFER)
+					cifs_buf_release(smb_read_data);
 				smb_read_data = NULL;
 				smb_read_data = NULL;
 			}
 			}
 		}
 		}
@@ -1478,6 +1481,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 	int xid;
 	int xid;
 	char *current_offset;
 	char *current_offset;
 	struct cifsFileInfo *open_file;
 	struct cifsFileInfo *open_file;
+	int buf_type = CIFS_NO_BUFFER;
 
 
 	xid = GetXid();
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
@@ -1514,9 +1518,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
 					break;
 					break;
 			}
 			}
 			rc = CIFSSMBRead(xid, pTcon,
 			rc = CIFSSMBRead(xid, pTcon,
-					open_file->netfid,
-					current_read_size, *poffset,
-					&bytes_read, &current_offset);
+					 open_file->netfid,
+					 current_read_size, *poffset,
+					 &bytes_read, &current_offset,
+					 &buf_type);
 		}
 		}
 		if (rc || (bytes_read == 0)) {
 		if (rc || (bytes_read == 0)) {
 			if (total_read) {
 			if (total_read) {
@@ -1614,6 +1619,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 	struct smb_com_read_rsp *pSMBr;
 	struct smb_com_read_rsp *pSMBr;
 	struct pagevec lru_pvec;
 	struct pagevec lru_pvec;
 	struct cifsFileInfo *open_file;
 	struct cifsFileInfo *open_file;
+	int buf_type = CIFS_NO_BUFFER;
 
 
 	xid = GetXid();
 	xid = GetXid();
 	if (file->private_data == NULL) {
 	if (file->private_data == NULL) {
@@ -1670,14 +1676,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 			}
 			}
 
 
 			rc = CIFSSMBRead(xid, pTcon,
 			rc = CIFSSMBRead(xid, pTcon,
-					open_file->netfid,
-					read_size, offset,
-					&bytes_read, &smb_read_data);
-
+					 open_file->netfid,
+					 read_size, offset,
+					 &bytes_read, &smb_read_data,
+					 &buf_type);
 			/* BB more RC checks ? */
 			/* BB more RC checks ? */
 			if (rc== -EAGAIN) {
 			if (rc== -EAGAIN) {
 				if (smb_read_data) {
 				if (smb_read_data) {
-					cifs_buf_release(smb_read_data);
+					if(buf_type == CIFS_SMALL_BUFFER)
+						cifs_small_buf_release(smb_read_data);
+					else if(buf_type == CIFS_LARGE_BUFFER)
+						cifs_buf_release(smb_read_data);
 					smb_read_data = NULL;
 					smb_read_data = NULL;
 				}
 				}
 			}
 			}
@@ -1734,7 +1743,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 			break;
 			break;
 		}
 		}
 		if (smb_read_data) {
 		if (smb_read_data) {
-			cifs_buf_release(smb_read_data);
+			if(buf_type == CIFS_SMALL_BUFFER)
+				cifs_small_buf_release(smb_read_data);
+			else if(buf_type == CIFS_LARGE_BUFFER)
+				cifs_buf_release(smb_read_data);
 			smb_read_data = NULL;
 			smb_read_data = NULL;
 		}
 		}
 		bytes_read = 0;
 		bytes_read = 0;

+ 3 - 2
fs/cifs/inode.c

@@ -229,11 +229,12 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
 			 cifs_sb->mnt_cifs_flags &
 			 cifs_sb->mnt_cifs_flags &
 				CIFS_MOUNT_MAP_SPECIAL_CHR);
 				CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc==0) {
 	if (rc==0) {
+		int buf_type = CIFS_NO_BUFFER;
 			/* Read header */
 			/* Read header */
 		rc = CIFSSMBRead(xid, pTcon,
 		rc = CIFSSMBRead(xid, pTcon,
 			         netfid,
 			         netfid,
 				 24 /* length */, 0 /* offset */,
 				 24 /* length */, 0 /* offset */,
-				 &bytes_read, &pbuf);
+				 &bytes_read, &pbuf, &buf_type);
 		if((rc == 0) && (bytes_read >= 8)) {
 		if((rc == 0) && (bytes_read >= 8)) {
 			if(memcmp("IntxBLK", pbuf, 8) == 0) {
 			if(memcmp("IntxBLK", pbuf, 8) == 0) {
 				cFYI(1,("Block device"));
 				cFYI(1,("Block device"));
@@ -267,7 +268,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
 		} else {
 		} else {
 			inode->i_mode |= S_IFREG; /* then it is a file */
 			inode->i_mode |= S_IFREG; /* then it is a file */
 			rc = -EOPNOTSUPP; /* or some unknown SFU type */	
 			rc = -EOPNOTSUPP; /* or some unknown SFU type */	
-		}
+		}		
 		CIFSSMBClose(xid, pTcon, netfid);
 		CIFSSMBClose(xid, pTcon, netfid);
 	}
 	}
 	return rc;
 	return rc;

+ 1 - 1
fs/cifs/misc.c

@@ -299,7 +299,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 	struct cifsSesInfo * ses;
 	struct cifsSesInfo * ses;
 	char *temp = (char *) buffer;
 	char *temp = (char *) buffer;
 
 
-	memset(temp,0,MAX_CIFS_HDR_SIZE);
+	memset(temp,0,256); /* bigger than MAX_CIFS_HDR_SIZE */
 
 
 	buffer->smb_buf_length =
 	buffer->smb_buf_length =
 	    (2 * word_count) + sizeof (struct smb_hdr) -
 	    (2 * word_count) + sizeof (struct smb_hdr) -

+ 19 - 19
fs/cifs/transport.c

@@ -298,7 +298,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
 
 
 int
 int
 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
-	     struct kvec *iov, int n_vec, int *pbytes_returned,
+	     struct kvec *iov, int n_vec, int * pRespBufType /* ret */, 
 	     const int long_op)
 	     const int long_op)
 {
 {
 	int rc = 0;
 	int rc = 0;
@@ -306,6 +306,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 	unsigned long timeout;
 	unsigned long timeout;
 	struct mid_q_entry *midQ;
 	struct mid_q_entry *midQ;
 	struct smb_hdr *in_buf = iov[0].iov_base;
 	struct smb_hdr *in_buf = iov[0].iov_base;
+	
+	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
 
 
 	if (ses == NULL) {
 	if (ses == NULL) {
 		cERROR(1,("Null smb session"));
 		cERROR(1,("Null smb session"));
@@ -491,23 +493,20 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 		if (midQ->resp_buf && 
 		if (midQ->resp_buf && 
 			(midQ->midState == MID_RESPONSE_RECEIVED)) {
 			(midQ->midState == MID_RESPONSE_RECEIVED)) {
 
 
-			in_buf->smb_buf_length = receive_len;
-			if(receive_len > 500) {
-				/* use multiple buffers on way out */
-			} else { 
-				memcpy((char *)in_buf + 4,
-					(char *)midQ->resp_buf + 4,
-					receive_len);
-				iov[0].iov_len = receive_len + 4;
-				iov[1].iov_len = 0;
-			}
+			iov[0].iov_base = (char *)midQ->resp_buf;
+			if(midQ->largeBuf)
+				*pRespBufType = CIFS_LARGE_BUFFER;
+			else
+				*pRespBufType = CIFS_SMALL_BUFFER;
+			iov[0].iov_len = receive_len + 4;
+			iov[1].iov_len = 0;
 
 
-			dump_smb(in_buf, 80);
+			dump_smb(midQ->resp_buf, 80);
 			/* convert the length into a more usable form */
 			/* convert the length into a more usable form */
 			if((receive_len > 24) &&
 			if((receive_len > 24) &&
 			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
 			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
 					SECMODE_SIGN_ENABLED))) {
 					SECMODE_SIGN_ENABLED))) {
-				rc = cifs_verify_signature(in_buf,
+				rc = cifs_verify_signature(midQ->resp_buf,
 						ses->server->mac_signing_key,
 						ses->server->mac_signing_key,
 						midQ->sequence_number+1);
 						midQ->sequence_number+1);
 				if(rc) {
 				if(rc) {
@@ -516,18 +515,19 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 				}
 				}
 			}
 			}
 
 
-			*pbytes_returned = in_buf->smb_buf_length;
-
 			/* BB special case reconnect tid and uid here? */
 			/* BB special case reconnect tid and uid here? */
 			/* BB special case Errbadpassword and pwdexpired here */
 			/* BB special case Errbadpassword and pwdexpired here */
-			rc = map_smb_to_linux_error(in_buf);
+			rc = map_smb_to_linux_error(midQ->resp_buf);
 
 
 			/* convert ByteCount if necessary */
 			/* convert ByteCount if necessary */
 			if (receive_len >=
 			if (receive_len >=
 			    sizeof (struct smb_hdr) -
 			    sizeof (struct smb_hdr) -
 			    4 /* do not count RFC1001 header */  +
 			    4 /* do not count RFC1001 header */  +
-			    (2 * in_buf->WordCount) + 2 /* bcc */ )
-				BCC(in_buf) = le16_to_cpu(BCC_LE(in_buf));
+			    (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
+				BCC(midQ->resp_buf) = 
+					le16_to_cpu(BCC_LE(midQ->resp_buf));
+			midQ->resp_buf = NULL;  /* mark it so will not be freed
+						by DeleteMidQEntry */
 		} else {
 		} else {
 			rc = -EIO;
 			rc = -EIO;
 			cFYI(1,("Bad MID state?"));
 			cFYI(1,("Bad MID state?"));
@@ -793,7 +793,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
 				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
 		} else {
 		} else {
 			rc = -EIO;
 			rc = -EIO;
-			cERROR(1,("Bad MID state? "));
+			cERROR(1,("Bad MID state?"));
 		}
 		}
 	}
 	}
 cifs_no_response_exit:
 cifs_no_response_exit: