aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2005-12-12 20:53:18 -0800
committerSteve French <sfrench@us.ibm.com>2005-12-12 20:53:18 -0800
commitec637e3ffb6b978143652477c7c5f96c9519b691 (patch)
tree32533b8f101e1d85b3499050eef29e78480e5cae
parentc89a86bb96307019867d11874ef0b86adaa0598e (diff)
[CIFS] Avoid extra large buffer allocation (and memcpy) in cifs_readpages
Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/cifs_debug.c39
-rw-r--r--fs/cifs/cifsfs.c5
-rw-r--r--fs/cifs/cifsglob.h8
-rw-r--r--fs/cifs/cifspdu.h6
-rw-r--r--fs/cifs/cifsproto.h14
-rw-r--r--fs/cifs/cifssmb.c93
-rw-r--r--fs/cifs/connect.c2
-rw-r--r--fs/cifs/file.c52
-rw-r--r--fs/cifs/inode.c5
-rw-r--r--fs/cifs/misc.c2
-rw-r--r--fs/cifs/transport.c38
11 files changed, 156 insertions, 108 deletions
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 6f5d81f5eac..f4124a32bef 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -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;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index ba90903909a..582d66ca6da 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -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);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c011c278af4..862e403ff21 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -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 */
/*
*****************************************************************
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 5253e779b3a..3c09fb9cc56 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -80,7 +80,11 @@
#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 */
/*****************************************************************
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c058f8a45b2..8ef0ce47f5b 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -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,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 3565d3bf2e3..1620991cd4d 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -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 */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 651f3b6cebe..45c9d726c00 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -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;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index b67be3d8c01..c249b628fd1 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -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;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index d1e99575743..f65310cc60a 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -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;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index ac5a72a299a..812c6bb0fe3 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -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) -
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 0abfbf4e4a4..c96a148c39b 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -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: