[CIFS] Avoid extra large buffer allocation (and memcpy) in cifs_readpages
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Родитель
c89a86bb96
Коммит
ec637e3ffb
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
||||
/*
|
||||
*****************************************************************
|
||||
|
|
|
@ -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 */
|
||||
/*****************************************************************
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, ¤t_offset);
|
||||
open_file->netfid,
|
||||
current_read_size, *poffset,
|
||||
&bytes_read, ¤t_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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) -
|
||||
|
|
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче