aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2005-06-13 14:24:43 -0400
committerSteve French <sfrench@us.ibm.com>2005-06-13 14:24:43 -0400
commitd6e04ae64c6b06ef76a5d4fb49106b393b7fa50a (patch)
tree0ae0d4e7c94ccbba95e55d7512eb628d845eff20 /fs/cifs
parent2830077f7ae93ef2f7a312e3e489110963612e77 (diff)
[CIFS] CIFS writepage improvements - eliminate double copy
Signed-off-by: Steve French (sfrench@us.ibm.com)
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsproto.h6
-rw-r--r--fs/cifs/cifssmb.c57
-rw-r--r--fs/cifs/file.c21
-rw-r--r--fs/cifs/transport.c223
4 files changed, 231 insertions, 76 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index ea239dea571e..b43ac9230eab 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -47,6 +47,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
47 struct smb_hdr * /* input */ , 47 struct smb_hdr * /* input */ ,
48 struct smb_hdr * /* out */ , 48 struct smb_hdr * /* out */ ,
49 int * /* bytes returned */ , const int long_op); 49 int * /* bytes returned */ , const int long_op);
50extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
51 struct smb_hdr * /* input */ , int hdr_len,
52 const char * /* SMB data to send */ , int data_len,
53 int * /* bytes returned */ , const int long_op);
50extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); 54extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
51extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); 55extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
52extern int is_valid_oplock_break(struct smb_hdr *smb); 56extern int is_valid_oplock_break(struct smb_hdr *smb);
@@ -222,7 +226,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
222extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, 226extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
223 const int netfid, const unsigned int count, 227 const int netfid, const unsigned int count,
224 const __u64 offset, unsigned int *nbytes, 228 const __u64 offset, unsigned int *nbytes,
225 const char __user *buf,const int long_op); 229 const char *buf,const int long_op);
226extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, 230extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
227 const unsigned char *searchName, __u64 * inode_number, 231 const unsigned char *searchName, __u64 * inode_number,
228 const struct nls_table *nls_codepage, 232 const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 3c628bf667a5..b4f7b9859e3b 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -951,56 +951,69 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
951} 951}
952 952
953#ifdef CONFIG_CIFS_EXPERIMENTAL 953#ifdef CONFIG_CIFS_EXPERIMENTAL
954int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, 954int
955CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
955 const int netfid, const unsigned int count, 956 const int netfid, const unsigned int count,
956 const __u64 offset, unsigned int *nbytes, const char __user *buf, 957 const __u64 offset, unsigned int *nbytes, const char *buf,
957 const int long_op) 958 const int long_op)
958{ 959{
959 int rc = -EACCES; 960 int rc = -EACCES;
960 WRITE_REQ *pSMB = NULL; 961 WRITE_REQ *pSMB = NULL;
961 WRITE_RSP *pSMBr = NULL; 962 int bytes_returned;
962 /*int bytes_returned;*/ 963 int smb_hdr_len;
963 unsigned bytes_sent; 964 __u32 bytes_sent;
964 __u16 byte_count; 965 __u16 byte_count;
965 966
967 cERROR(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
966 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); 968 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
967
968 if (rc) 969 if (rc)
969 return rc; 970 return rc;
970
971 pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
972
973 /* tcon and ses pointer are checked in smb_init */ 971 /* tcon and ses pointer are checked in smb_init */
974 if (tcon->ses->server == NULL) 972 if (tcon->ses->server == NULL)
975 return -ECONNABORTED; 973 return -ECONNABORTED;
976 974
977 pSMB->AndXCommand = 0xFF; /* none */ 975 pSMB->AndXCommand = 0xFF; /* none */
978 pSMB->Fid = netfid; 976 pSMB->Fid = netfid;
979 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); 977 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
980 pSMB->OffsetHigh = cpu_to_le32(offset >> 32); 978 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
981 pSMB->Reserved = 0xFFFFFFFF; 979 pSMB->Reserved = 0xFFFFFFFF;
982 pSMB->WriteMode = 0; 980 pSMB->WriteMode = 0;
983 pSMB->Remaining = 0; 981 pSMB->Remaining = 0;
984 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF; 982
983 /* Can increase buffer size if buffer is big enough in some cases - ie
984 can send more if LARGE_WRITE_X capability returned by the server and if
985 our buffer is big enough or if we convert to iovecs on socket writes
986 and eliminate the copy to the CIFS buffer */
987 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
988 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
989 } else {
990 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
991 & ~0xFF;
992 }
993
985 if (bytes_sent > count) 994 if (bytes_sent > count)
986 bytes_sent = count; 995 bytes_sent = count;
987 pSMB->DataLengthHigh = 0;
988 pSMB->DataOffset = 996 pSMB->DataOffset =
989 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); 997 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
990 998
991 byte_count = bytes_sent + 1 /* pad */ ; 999 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
992 pSMB->DataLengthLow = cpu_to_le16(bytes_sent); 1000 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
993 pSMB->DataLengthHigh = 0; 1001 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
994 pSMB->hdr.smb_buf_length += byte_count; 1002 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1003 pSMB->hdr.smb_buf_length += bytes_sent+1;
995 pSMB->ByteCount = cpu_to_le16(byte_count); 1004 pSMB->ByteCount = cpu_to_le16(byte_count);
996 1005
997/* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, 1006 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
998 (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */ 1007 buf, bytes_sent, &bytes_returned, long_op);
999 if (rc) { 1008 if (rc) {
1000 cFYI(1, ("Send error in write2 (large write) = %d", rc)); 1009 cFYI(1, ("Send error in write = %d", rc));
1001 *nbytes = 0; 1010 *nbytes = 0;
1002 } else 1011 } else {
1003 *nbytes = le16_to_cpu(pSMBr->Count); 1012 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1013 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1014 *nbytes = (*nbytes) << 16;
1015 *nbytes += le16_to_cpu(pSMBr->Count);
1016 }
1004 1017
1005 cifs_small_buf_release(pSMB); 1018 cifs_small_buf_release(pSMB);
1006 1019
@@ -1009,6 +1022,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1009 1022
1010 return rc; 1023 return rc;
1011} 1024}
1025
1026
1012#endif /* CIFS_EXPERIMENTAL */ 1027#endif /* CIFS_EXPERIMENTAL */
1013 1028
1014int 1029int
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index dde2d251fc3d..ca74c1151be9 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -791,9 +791,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
791 791
792 pTcon = cifs_sb->tcon; 792 pTcon = cifs_sb->tcon;
793 793
794 /* cFYI(1, 794 cFYI(1,(" write %d bytes to offset %lld of %s", write_size,
795 (" write %d bytes to offset %lld of %s", write_size, 795 *poffset, file->f_dentry->d_name.name)); /* BB removeme BB */
796 *poffset, file->f_dentry->d_name.name)); */
797 796
798 if (file->private_data == NULL) 797 if (file->private_data == NULL)
799 return -EBADF; 798 return -EBADF;
@@ -846,7 +845,21 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
846 if (rc != 0) 845 if (rc != 0)
847 break; 846 break;
848 } 847 }
849 848#ifdef CIFS_EXPERIMENTAL
849 /* BB FIXME We can not sign across two buffers yet */
850 cERROR(1,("checking signing")); /* BB removeme BB */
851 if(pTcon->ses->server->secMode &
852 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED) == 0)
853 rc = CIFSSMBWrite2(xid, pTcon,
854 open_file->netfid,
855 min_t(const int, cifs_sb->wsize,
856 write_size - total_written),
857 *poffset, &bytes_written,
858 write_data + total_written,
859 long_op);
860 } else
861 /* BB FIXME fixup indentation of line below */
862#endif
850 rc = CIFSSMBWrite(xid, pTcon, 863 rc = CIFSSMBWrite(xid, pTcon,
851 open_file->netfid, 864 open_file->netfid,
852 min_t(const int, cifs_sb->wsize, 865 min_t(const int, cifs_sb->wsize,
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 0046c219833d..04f4af07fdd4 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -49,7 +49,8 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
49 return NULL; 49 return NULL;
50 } 50 }
51 51
52 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS); 52 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
53 SLAB_KERNEL | SLAB_NOFS);
53 if (temp == NULL) 54 if (temp == NULL)
54 return temp; 55 return temp;
55 else { 56 else {
@@ -179,27 +180,24 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
179 return rc; 180 return rc;
180} 181}
181 182
182#ifdef CIFS_EXPERIMENTAL 183#ifdef CONFIG_CIFS_EXPERIMENTAL
183/* BB finish off this function, adding support for writing set of pages as iovec */ 184static int
184/* and also adding support for operations that need to parse the response smb */ 185smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
185 186 unsigned int smb_hdr_length, const char * data, unsigned int datalen,
186int 187 struct sockaddr *sin)
187smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
188 unsigned int smb_buf_length, struct kvec * write_vector
189 /* page list */, struct sockaddr *sin)
190{ 188{
191 int rc = 0; 189 int rc = 0;
192 int i = 0; 190 int i = 0;
193 struct msghdr smb_msg; 191 struct msghdr smb_msg;
194 number_of_pages += 1; /* account for SMB header */ 192 struct kvec iov[2];
195 struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); 193 unsigned len = smb_hdr_length + 4;
196 unsigned len = smb_buf_length + 4; 194
197
198 if(ssocket == NULL) 195 if(ssocket == NULL)
199 return -ENOTSOCK; /* BB eventually add reconnect code here */ 196 return -ENOTSOCK; /* BB eventually add reconnect code here */
200 iov.iov_base = smb_buffer; 197 iov[0].iov_base = smb_buffer;
201 iov.iov_len = len; 198 iov[0].iov_len = len;
202 199 iov[1].iov_base = data;
200 iov[2].iov_len = datalen;
203 smb_msg.msg_name = sin; 201 smb_msg.msg_name = sin;
204 smb_msg.msg_namelen = sizeof (struct sockaddr); 202 smb_msg.msg_namelen = sizeof (struct sockaddr);
205 smb_msg.msg_control = NULL; 203 smb_msg.msg_control = NULL;
@@ -212,12 +210,11 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
212 Flags2 is converted in SendReceive */ 210 Flags2 is converted in SendReceive */
213 211
214 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); 212 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
215 cFYI(1, ("Sending smb of length %d ", smb_buf_length)); 213 cFYI(1, ("Sending smb of length %d ", len + datalen));
216 dump_smb(smb_buffer, len); 214 dump_smb(smb_buffer, len);
217 215
218 while (len > 0) { 216 while (len + datalen > 0) {
219 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, 217 rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len);
220 len);
221 if ((rc == -ENOSPC) || (rc == -EAGAIN)) { 218 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
222 i++; 219 i++;
223 if(i > 60) { 220 if(i > 60) {
@@ -232,9 +229,22 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
232 } 229 }
233 if (rc < 0) 230 if (rc < 0)
234 break; 231 break;
235 iov.iov_base += rc; 232 if(iov[0].iov_len > 0) {
236 iov.iov_len -= rc; 233 if(rc >= len) {
237 len -= rc; 234 iov[0].iov_len = 0;
235 rc -= len;
236 } else { /* some of hdr was not sent */
237 len -= rc;
238 iov[0].iov_len -= rc;
239 iov[0].iov_base += rc;
240 continue;
241 }
242 }
243 if((iov[0].iov_len == 0) && (rc > 0)){
244 iov[1].iov_base += rc;
245 iov[1].iov_len -= rc;
246 datalen -= rc;
247 }
238 } 248 }
239 249
240 if (rc < 0) { 250 if (rc < 0) {
@@ -246,14 +256,15 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
246 return rc; 256 return rc;
247} 257}
248 258
249
250int 259int
251CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, 260SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
252 struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op) 261 struct smb_hdr *in_buf, int hdrlen, const char * data,
262 int datalen, int *pbytes_returned, const int long_op)
253{ 263{
254 int rc = 0; 264 int rc = 0;
255 unsigned long timeout = 15 * HZ; 265 unsigned int receive_len;
256 struct mid_q_entry *midQ = NULL; 266 unsigned long timeout;
267 struct mid_q_entry *midQ;
257 268
258 if (ses == NULL) { 269 if (ses == NULL) {
259 cERROR(1,("Null smb session")); 270 cERROR(1,("Null smb session"));
@@ -263,14 +274,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
263 cERROR(1,("Null tcp session")); 274 cERROR(1,("Null tcp session"));
264 return -EIO; 275 return -EIO;
265 } 276 }
266 if(pbytes_returned == NULL)
267 return -EIO;
268 else
269 *pbytes_returned = 0;
270 277
271 278 if(ses->server->tcpStatus == CifsExiting)
272
273 if(ses->server->tcpStatus == CIFS_EXITING)
274 return -ENOENT; 279 return -ENOENT;
275 280
276 /* Ensure that we do not send more than 50 overlapping requests 281 /* Ensure that we do not send more than 50 overlapping requests
@@ -282,7 +287,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
282 } else { 287 } else {
283 spin_lock(&GlobalMid_Lock); 288 spin_lock(&GlobalMid_Lock);
284 while(1) { 289 while(1) {
285 if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ 290 if(atomic_read(&ses->server->inFlight) >=
291 cifs_max_pending){
286 spin_unlock(&GlobalMid_Lock); 292 spin_unlock(&GlobalMid_Lock);
287 wait_event(ses->server->request_q, 293 wait_event(ses->server->request_q,
288 atomic_read(&ses->server->inFlight) 294 atomic_read(&ses->server->inFlight)
@@ -314,17 +320,17 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
314 320
315 if (ses->server->tcpStatus == CifsExiting) { 321 if (ses->server->tcpStatus == CifsExiting) {
316 rc = -ENOENT; 322 rc = -ENOENT;
317 goto cifs_out_label; 323 goto out_unlock2;
318 } else if (ses->server->tcpStatus == CifsNeedReconnect) { 324 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
319 cFYI(1,("tcp session dead - return to caller to retry")); 325 cFYI(1,("tcp session dead - return to caller to retry"));
320 rc = -EAGAIN; 326 rc = -EAGAIN;
321 goto cifs_out_label; 327 goto out_unlock2;
322 } else if (ses->status != CifsGood) { 328 } else if (ses->status != CifsGood) {
323 /* check if SMB session is bad because we are setting it up */ 329 /* check if SMB session is bad because we are setting it up */
324 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 330 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
325 (in_buf->Command != SMB_COM_NEGOTIATE)) { 331 (in_buf->Command != SMB_COM_NEGOTIATE)) {
326 rc = -EAGAIN; 332 rc = -EAGAIN;
327 goto cifs_out_label; 333 goto out_unlock2;
328 } /* else ok - we are setting up session */ 334 } /* else ok - we are setting up session */
329 } 335 }
330 midQ = AllocMidQEntry(in_buf, ses); 336 midQ = AllocMidQEntry(in_buf, ses);
@@ -352,13 +358,12 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
352 return -EIO; 358 return -EIO;
353 } 359 }
354 360
355 /* BB can we sign efficiently in this path? */ 361/* BB FIXME */
356 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); 362/* rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */
357 363
358 midQ->midState = MID_REQUEST_SUBMITTED; 364 midQ->midState = MID_REQUEST_SUBMITTED;
359/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, 365 rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen,
360 piovec, 366 (struct sockaddr *) &(ses->server->addr.sockAddr));
361 (struct sockaddr *) &(ses->server->addr.sockAddr));*/
362 if(rc < 0) { 367 if(rc < 0) {
363 DeleteMidQEntry(midQ); 368 DeleteMidQEntry(midQ);
364 up(&ses->server->tcpSem); 369 up(&ses->server->tcpSem);
@@ -370,19 +375,137 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
370 return rc; 375 return rc;
371 } else 376 } else
372 up(&ses->server->tcpSem); 377 up(&ses->server->tcpSem);
373cifs_out_label: 378 if (long_op == -1)
374 if(midQ) 379 goto cifs_no_response_exit2;
375 DeleteMidQEntry(midQ); 380 else if (long_op == 2) /* writes past end of file can take loong time */
376 381 timeout = 300 * HZ;
382 else if (long_op == 1)
383 timeout = 45 * HZ; /* should be greater than
384 servers oplock break timeout (about 43 seconds) */
385 else if (long_op > 2) {
386 timeout = MAX_SCHEDULE_TIMEOUT;
387 } else
388 timeout = 15 * HZ;
389 /* wait for 15 seconds or until woken up due to response arriving or
390 due to last connection to this server being unmounted */
391 if (signal_pending(current)) {
392 /* if signal pending do not hold up user for full smb timeout
393 but we still give response a change to complete */
394 timeout = 2 * HZ;
395 }
396
397 /* No user interrupts in wait - wreaks havoc with performance */
398 if(timeout != MAX_SCHEDULE_TIMEOUT) {
399 timeout += jiffies;
400 wait_event(ses->server->response_q,
401 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
402 time_after(jiffies, timeout) ||
403 ((ses->server->tcpStatus != CifsGood) &&
404 (ses->server->tcpStatus != CifsNew)));
405 } else {
406 wait_event(ses->server->response_q,
407 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
408 ((ses->server->tcpStatus != CifsGood) &&
409 (ses->server->tcpStatus != CifsNew)));
410 }
411
412 spin_lock(&GlobalMid_Lock);
413 if (midQ->resp_buf) {
414 spin_unlock(&GlobalMid_Lock);
415 receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
416 } else {
417 cERROR(1,("No response buffer"));
418 if(midQ->midState == MID_REQUEST_SUBMITTED) {
419 if(ses->server->tcpStatus == CifsExiting)
420 rc = -EHOSTDOWN;
421 else {
422 ses->server->tcpStatus = CifsNeedReconnect;
423 midQ->midState = MID_RETRY_NEEDED;
424 }
425 }
426
427 if (rc != -EHOSTDOWN) {
428 if(midQ->midState == MID_RETRY_NEEDED) {
429 rc = -EAGAIN;
430 cFYI(1,("marking request for retry"));
431 } else {
432 rc = -EIO;
433 }
434 }
435 spin_unlock(&GlobalMid_Lock);
436 DeleteMidQEntry(midQ);
437 /* If not lock req, update # of requests on wire to server */
438 if(long_op < 3) {
439 atomic_dec(&ses->server->inFlight);
440 wake_up(&ses->server->request_q);
441 }
442 return rc;
443 }
444
445 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
446 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
447 receive_len, xid));
448 rc = -EIO;
449 } else { /* rcvd frame is ok */
450
451 if (midQ->resp_buf &&
452 (midQ->midState == MID_RESPONSE_RECEIVED)) {
453 in_buf->smb_buf_length = receive_len;
454 /* BB verify that length would not overrun small buf */
455 memcpy((char *)in_buf + 4,
456 (char *)midQ->resp_buf + 4,
457 receive_len);
458
459 dump_smb(in_buf, 80);
460 /* convert the length into a more usable form */
461 if((receive_len > 24) &&
462 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
463 SECMODE_SIGN_ENABLED))) {
464 rc = cifs_verify_signature(in_buf,
465 ses->server->mac_signing_key,
466 midQ->sequence_number+1);
467 if(rc) {
468 cERROR(1,("Unexpected SMB signature"));
469 /* BB FIXME add code to kill session */
470 }
471 }
472
473 *pbytes_returned = in_buf->smb_buf_length;
474
475 /* BB special case reconnect tid and uid here? */
476 rc = map_smb_to_linux_error(in_buf);
477
478 /* convert ByteCount if necessary */
479 if (receive_len >=
480 sizeof (struct smb_hdr) -
481 4 /* do not count RFC1001 header */ +
482 (2 * in_buf->WordCount) + 2 /* bcc */ )
483 BCC(in_buf) = le16_to_cpu(BCC(in_buf));
484 } else {
485 rc = -EIO;
486 cFYI(1,("Bad MID state? "));
487 }
488 }
489cifs_no_response_exit2:
490 DeleteMidQEntry(midQ);
491
377 if(long_op < 3) { 492 if(long_op < 3) {
378 atomic_dec(&ses->server->inFlight); 493 atomic_dec(&ses->server->inFlight);
379 wake_up(&ses->server->request_q); 494 wake_up(&ses->server->request_q);
380 } 495 }
381 496
382 return rc; 497 return rc;
383}
384 498
499out_unlock2:
500 up(&ses->server->tcpSem);
501 /* If not lock req, update # of requests on wire to server */
502 if(long_op < 3) {
503 atomic_dec(&ses->server->inFlight);
504 wake_up(&ses->server->request_q);
505 }
385 506
507 return rc;
508}
386#endif /* CIFS_EXPERIMENTAL */ 509#endif /* CIFS_EXPERIMENTAL */
387 510
388int 511int