diff options
author | Steve French <sfrench@us.ibm.com> | 2005-12-12 23:53:18 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2005-12-12 23:53:18 -0500 |
commit | ec637e3ffb6b978143652477c7c5f96c9519b691 (patch) | |
tree | 32533b8f101e1d85b3499050eef29e78480e5cae /fs | |
parent | c89a86bb96307019867d11874ef0b86adaa0598e (diff) |
[CIFS] Avoid extra large buffer allocation (and memcpy) in cifs_readpages
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifs_debug.c | 39 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 5 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 8 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 6 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 14 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 93 | ||||
-rw-r--r-- | fs/cifs/connect.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 52 | ||||
-rw-r--r-- | fs/cifs/inode.c | 5 | ||||
-rw-r--r-- | fs/cifs/misc.c | 2 | ||||
-rw-r--r-- | fs/cifs/transport.c | 38 |
11 files changed, 156 insertions, 108 deletions
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 6f5d81f5eacb..f4124a32bef8 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -401,8 +401,8 @@ static read_proc_t ntlmv2_enabled_read; | |||
401 | static write_proc_t ntlmv2_enabled_write; | 401 | static write_proc_t ntlmv2_enabled_write; |
402 | static read_proc_t packet_signing_enabled_read; | 402 | static read_proc_t packet_signing_enabled_read; |
403 | static write_proc_t packet_signing_enabled_write; | 403 | static write_proc_t packet_signing_enabled_write; |
404 | static read_proc_t quotaEnabled_read; | 404 | static read_proc_t experimEnabled_read; |
405 | static write_proc_t quotaEnabled_write; | 405 | static write_proc_t experimEnabled_write; |
406 | static read_proc_t linuxExtensionsEnabled_read; | 406 | static read_proc_t linuxExtensionsEnabled_read; |
407 | static write_proc_t linuxExtensionsEnabled_write; | 407 | static write_proc_t linuxExtensionsEnabled_write; |
408 | 408 | ||
@@ -442,9 +442,9 @@ cifs_proc_init(void) | |||
442 | pde->write_proc = oplockEnabled_write; | 442 | pde->write_proc = oplockEnabled_write; |
443 | 443 | ||
444 | pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, | 444 | pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, |
445 | quotaEnabled_read, NULL); | 445 | experimEnabled_read, NULL); |
446 | if (pde) | 446 | if (pde) |
447 | pde->write_proc = quotaEnabled_write; | 447 | pde->write_proc = experimEnabled_write; |
448 | 448 | ||
449 | pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, | 449 | pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, |
450 | linuxExtensionsEnabled_read, NULL); | 450 | linuxExtensionsEnabled_read, NULL); |
@@ -586,14 +586,13 @@ oplockEnabled_write(struct file *file, const char __user *buffer, | |||
586 | } | 586 | } |
587 | 587 | ||
588 | static int | 588 | static int |
589 | quotaEnabled_read(char *page, char **start, off_t off, | 589 | experimEnabled_read(char *page, char **start, off_t off, |
590 | int count, int *eof, void *data) | 590 | int count, int *eof, void *data) |
591 | { | 591 | { |
592 | int len; | 592 | int len; |
593 | 593 | ||
594 | len = sprintf(page, "%d\n", experimEnabled); | 594 | len = sprintf(page, "%d\n", experimEnabled); |
595 | /* could also check if quotas are enabled in kernel | 595 | |
596 | as a whole first */ | ||
597 | len -= off; | 596 | len -= off; |
598 | *start = page + off; | 597 | *start = page + off; |
599 | 598 | ||
@@ -608,21 +607,23 @@ quotaEnabled_read(char *page, char **start, off_t off, | |||
608 | return len; | 607 | return len; |
609 | } | 608 | } |
610 | static int | 609 | static int |
611 | quotaEnabled_write(struct file *file, const char __user *buffer, | 610 | experimEnabled_write(struct file *file, const char __user *buffer, |
612 | unsigned long count, void *data) | 611 | unsigned long count, void *data) |
613 | { | 612 | { |
614 | char c; | 613 | char c; |
615 | int rc; | 614 | int rc; |
616 | 615 | ||
617 | rc = get_user(c, buffer); | 616 | rc = get_user(c, buffer); |
618 | if (rc) | 617 | if (rc) |
619 | return rc; | 618 | return rc; |
620 | if (c == '0' || c == 'n' || c == 'N') | 619 | if (c == '0' || c == 'n' || c == 'N') |
621 | experimEnabled = 0; | 620 | experimEnabled = 0; |
622 | else if (c == '1' || c == 'y' || c == 'Y') | 621 | else if (c == '1' || c == 'y' || c == 'Y') |
623 | experimEnabled = 1; | 622 | experimEnabled = 1; |
623 | else if (c == '2') | ||
624 | experimEnabled = 2; | ||
624 | 625 | ||
625 | return count; | 626 | return count; |
626 | } | 627 | } |
627 | 628 | ||
628 | static int | 629 | static int |
@@ -632,8 +633,6 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off, | |||
632 | int len; | 633 | int len; |
633 | 634 | ||
634 | len = sprintf(page, "%d\n", linuxExtEnabled); | 635 | len = sprintf(page, "%d\n", linuxExtEnabled); |
635 | /* could also check if quotas are enabled in kernel | ||
636 | as a whole first */ | ||
637 | len -= off; | 636 | len -= off; |
638 | *start = page + off; | 637 | *start = page + off; |
639 | 638 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ba90903909a6..582d66ca6da5 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -733,7 +733,7 @@ cifs_init_request_bufs(void) | |||
733 | kmem_cache_destroy(cifs_req_cachep); | 733 | kmem_cache_destroy(cifs_req_cachep); |
734 | return -ENOMEM; | 734 | return -ENOMEM; |
735 | } | 735 | } |
736 | /* 256 (MAX_CIFS_HDR_SIZE bytes is enough for most SMB responses and | 736 | /* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and |
737 | almost all handle based requests (but not write response, nor is it | 737 | almost all handle based requests (but not write response, nor is it |
738 | sufficient for path based requests). A smaller size would have | 738 | sufficient for path based requests). A smaller size would have |
739 | been more efficient (compacting multiple slab items on one 4k page) | 739 | been more efficient (compacting multiple slab items on one 4k page) |
@@ -742,7 +742,8 @@ cifs_init_request_bufs(void) | |||
742 | efficient to alloc 1 per page off the slab compared to 17K (5page) | 742 | efficient to alloc 1 per page off the slab compared to 17K (5page) |
743 | alloc of large cifs buffers even when page debugging is on */ | 743 | alloc of large cifs buffers even when page debugging is on */ |
744 | cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", | 744 | cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", |
745 | MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); | 745 | MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN, |
746 | NULL, NULL); | ||
746 | if (cifs_sm_req_cachep == NULL) { | 747 | if (cifs_sm_req_cachep == NULL) { |
747 | mempool_destroy(cifs_req_poolp); | 748 | mempool_destroy(cifs_req_poolp); |
748 | kmem_cache_destroy(cifs_req_cachep); | 749 | kmem_cache_destroy(cifs_req_cachep); |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c011c278af4c..862e403ff211 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -285,6 +285,7 @@ struct cifs_search_info { | |||
285 | unsigned endOfSearch:1; | 285 | unsigned endOfSearch:1; |
286 | unsigned emptyDir:1; | 286 | unsigned emptyDir:1; |
287 | unsigned unicode:1; | 287 | unsigned unicode:1; |
288 | unsigned smallBuf:1; /* so we know which buf_release function to call */ | ||
288 | }; | 289 | }; |
289 | 290 | ||
290 | struct cifsFileInfo { | 291 | struct cifsFileInfo { |
@@ -420,7 +421,12 @@ struct dir_notify_req { | |||
420 | #define MID_RESPONSE_RECEIVED 4 | 421 | #define MID_RESPONSE_RECEIVED 4 |
421 | #define MID_RETRY_NEEDED 8 /* session closed while this request out */ | 422 | #define MID_RETRY_NEEDED 8 /* session closed while this request out */ |
422 | #define MID_NO_RESP_NEEDED 0x10 | 423 | #define MID_NO_RESP_NEEDED 0x10 |
423 | #define MID_SMALL_BUFFER 0x20 /* 112 byte response buffer instead of 4K */ | 424 | |
425 | /* Types of response buffer returned from SendReceive2 */ | ||
426 | #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ | ||
427 | #define CIFS_SMALL_BUFFER 1 | ||
428 | #define CIFS_LARGE_BUFFER 2 | ||
429 | #define CIFS_IOVEC 4 /* array of response buffers */ | ||
424 | 430 | ||
425 | /* | 431 | /* |
426 | ***************************************************************** | 432 | ***************************************************************** |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 5253e779b3aa..3c09fb9cc569 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -80,7 +80,11 @@ | |||
80 | #define NT_TRANSACT_GET_USER_QUOTA 0x07 | 80 | #define NT_TRANSACT_GET_USER_QUOTA 0x07 |
81 | #define NT_TRANSACT_SET_USER_QUOTA 0x08 | 81 | #define NT_TRANSACT_SET_USER_QUOTA 0x08 |
82 | 82 | ||
83 | #define MAX_CIFS_HDR_SIZE 256 /* is future chained NTCreateXReadX bigger? */ | 83 | #define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */ |
84 | /* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */ | ||
85 | /* among the requests (NTCreateX response is bigger with wct of 34) */ | ||
86 | #define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */ | ||
87 | #define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */ | ||
84 | 88 | ||
85 | /* internal cifs vfs structures */ | 89 | /* internal cifs vfs structures */ |
86 | /***************************************************************** | 90 | /***************************************************************** |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index c058f8a45b2b..8ef0ce47f5b6 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -49,7 +49,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | |||
49 | int * /* bytes returned */ , const int long_op); | 49 | int * /* bytes returned */ , const int long_op); |
50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, | 50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, |
51 | struct kvec *, int /* nvec to send */, | 51 | struct kvec *, int /* nvec to send */, |
52 | int * /* bytes returned */ , const int long_op); | 52 | int * /* type of buf returned */ , const int long_op); |
53 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); | 53 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); |
54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); | 54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); |
55 | extern int is_valid_oplock_break(struct smb_hdr *smb); | 55 | extern int is_valid_oplock_break(struct smb_hdr *smb); |
@@ -93,11 +93,12 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
93 | const struct nls_table *); | 93 | const struct nls_table *); |
94 | 94 | ||
95 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | 95 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, |
96 | const char *searchName, const struct nls_table *nls_codepage, | 96 | const char *searchName, const struct nls_table *nls_codepage, |
97 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep); | 97 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, |
98 | int map, const char dirsep); | ||
98 | 99 | ||
99 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | 100 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, |
100 | __u16 searchHandle, struct cifs_search_info * psrch_inf); | 101 | __u16 searchHandle, struct cifs_search_info * psrch_inf); |
101 | 102 | ||
102 | extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, | 103 | extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, |
103 | const __u16 search_handle); | 104 | const __u16 search_handle); |
@@ -230,8 +231,9 @@ extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, | |||
230 | const int smb_file_id); | 231 | const int smb_file_id); |
231 | 232 | ||
232 | extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | 233 | extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, |
233 | const int netfid, unsigned int count, | 234 | const int netfid, unsigned int count, |
234 | const __u64 lseek, unsigned int *nbytes, char **buf); | 235 | const __u64 lseek, unsigned int *nbytes, char **buf, |
236 | int * return_buf_type); | ||
235 | extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | 237 | extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, |
236 | const int netfid, const unsigned int count, | 238 | const int netfid, const unsigned int count, |
237 | const __u64 lseek, unsigned int *nbytes, | 239 | const __u64 lseek, unsigned int *nbytes, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 3565d3bf2e32..1620991cd4d2 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -958,21 +958,19 @@ openRetry: | |||
958 | return rc; | 958 | return rc; |
959 | } | 959 | } |
960 | 960 | ||
961 | /* If no buffer passed in, then caller wants to do the copy | ||
962 | as in the case of readpages so the SMB buffer must be | ||
963 | freed by the caller */ | ||
964 | |||
965 | int | 961 | int |
966 | CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | 962 | CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, |
967 | const int netfid, const unsigned int count, | 963 | const int netfid, const unsigned int count, |
968 | const __u64 lseek, unsigned int *nbytes, char **buf) | 964 | const __u64 lseek, unsigned int *nbytes, char **buf, |
965 | int * pbuf_type) | ||
969 | { | 966 | { |
970 | int rc = -EACCES; | 967 | int rc = -EACCES; |
971 | READ_REQ *pSMB = NULL; | 968 | READ_REQ *pSMB = NULL; |
972 | READ_RSP *pSMBr = NULL; | 969 | READ_RSP *pSMBr = NULL; |
973 | char *pReadData = NULL; | 970 | char *pReadData = NULL; |
974 | int bytes_returned; | ||
975 | int wct; | 971 | int wct; |
972 | int resp_buf_type = 0; | ||
973 | struct kvec iov[1]; | ||
976 | 974 | ||
977 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); | 975 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); |
978 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | 976 | if(tcon->ses->capabilities & CAP_LARGE_FILES) |
@@ -981,8 +979,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
981 | wct = 10; /* old style read */ | 979 | wct = 10; /* old style read */ |
982 | 980 | ||
983 | *nbytes = 0; | 981 | *nbytes = 0; |
984 | rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB, | 982 | rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB); |
985 | (void **) &pSMBr); | ||
986 | if (rc) | 983 | if (rc) |
987 | return rc; | 984 | return rc; |
988 | 985 | ||
@@ -990,13 +987,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
990 | if (tcon->ses->server == NULL) | 987 | if (tcon->ses->server == NULL) |
991 | return -ECONNABORTED; | 988 | return -ECONNABORTED; |
992 | 989 | ||
993 | pSMB->AndXCommand = 0xFF; /* none */ | 990 | pSMB->AndXCommand = 0xFF; /* none */ |
994 | pSMB->Fid = netfid; | 991 | pSMB->Fid = netfid; |
995 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); | 992 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); |
996 | if(wct == 12) | 993 | if(wct == 12) |
997 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | 994 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); |
998 | else if((lseek >> 32) > 0) /* can not handle this big offset for old */ | 995 | else if((lseek >> 32) > 0) /* can not handle this big offset for old */ |
999 | return -EIO; | 996 | return -EIO; |
1000 | 997 | ||
1001 | pSMB->Remaining = 0; | 998 | pSMB->Remaining = 0; |
1002 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); | 999 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); |
@@ -1005,14 +1002,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
1005 | pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ | 1002 | pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ |
1006 | else { | 1003 | else { |
1007 | /* old style read */ | 1004 | /* old style read */ |
1008 | struct smb_com_readx_req * pSMBW = | 1005 | struct smb_com_readx_req * pSMBW = |
1009 | (struct smb_com_readx_req *)pSMB; | 1006 | (struct smb_com_readx_req *)pSMB; |
1010 | pSMBW->ByteCount = 0; | 1007 | pSMBW->ByteCount = 0; |
1011 | } | 1008 | } |
1012 | 1009 | ||
1013 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1010 | iov[0].iov_base = (char *)pSMB; |
1014 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1011 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
1012 | rc = SendReceive2(xid, tcon->ses, iov, | ||
1013 | 1 /* num iovecs */, | ||
1014 | &resp_buf_type, 0); | ||
1015 | cifs_stats_inc(&tcon->num_reads); | 1015 | cifs_stats_inc(&tcon->num_reads); |
1016 | pSMBr = (READ_RSP *)iov[0].iov_base; | ||
1016 | if (rc) { | 1017 | if (rc) { |
1017 | cERROR(1, ("Send error in read = %d", rc)); | 1018 | cERROR(1, ("Send error in read = %d", rc)); |
1018 | } else { | 1019 | } else { |
@@ -1022,33 +1023,43 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
1022 | *nbytes = data_length; | 1023 | *nbytes = data_length; |
1023 | 1024 | ||
1024 | /*check that DataLength would not go beyond end of SMB */ | 1025 | /*check that DataLength would not go beyond end of SMB */ |
1025 | if ((data_length > CIFSMaxBufSize) | 1026 | if ((data_length > CIFSMaxBufSize) |
1026 | || (data_length > count)) { | 1027 | || (data_length > count)) { |
1027 | cFYI(1,("bad length %d for count %d",data_length,count)); | 1028 | cFYI(1,("bad length %d for count %d",data_length,count)); |
1028 | rc = -EIO; | 1029 | rc = -EIO; |
1029 | *nbytes = 0; | 1030 | *nbytes = 0; |
1030 | } else { | 1031 | } else { |
1031 | pReadData = | 1032 | pReadData = (char *) (&pSMBr->hdr.Protocol) + |
1032 | (char *) (&pSMBr->hdr.Protocol) + | ||
1033 | le16_to_cpu(pSMBr->DataOffset); | 1033 | le16_to_cpu(pSMBr->DataOffset); |
1034 | /* if(rc = copy_to_user(buf, pReadData, data_length)) { | 1034 | /* if(rc = copy_to_user(buf, pReadData, data_length)) { |
1035 | cERROR(1,("Faulting on read rc = %d",rc)); | 1035 | cERROR(1,("Faulting on read rc = %d",rc)); |
1036 | rc = -EFAULT; | 1036 | rc = -EFAULT; |
1037 | }*/ /* can not use copy_to_user when using page cache*/ | 1037 | }*/ /* can not use copy_to_user when using page cache*/ |
1038 | if(*buf) | 1038 | if(*buf) |
1039 | memcpy(*buf,pReadData,data_length); | 1039 | memcpy(*buf,pReadData,data_length); |
1040 | } | 1040 | } |
1041 | } | 1041 | } |
1042 | if(*buf) | ||
1043 | cifs_buf_release(pSMB); | ||
1044 | else | ||
1045 | *buf = (char *)pSMB; | ||
1046 | 1042 | ||
1047 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1043 | cifs_small_buf_release(pSMB); |
1044 | if(*buf) { | ||
1045 | if(resp_buf_type == CIFS_SMALL_BUFFER) | ||
1046 | cifs_small_buf_release(iov[0].iov_base); | ||
1047 | else if(resp_buf_type == CIFS_LARGE_BUFFER) | ||
1048 | cifs_buf_release(iov[0].iov_base); | ||
1049 | } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ { | ||
1050 | *buf = iov[0].iov_base; | ||
1051 | if(resp_buf_type == CIFS_SMALL_BUFFER) | ||
1052 | *pbuf_type = CIFS_SMALL_BUFFER; | ||
1053 | else if(resp_buf_type == CIFS_LARGE_BUFFER) | ||
1054 | *pbuf_type = CIFS_LARGE_BUFFER; | ||
1055 | } | ||
1056 | |||
1057 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
1048 | since file handle passed in no longer valid */ | 1058 | since file handle passed in no longer valid */ |
1049 | return rc; | 1059 | return rc; |
1050 | } | 1060 | } |
1051 | 1061 | ||
1062 | |||
1052 | int | 1063 | int |
1053 | CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | 1064 | CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, |
1054 | const int netfid, const unsigned int count, | 1065 | const int netfid, const unsigned int count, |
@@ -1163,10 +1174,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1163 | { | 1174 | { |
1164 | int rc = -EACCES; | 1175 | int rc = -EACCES; |
1165 | WRITE_REQ *pSMB = NULL; | 1176 | WRITE_REQ *pSMB = NULL; |
1166 | int bytes_returned, wct; | 1177 | int wct; |
1167 | int smb_hdr_len; | 1178 | int smb_hdr_len; |
1179 | int resp_buf_type = 0; | ||
1168 | 1180 | ||
1169 | /* BB removeme BB */ | ||
1170 | cFYI(1,("write2 at %lld %d bytes", (long long)offset, count)); | 1181 | cFYI(1,("write2 at %lld %d bytes", (long long)offset, count)); |
1171 | 1182 | ||
1172 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | 1183 | if(tcon->ses->capabilities & CAP_LARGE_FILES) |
@@ -1209,22 +1220,34 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1209 | pSMBW->ByteCount = cpu_to_le16(count + 5); | 1220 | pSMBW->ByteCount = cpu_to_le16(count + 5); |
1210 | } | 1221 | } |
1211 | iov[0].iov_base = pSMB; | 1222 | iov[0].iov_base = pSMB; |
1212 | iov[0].iov_len = smb_hdr_len + 4; | 1223 | if(wct == 14) |
1224 | iov[0].iov_len = smb_hdr_len + 4; | ||
1225 | else /* wct == 12 pad bigger by four bytes */ | ||
1226 | iov[0].iov_len = smb_hdr_len + 8; | ||
1227 | |||
1213 | 1228 | ||
1214 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned, | 1229 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, |
1215 | long_op); | 1230 | long_op); |
1216 | cifs_stats_inc(&tcon->num_writes); | 1231 | cifs_stats_inc(&tcon->num_writes); |
1217 | if (rc) { | 1232 | if (rc) { |
1218 | cFYI(1, ("Send error Write2 = %d", rc)); | 1233 | cFYI(1, ("Send error Write2 = %d", rc)); |
1219 | *nbytes = 0; | 1234 | *nbytes = 0; |
1235 | } else if(resp_buf_type == 0) { | ||
1236 | /* presumably this can not happen, but best to be safe */ | ||
1237 | rc = -EIO; | ||
1238 | *nbytes = 0; | ||
1220 | } else { | 1239 | } else { |
1221 | WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB; | 1240 | WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base; |
1222 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | 1241 | *nbytes = le16_to_cpu(pSMBr->CountHigh); |
1223 | *nbytes = (*nbytes) << 16; | 1242 | *nbytes = (*nbytes) << 16; |
1224 | *nbytes += le16_to_cpu(pSMBr->Count); | 1243 | *nbytes += le16_to_cpu(pSMBr->Count); |
1225 | } | 1244 | } |
1226 | 1245 | ||
1227 | cifs_small_buf_release(pSMB); | 1246 | cifs_small_buf_release(pSMB); |
1247 | if(resp_buf_type == CIFS_SMALL_BUFFER) | ||
1248 | cifs_small_buf_release(iov[0].iov_base); | ||
1249 | else if(resp_buf_type == CIFS_LARGE_BUFFER) | ||
1250 | cifs_buf_release(iov[0].iov_base); | ||
1228 | 1251 | ||
1229 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1252 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
1230 | since file handle passed in no longer valid */ | 1253 | since file handle passed in no longer valid */ |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 651f3b6cebed..45c9d726c002 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -514,7 +514,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
514 | /* else length ok */ | 514 | /* else length ok */ |
515 | reconnect = 0; | 515 | reconnect = 0; |
516 | 516 | ||
517 | if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { | 517 | if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { |
518 | isLargeBuf = TRUE; | 518 | isLargeBuf = TRUE; |
519 | memcpy(bigbuf, smallbuf, 4); | 519 | memcpy(bigbuf, smallbuf, 4); |
520 | smb_buffer = bigbuf; | 520 | smb_buffer = bigbuf; |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index b67be3d8c019..c249b628fd1c 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -555,13 +555,13 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
555 | } | 555 | } |
556 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; | 556 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; |
557 | if (ptmp) { | 557 | if (ptmp) { |
558 | /* BB removeme BB */ cFYI(1, ("freeing smb buf in srch struct in closedir")); | 558 | cFYI(1, ("closedir free smb buf in srch struct")); |
559 | pCFileStruct->srch_inf.ntwrk_buf_start = NULL; | 559 | pCFileStruct->srch_inf.ntwrk_buf_start = NULL; |
560 | cifs_buf_release(ptmp); | 560 | cifs_buf_release(ptmp); |
561 | } | 561 | } |
562 | ptmp = pCFileStruct->search_resume_name; | 562 | ptmp = pCFileStruct->search_resume_name; |
563 | if (ptmp) { | 563 | if (ptmp) { |
564 | /* BB removeme BB */ cFYI(1, ("freeing resume name in closedir")); | 564 | cFYI(1, ("closedir free resume name")); |
565 | pCFileStruct->search_resume_name = NULL; | 565 | pCFileStruct->search_resume_name = NULL; |
566 | kfree(ptmp); | 566 | kfree(ptmp); |
567 | } | 567 | } |
@@ -871,8 +871,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
871 | break; | 871 | break; |
872 | } | 872 | } |
873 | /* BB FIXME We can not sign across two buffers yet */ | 873 | /* BB FIXME We can not sign across two buffers yet */ |
874 | if((experimEnabled) && ((pTcon->ses->server->secMode & | 874 | if((pTcon->ses->server->secMode & |
875 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { | 875 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) { |
876 | struct kvec iov[2]; | 876 | struct kvec iov[2]; |
877 | unsigned int len; | 877 | unsigned int len; |
878 | 878 | ||
@@ -1424,6 +1424,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1424 | rc = -EAGAIN; | 1424 | rc = -EAGAIN; |
1425 | smb_read_data = NULL; | 1425 | smb_read_data = NULL; |
1426 | while (rc == -EAGAIN) { | 1426 | while (rc == -EAGAIN) { |
1427 | int buf_type = CIFS_NO_BUFFER; | ||
1427 | if ((open_file->invalidHandle) && | 1428 | if ((open_file->invalidHandle) && |
1428 | (!open_file->closePend)) { | 1429 | (!open_file->closePend)) { |
1429 | rc = cifs_reopen_file(file->f_dentry->d_inode, | 1430 | 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, | |||
1432 | break; | 1433 | break; |
1433 | } | 1434 | } |
1434 | rc = CIFSSMBRead(xid, pTcon, | 1435 | rc = CIFSSMBRead(xid, pTcon, |
1435 | open_file->netfid, | 1436 | open_file->netfid, |
1436 | current_read_size, *poffset, | 1437 | current_read_size, *poffset, |
1437 | &bytes_read, &smb_read_data); | 1438 | &bytes_read, &smb_read_data, |
1439 | &buf_type); | ||
1438 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1440 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; |
1439 | if (copy_to_user(current_offset, | 1441 | if (copy_to_user(current_offset, |
1440 | smb_read_data + 4 /* RFC1001 hdr */ | 1442 | smb_read_data + 4 /* RFC1001 hdr */ |
1441 | + le16_to_cpu(pSMBr->DataOffset), | 1443 | + le16_to_cpu(pSMBr->DataOffset), |
1442 | bytes_read)) { | 1444 | bytes_read)) { |
1443 | rc = -EFAULT; | 1445 | rc = -EFAULT; |
1444 | FreeXid(xid); | 1446 | } |
1445 | return rc; | ||
1446 | } | ||
1447 | if (smb_read_data) { | 1447 | if (smb_read_data) { |
1448 | cifs_buf_release(smb_read_data); | 1448 | if(buf_type == CIFS_SMALL_BUFFER) |
1449 | cifs_small_buf_release(smb_read_data); | ||
1450 | else if(buf_type == CIFS_LARGE_BUFFER) | ||
1451 | cifs_buf_release(smb_read_data); | ||
1449 | smb_read_data = NULL; | 1452 | smb_read_data = NULL; |
1450 | } | 1453 | } |
1451 | } | 1454 | } |
@@ -1478,6 +1481,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1478 | int xid; | 1481 | int xid; |
1479 | char *current_offset; | 1482 | char *current_offset; |
1480 | struct cifsFileInfo *open_file; | 1483 | struct cifsFileInfo *open_file; |
1484 | int buf_type = CIFS_NO_BUFFER; | ||
1481 | 1485 | ||
1482 | xid = GetXid(); | 1486 | xid = GetXid(); |
1483 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 1487 | 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, | |||
1514 | break; | 1518 | break; |
1515 | } | 1519 | } |
1516 | rc = CIFSSMBRead(xid, pTcon, | 1520 | rc = CIFSSMBRead(xid, pTcon, |
1517 | open_file->netfid, | 1521 | open_file->netfid, |
1518 | current_read_size, *poffset, | 1522 | current_read_size, *poffset, |
1519 | &bytes_read, ¤t_offset); | 1523 | &bytes_read, ¤t_offset, |
1524 | &buf_type); | ||
1520 | } | 1525 | } |
1521 | if (rc || (bytes_read == 0)) { | 1526 | if (rc || (bytes_read == 0)) { |
1522 | if (total_read) { | 1527 | if (total_read) { |
@@ -1614,6 +1619,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1614 | struct smb_com_read_rsp *pSMBr; | 1619 | struct smb_com_read_rsp *pSMBr; |
1615 | struct pagevec lru_pvec; | 1620 | struct pagevec lru_pvec; |
1616 | struct cifsFileInfo *open_file; | 1621 | struct cifsFileInfo *open_file; |
1622 | int buf_type = CIFS_NO_BUFFER; | ||
1617 | 1623 | ||
1618 | xid = GetXid(); | 1624 | xid = GetXid(); |
1619 | if (file->private_data == NULL) { | 1625 | if (file->private_data == NULL) { |
@@ -1670,14 +1676,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1670 | } | 1676 | } |
1671 | 1677 | ||
1672 | rc = CIFSSMBRead(xid, pTcon, | 1678 | rc = CIFSSMBRead(xid, pTcon, |
1673 | open_file->netfid, | 1679 | open_file->netfid, |
1674 | read_size, offset, | 1680 | read_size, offset, |
1675 | &bytes_read, &smb_read_data); | 1681 | &bytes_read, &smb_read_data, |
1676 | 1682 | &buf_type); | |
1677 | /* BB more RC checks ? */ | 1683 | /* BB more RC checks ? */ |
1678 | if (rc== -EAGAIN) { | 1684 | if (rc== -EAGAIN) { |
1679 | if (smb_read_data) { | 1685 | if (smb_read_data) { |
1680 | cifs_buf_release(smb_read_data); | 1686 | if(buf_type == CIFS_SMALL_BUFFER) |
1687 | cifs_small_buf_release(smb_read_data); | ||
1688 | else if(buf_type == CIFS_LARGE_BUFFER) | ||
1689 | cifs_buf_release(smb_read_data); | ||
1681 | smb_read_data = NULL; | 1690 | smb_read_data = NULL; |
1682 | } | 1691 | } |
1683 | } | 1692 | } |
@@ -1734,7 +1743,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1734 | break; | 1743 | break; |
1735 | } | 1744 | } |
1736 | if (smb_read_data) { | 1745 | if (smb_read_data) { |
1737 | cifs_buf_release(smb_read_data); | 1746 | if(buf_type == CIFS_SMALL_BUFFER) |
1747 | cifs_small_buf_release(smb_read_data); | ||
1748 | else if(buf_type == CIFS_LARGE_BUFFER) | ||
1749 | cifs_buf_release(smb_read_data); | ||
1738 | smb_read_data = NULL; | 1750 | smb_read_data = NULL; |
1739 | } | 1751 | } |
1740 | bytes_read = 0; | 1752 | bytes_read = 0; |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index d1e995757436..f65310cc60a1 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, | |||
229 | cifs_sb->mnt_cifs_flags & | 229 | cifs_sb->mnt_cifs_flags & |
230 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 230 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
231 | if (rc==0) { | 231 | if (rc==0) { |
232 | int buf_type = CIFS_NO_BUFFER; | ||
232 | /* Read header */ | 233 | /* Read header */ |
233 | rc = CIFSSMBRead(xid, pTcon, | 234 | rc = CIFSSMBRead(xid, pTcon, |
234 | netfid, | 235 | netfid, |
235 | 24 /* length */, 0 /* offset */, | 236 | 24 /* length */, 0 /* offset */, |
236 | &bytes_read, &pbuf); | 237 | &bytes_read, &pbuf, &buf_type); |
237 | if((rc == 0) && (bytes_read >= 8)) { | 238 | if((rc == 0) && (bytes_read >= 8)) { |
238 | if(memcmp("IntxBLK", pbuf, 8) == 0) { | 239 | if(memcmp("IntxBLK", pbuf, 8) == 0) { |
239 | cFYI(1,("Block device")); | 240 | cFYI(1,("Block device")); |
@@ -267,7 +268,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, | |||
267 | } else { | 268 | } else { |
268 | inode->i_mode |= S_IFREG; /* then it is a file */ | 269 | inode->i_mode |= S_IFREG; /* then it is a file */ |
269 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ | 270 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ |
270 | } | 271 | } |
271 | CIFSSMBClose(xid, pTcon, netfid); | 272 | CIFSSMBClose(xid, pTcon, netfid); |
272 | } | 273 | } |
273 | return rc; | 274 | return rc; |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index ac5a72a299a3..812c6bb0fe38 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 */ , | |||
299 | struct cifsSesInfo * ses; | 299 | struct cifsSesInfo * ses; |
300 | char *temp = (char *) buffer; | 300 | char *temp = (char *) buffer; |
301 | 301 | ||
302 | memset(temp,0,MAX_CIFS_HDR_SIZE); | 302 | memset(temp,0,256); /* bigger than MAX_CIFS_HDR_SIZE */ |
303 | 303 | ||
304 | buffer->smb_buf_length = | 304 | buffer->smb_buf_length = |
305 | (2 * word_count) + sizeof (struct smb_hdr) - | 305 | (2 * word_count) + sizeof (struct smb_hdr) - |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0abfbf4e4a49..c96a148c39b2 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, | |||
298 | 298 | ||
299 | int | 299 | int |
300 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | 300 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
301 | struct kvec *iov, int n_vec, int *pbytes_returned, | 301 | struct kvec *iov, int n_vec, int * pRespBufType /* ret */, |
302 | const int long_op) | 302 | const int long_op) |
303 | { | 303 | { |
304 | int rc = 0; | 304 | int rc = 0; |
@@ -306,6 +306,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
306 | unsigned long timeout; | 306 | unsigned long timeout; |
307 | struct mid_q_entry *midQ; | 307 | struct mid_q_entry *midQ; |
308 | struct smb_hdr *in_buf = iov[0].iov_base; | 308 | struct smb_hdr *in_buf = iov[0].iov_base; |
309 | |||
310 | *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ | ||
309 | 311 | ||
310 | if (ses == NULL) { | 312 | if (ses == NULL) { |
311 | cERROR(1,("Null smb session")); | 313 | cERROR(1,("Null smb session")); |
@@ -491,23 +493,20 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
491 | if (midQ->resp_buf && | 493 | if (midQ->resp_buf && |
492 | (midQ->midState == MID_RESPONSE_RECEIVED)) { | 494 | (midQ->midState == MID_RESPONSE_RECEIVED)) { |
493 | 495 | ||
494 | in_buf->smb_buf_length = receive_len; | 496 | iov[0].iov_base = (char *)midQ->resp_buf; |
495 | if(receive_len > 500) { | 497 | if(midQ->largeBuf) |
496 | /* use multiple buffers on way out */ | 498 | *pRespBufType = CIFS_LARGE_BUFFER; |
497 | } else { | 499 | else |
498 | memcpy((char *)in_buf + 4, | 500 | *pRespBufType = CIFS_SMALL_BUFFER; |
499 | (char *)midQ->resp_buf + 4, | 501 | iov[0].iov_len = receive_len + 4; |
500 | receive_len); | 502 | iov[1].iov_len = 0; |
501 | iov[0].iov_len = receive_len + 4; | ||
502 | iov[1].iov_len = 0; | ||
503 | } | ||
504 | 503 | ||
505 | dump_smb(in_buf, 80); | 504 | dump_smb(midQ->resp_buf, 80); |
506 | /* convert the length into a more usable form */ | 505 | /* convert the length into a more usable form */ |
507 | if((receive_len > 24) && | 506 | if((receive_len > 24) && |
508 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | 507 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | |
509 | SECMODE_SIGN_ENABLED))) { | 508 | SECMODE_SIGN_ENABLED))) { |
510 | rc = cifs_verify_signature(in_buf, | 509 | rc = cifs_verify_signature(midQ->resp_buf, |
511 | ses->server->mac_signing_key, | 510 | ses->server->mac_signing_key, |
512 | midQ->sequence_number+1); | 511 | midQ->sequence_number+1); |
513 | if(rc) { | 512 | if(rc) { |
@@ -516,18 +515,19 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
516 | } | 515 | } |
517 | } | 516 | } |
518 | 517 | ||
519 | *pbytes_returned = in_buf->smb_buf_length; | ||
520 | |||
521 | /* BB special case reconnect tid and uid here? */ | 518 | /* BB special case reconnect tid and uid here? */ |
522 | /* BB special case Errbadpassword and pwdexpired here */ | 519 | /* BB special case Errbadpassword and pwdexpired here */ |
523 | rc = map_smb_to_linux_error(in_buf); | 520 | rc = map_smb_to_linux_error(midQ->resp_buf); |
524 | 521 | ||
525 | /* convert ByteCount if necessary */ | 522 | /* convert ByteCount if necessary */ |
526 | if (receive_len >= | 523 | if (receive_len >= |
527 | sizeof (struct smb_hdr) - | 524 | sizeof (struct smb_hdr) - |
528 | 4 /* do not count RFC1001 header */ + | 525 | 4 /* do not count RFC1001 header */ + |
529 | (2 * in_buf->WordCount) + 2 /* bcc */ ) | 526 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) |
530 | BCC(in_buf) = le16_to_cpu(BCC_LE(in_buf)); | 527 | BCC(midQ->resp_buf) = |
528 | le16_to_cpu(BCC_LE(midQ->resp_buf)); | ||
529 | midQ->resp_buf = NULL; /* mark it so will not be freed | ||
530 | by DeleteMidQEntry */ | ||
531 | } else { | 531 | } else { |
532 | rc = -EIO; | 532 | rc = -EIO; |
533 | cFYI(1,("Bad MID state?")); | 533 | cFYI(1,("Bad MID state?")); |
@@ -793,7 +793,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
793 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | 793 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); |
794 | } else { | 794 | } else { |
795 | rc = -EIO; | 795 | rc = -EIO; |
796 | cERROR(1,("Bad MID state? ")); | 796 | cERROR(1,("Bad MID state?")); |
797 | } | 797 | } |
798 | } | 798 | } |
799 | cifs_no_response_exit: | 799 | cifs_no_response_exit: |