[CIFS] Avoid extra large buffer allocation (and memcpy) in cifs_readpages
Steve French [Tue, 13 Dec 2005 04:53:18 +0000 (20:53 -0800)]
Signed-off-by: Steve French <sfrench@us.ibm.com>

fs/cifs/cifs_debug.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/misc.c
fs/cifs/transport.c

index 6f5d81f..f4124a3 100644 (file)
@@ -401,8 +401,8 @@ static read_proc_t ntlmv2_enabled_read;
 static write_proc_t ntlmv2_enabled_write;
 static read_proc_t packet_signing_enabled_read;
 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 write_proc_t linuxExtensionsEnabled_write;
 
@@ -442,9 +442,9 @@ cifs_proc_init(void)
                pde->write_proc = oplockEnabled_write;
 
        pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs,
-                               quotaEnabled_read, NULL);
+                               experimEnabled_read, NULL);
        if (pde)
-               pde->write_proc = quotaEnabled_write;
+               pde->write_proc = experimEnabled_write;
 
        pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs,
                                linuxExtensionsEnabled_read, NULL);
@@ -586,14 +586,13 @@ oplockEnabled_write(struct file *file, const char __user *buffer,
 }
 
 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 len;
 
         len = sprintf(page, "%d\n", experimEnabled);
-/* could also check if quotas are enabled in kernel
-       as a whole first */
+
         len -= off;
         *start = page + off;
 
@@ -608,21 +607,23 @@ quotaEnabled_read(char *page, char **start, off_t off,
         return len;
 }
 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)
 {
-        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
@@ -632,8 +633,6 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off,
         int len;
 
         len = sprintf(page, "%d\n", linuxExtEnabled);
-/* could also check if quotas are enabled in kernel
-       as a whole first */
         len -= off;
         *start = page + off;
 
index ba90903..582d66c 100644 (file)
@@ -733,7 +733,7 @@ cifs_init_request_bufs(void)
                kmem_cache_destroy(cifs_req_cachep);
                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
        sufficient for path based requests).  A smaller size would have
        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) 
        alloc of large cifs buffers even when page debugging is on */
        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) {
                mempool_destroy(cifs_req_poolp);
                kmem_cache_destroy(cifs_req_cachep);
index c011c27..862e403 100644 (file)
@@ -285,6 +285,7 @@ struct cifs_search_info {
        unsigned endOfSearch:1;
        unsigned emptyDir:1;
        unsigned unicode:1;
+       unsigned smallBuf:1; /* so we know which buf_release function to call */
 };
 
 struct cifsFileInfo {
@@ -420,7 +421,12 @@ struct dir_notify_req {
 #define   MID_RESPONSE_RECEIVED 4
 #define   MID_RETRY_NEEDED      8 /* session closed while this request out */
 #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 */
 
 /*
  *****************************************************************
index 5253e77..3c09fb9 100644 (file)
 #define NT_TRANSACT_GET_USER_QUOTA    0x07
 #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 */
 /*****************************************************************
index c058f8a..8ef0ce4 100644 (file)
@@ -49,7 +49,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
                        int * /* bytes returned */ , const int long_op);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
                        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 checkSMB(struct smb_hdr *smb, __u16 mid, int length);
 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 *);
 
 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,
-            __u16 searchHandle, struct cifs_search_info * psrch_inf);
+               __u16 searchHandle, struct cifs_search_info * psrch_inf);
 
 extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
                        const __u16 search_handle);
@@ -230,8 +231,9 @@ extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
                        const int smb_file_id);
 
 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,
                        const int netfid, const unsigned int count,
                        const __u64 lseek, unsigned int *nbytes,
index 3565d3b..1620991 100644 (file)
@@ -958,21 +958,19 @@ openRetry:
        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
 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;
        READ_REQ *pSMB = NULL;
        READ_RSP *pSMBr = NULL;
        char *pReadData = NULL;
-       int bytes_returned;
        int wct;
+       int resp_buf_type = 0;
+       struct kvec iov[1];
 
        cFYI(1,("Reading %d bytes on fid %d",count,netfid));
        if(tcon->ses->capabilities & CAP_LARGE_FILES)
@@ -981,8 +979,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
                wct = 10; /* old style read */
 
        *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)
                return rc;
 
@@ -990,13 +987,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
        if (tcon->ses->server == NULL)
                return -ECONNABORTED;
 
-       pSMB->AndXCommand = 0xFF;       /* none */
+       pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
        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;
+       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);
@@ -1005,14 +1002,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
                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 * pSMBW =
                        (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);
+       pSMBr = (READ_RSP *)iov[0].iov_base;
        if (rc) {
                cERROR(1, ("Send error in read = %d", rc));
        } else {
@@ -1022,33 +1023,43 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
                *nbytes = data_length;
 
                /*check that DataLength would not go beyond end of SMB */
-               if ((data_length > CIFSMaxBufSize) 
+               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) +
+                       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(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);
+                               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 */
        return rc;
 }
 
+
 int
 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
             const int netfid, const unsigned int count,
@@ -1163,10 +1174,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 {
        int rc = -EACCES;
        WRITE_REQ *pSMB = NULL;
-       int bytes_returned, wct;
+       int wct;
        int smb_hdr_len;
+       int resp_buf_type = 0;
 
-       /* BB removeme BB */
        cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
 
        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);
        }
        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);
        cifs_stats_inc(&tcon->num_writes);
        if (rc) {
                cFYI(1, ("Send error Write2 = %d", rc));
                *nbytes = 0;
+       } else if(resp_buf_type == 0) {
+               /* presumably this can not happen, but best to be safe */
+               rc = -EIO;
+               *nbytes = 0;
        } else {
-               WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
+               WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
                *nbytes = le16_to_cpu(pSMBr->CountHigh);
                *nbytes = (*nbytes) << 16;
                *nbytes += le16_to_cpu(pSMBr->Count);
        } 
 
        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 
                since file handle passed in no longer valid */
index 651f3b6..45c9d72 100644 (file)
@@ -514,7 +514,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                /* else length ok */
                reconnect = 0;
 
-               if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
+               if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
                        isLargeBuf = TRUE;
                        memcpy(bigbuf, smallbuf, 4);
                        smb_buffer = bigbuf;
index b67be3d..c249b62 100644 (file)
@@ -555,13 +555,13 @@ int cifs_closedir(struct inode *inode, struct file *file)
                }
                ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
                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;
                        cifs_buf_release(ptmp);
                }
                ptmp = pCFileStruct->search_resume_name;
                if (ptmp) {
-   /* BB removeme BB */        cFYI(1, ("freeing resume name in closedir"));
+                       cFYI(1, ("closedir free resume name"));
                        pCFileStruct->search_resume_name = NULL;
                        kfree(ptmp);
                }
@@ -871,8 +871,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
                                        break;
                        }
                        /* 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];
                                unsigned int len;
 
@@ -1424,6 +1424,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
                rc = -EAGAIN;
                smb_read_data = NULL;
                while (rc == -EAGAIN) {
+                       int buf_type = CIFS_NO_BUFFER;
                        if ((open_file->invalidHandle) && 
                            (!open_file->closePend)) {
                                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;
                        }
                        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;
                        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);
+                               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;
                        }
                }
@@ -1478,6 +1481,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 buf_type = CIFS_NO_BUFFER;
 
        xid = GetXid();
        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;
                        }
                        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 (total_read) {
@@ -1614,6 +1619,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 buf_type = CIFS_NO_BUFFER;
 
        xid = GetXid();
        if (file->private_data == NULL) {
@@ -1670,14 +1676,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        }
 
                        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 ? */
                        if (rc== -EAGAIN) {
                                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;
                                }
                        }
@@ -1734,7 +1743,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        break;
                }
                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;
                }
                bytes_read = 0;
index d1e9957..f65310c 100644 (file)
@@ -229,11 +229,12 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
                         cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc==0) {
+               int buf_type = CIFS_NO_BUFFER;
                        /* Read header */
                rc = CIFSSMBRead(xid, pTcon,
                                 netfid,
                                 24 /* length */, 0 /* offset */,
-                                &bytes_read, &pbuf);
+                                &bytes_read, &pbuf, &buf_type);
                if((rc == 0) && (bytes_read >= 8)) {
                        if(memcmp("IntxBLK", pbuf, 8) == 0) {
                                cFYI(1,("Block device"));
@@ -267,7 +268,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
                } else {
                        inode->i_mode |= S_IFREG; /* then it is a file */
                        rc = -EOPNOTSUPP; /* or some unknown SFU type */        
-               }
+               }               
                CIFSSMBClose(xid, pTcon, netfid);
        }
        return rc;
index ac5a72a..812c6bb 100644 (file)
@@ -299,7 +299,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
        struct cifsSesInfo * ses;
        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 =
            (2 * word_count) + sizeof (struct smb_hdr) -
index 0abfbf4..c96a148 100644 (file)
@@ -298,7 +298,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
 
 int
 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)
 {
        int rc = 0;
@@ -306,6 +306,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
        unsigned long timeout;
        struct mid_q_entry *midQ;
        struct smb_hdr *in_buf = iov[0].iov_base;
+       
+       *pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
 
        if (ses == NULL) {
                cERROR(1,("Null smb session"));
@@ -491,23 +493,20 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
                if (midQ->resp_buf && 
                        (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 */
                        if((receive_len > 24) &&
                           (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
                                        SECMODE_SIGN_ENABLED))) {
-                               rc = cifs_verify_signature(in_buf,
+                               rc = cifs_verify_signature(midQ->resp_buf,
                                                ses->server->mac_signing_key,
                                                midQ->sequence_number+1);
                                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 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 */
                        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_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 {
                        rc = -EIO;
                        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));
                } else {
                        rc = -EIO;
-                       cERROR(1,("Bad MID state? "));
+                       cERROR(1,("Bad MID state?"));
                }
        }
 cifs_no_response_exit: