aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/transport.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.com>2006-08-02 17:56:33 -0400
committerSteve French <sfrench@us.ibm.com>2006-08-11 17:28:47 -0400
commit7ee1af765dfa3146aef958258003245e082284e5 (patch)
tree90ab87a136d63c937064e595fd8062e5bc721e03 /fs/cifs/transport.c
parent6c3d8909d85b2c18fd7a6e64f0ca757a257b40fa (diff)
[CIFS]
Allow Windows blocking locks to be cancelled via a CANCEL_LOCK call. TODO - restrict this to servers that support NT_STATUS codes (Win9x will probably not support this call). Signed-off-by: Jeremy Allison <jra@samba.org> Signed-off-by: Steve French <sfrench@us.ibm.com> (cherry picked from 570d4d2d895569825d0d017d4e76b51138f68864 commit)
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r--fs/cifs/transport.c677
1 files changed, 404 insertions, 273 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 748b0df07a73..48d47b46b1fb 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -37,7 +37,7 @@ extern mempool_t *cifs_mid_poolp;
37extern kmem_cache_t *cifs_oplock_cachep; 37extern kmem_cache_t *cifs_oplock_cachep;
38 38
39static struct mid_q_entry * 39static struct mid_q_entry *
40AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) 40AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
41{ 41{
42 struct mid_q_entry *temp; 42 struct mid_q_entry *temp;
43 43
@@ -204,6 +204,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
204 rc = 0; 204 rc = 0;
205 } 205 }
206 206
207 /* Don't want to modify the buffer as a
208 side effect of this call. */
209 smb_buffer->smb_buf_length = smb_buf_length;
210
207 return rc; 211 return rc;
208} 212}
209 213
@@ -218,6 +222,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
218 unsigned int len = iov[0].iov_len; 222 unsigned int len = iov[0].iov_len;
219 unsigned int total_len; 223 unsigned int total_len;
220 int first_vec = 0; 224 int first_vec = 0;
225 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
221 226
222 if(ssocket == NULL) 227 if(ssocket == NULL)
223 return -ENOTSOCK; /* BB eventually add reconnect code here */ 228 return -ENOTSOCK; /* BB eventually add reconnect code here */
@@ -294,36 +299,15 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
294 } else 299 } else
295 rc = 0; 300 rc = 0;
296 301
302 /* Don't want to modify the buffer as a
303 side effect of this call. */
304 smb_buffer->smb_buf_length = smb_buf_length;
305
297 return rc; 306 return rc;
298} 307}
299 308
300int 309static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
301SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
302 struct kvec *iov, int n_vec, int * pRespBufType /* ret */,
303 const int long_op)
304{ 310{
305 int rc = 0;
306 unsigned int receive_len;
307 unsigned long timeout;
308 struct mid_q_entry *midQ;
309 struct smb_hdr *in_buf = iov[0].iov_base;
310
311 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
312
313 if ((ses == NULL) || (ses->server == NULL)) {
314 cifs_small_buf_release(in_buf);
315 cERROR(1,("Null session"));
316 return -EIO;
317 }
318
319 if(ses->server->tcpStatus == CifsExiting) {
320 cifs_small_buf_release(in_buf);
321 return -ENOENT;
322 }
323
324 /* Ensure that we do not send more than 50 overlapping requests
325 to the same server. We may make this configurable later or
326 use ses->maxReq */
327 if(long_op == -1) { 311 if(long_op == -1) {
328 /* oplock breaks must not be held up */ 312 /* oplock breaks must not be held up */
329 atomic_inc(&ses->server->inFlight); 313 atomic_inc(&ses->server->inFlight);
@@ -346,53 +330,140 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
346 } else { 330 } else {
347 if(ses->server->tcpStatus == CifsExiting) { 331 if(ses->server->tcpStatus == CifsExiting) {
348 spin_unlock(&GlobalMid_Lock); 332 spin_unlock(&GlobalMid_Lock);
349 cifs_small_buf_release(in_buf);
350 return -ENOENT; 333 return -ENOENT;
351 } 334 }
352 335
353 /* can not count locking commands against total since 336 /* can not count locking commands against total since
354 they are allowed to block on server */ 337 they are allowed to block on server */
355 338
356 if(long_op < 3) {
357 /* update # of requests on the wire to server */ 339 /* update # of requests on the wire to server */
340 if (long_op < 3)
358 atomic_inc(&ses->server->inFlight); 341 atomic_inc(&ses->server->inFlight);
359 }
360 spin_unlock(&GlobalMid_Lock); 342 spin_unlock(&GlobalMid_Lock);
361 break; 343 break;
362 } 344 }
363 } 345 }
364 } 346 }
365 /* make sure that we sign in the same order that we send on this socket 347 return 0;
366 and avoid races inside tcp sendmsg code that could cause corruption 348}
367 of smb data */
368
369 down(&ses->server->tcpSem);
370 349
350static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
351 struct mid_q_entry **ppmidQ)
352{
371 if (ses->server->tcpStatus == CifsExiting) { 353 if (ses->server->tcpStatus == CifsExiting) {
372 rc = -ENOENT; 354 return -ENOENT;
373 goto out_unlock2;
374 } else if (ses->server->tcpStatus == CifsNeedReconnect) { 355 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
375 cFYI(1,("tcp session dead - return to caller to retry")); 356 cFYI(1,("tcp session dead - return to caller to retry"));
376 rc = -EAGAIN; 357 return -EAGAIN;
377 goto out_unlock2;
378 } else if (ses->status != CifsGood) { 358 } else if (ses->status != CifsGood) {
379 /* check if SMB session is bad because we are setting it up */ 359 /* check if SMB session is bad because we are setting it up */
380 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 360 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
381 (in_buf->Command != SMB_COM_NEGOTIATE)) { 361 (in_buf->Command != SMB_COM_NEGOTIATE)) {
382 rc = -EAGAIN; 362 return -EAGAIN;
383 goto out_unlock2;
384 } /* else ok - we are setting up session */ 363 } /* else ok - we are setting up session */
385 } 364 }
386 midQ = AllocMidQEntry(in_buf, ses); 365 *ppmidQ = AllocMidQEntry(in_buf, ses);
387 if (midQ == NULL) { 366 if (*ppmidQ == NULL) {
367 return -ENOMEM;
368 }
369 return 0;
370}
371
372static int wait_for_response(struct cifsSesInfo *ses,
373 struct mid_q_entry *midQ,
374 unsigned long timeout,
375 unsigned long time_to_wait)
376{
377 unsigned long curr_timeout;
378
379 for (;;) {
380 curr_timeout = timeout + jiffies;
381 wait_event(ses->server->response_q,
382 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
383 time_after(jiffies, curr_timeout) ||
384 ((ses->server->tcpStatus != CifsGood) &&
385 (ses->server->tcpStatus != CifsNew)));
386
387 if (time_after(jiffies, curr_timeout) &&
388 (midQ->midState == MID_REQUEST_SUBMITTED) &&
389 ((ses->server->tcpStatus == CifsGood) ||
390 (ses->server->tcpStatus == CifsNew))) {
391
392 unsigned long lrt;
393
394 /* We timed out. Is the server still
395 sending replies ? */
396 spin_lock(&GlobalMid_Lock);
397 lrt = ses->server->lstrp;
398 spin_unlock(&GlobalMid_Lock);
399
400 /* Calculate time_to_wait past last receive time.
401 Although we prefer not to time out if the
402 server is still responding - we will time
403 out if the server takes more than 15 (or 45
404 or 180) seconds to respond to this request
405 and has not responded to any request from
406 other threads on the client within 10 seconds */
407 lrt += time_to_wait;
408 if (time_after(jiffies, lrt)) {
409 /* No replies for time_to_wait. */
410 cERROR(1,("server not responding"));
411 return -1;
412 }
413 } else {
414 return 0;
415 }
416 }
417}
418
419int
420SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
421 struct kvec *iov, int n_vec, int * pRespBufType /* ret */,
422 const int long_op)
423{
424 int rc = 0;
425 unsigned int receive_len;
426 unsigned long timeout;
427 struct mid_q_entry *midQ;
428 struct smb_hdr *in_buf = iov[0].iov_base;
429
430 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
431
432 if ((ses == NULL) || (ses->server == NULL)) {
433 cifs_small_buf_release(in_buf);
434 cERROR(1,("Null session"));
435 return -EIO;
436 }
437
438 if(ses->server->tcpStatus == CifsExiting) {
439 cifs_small_buf_release(in_buf);
440 return -ENOENT;
441 }
442
443 /* Ensure that we do not send more than 50 overlapping requests
444 to the same server. We may make this configurable later or
445 use ses->maxReq */
446
447 rc = wait_for_free_request(ses, long_op);
448 if (rc) {
449 cifs_small_buf_release(in_buf);
450 return rc;
451 }
452
453 /* make sure that we sign in the same order that we send on this socket
454 and avoid races inside tcp sendmsg code that could cause corruption
455 of smb data */
456
457 down(&ses->server->tcpSem);
458
459 rc = allocate_mid(ses, in_buf, &midQ);
460 if (rc) {
388 up(&ses->server->tcpSem); 461 up(&ses->server->tcpSem);
389 cifs_small_buf_release(in_buf); 462 cifs_small_buf_release(in_buf);
390 /* If not lock req, update # of requests on wire to server */ 463 /* Update # of requests on wire to server */
391 if(long_op < 3) { 464 atomic_dec(&ses->server->inFlight);
392 atomic_dec(&ses->server->inFlight); 465 wake_up(&ses->server->request_q);
393 wake_up(&ses->server->request_q); 466 return rc;
394 }
395 return -ENOMEM;
396 } 467 }
397 468
398 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); 469 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
@@ -407,32 +478,23 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
407 atomic_dec(&ses->server->inSend); 478 atomic_dec(&ses->server->inSend);
408 midQ->when_sent = jiffies; 479 midQ->when_sent = jiffies;
409#endif 480#endif
410 if(rc < 0) { 481
411 DeleteMidQEntry(midQ); 482 up(&ses->server->tcpSem);
412 up(&ses->server->tcpSem); 483 cifs_small_buf_release(in_buf);
413 cifs_small_buf_release(in_buf); 484
414 /* If not lock req, update # of requests on wire to server */ 485 if(rc < 0)
415 if(long_op < 3) { 486 goto out;
416 atomic_dec(&ses->server->inFlight);
417 wake_up(&ses->server->request_q);
418 }
419 return rc;
420 } else {
421 up(&ses->server->tcpSem);
422 cifs_small_buf_release(in_buf);
423 }
424 487
425 if (long_op == -1) 488 if (long_op == -1)
426 goto cifs_no_response_exit2; 489 goto out;
427 else if (long_op == 2) /* writes past end of file can take loong time */ 490 else if (long_op == 2) /* writes past end of file can take loong time */
428 timeout = 180 * HZ; 491 timeout = 180 * HZ;
429 else if (long_op == 1) 492 else if (long_op == 1)
430 timeout = 45 * HZ; /* should be greater than 493 timeout = 45 * HZ; /* should be greater than
431 servers oplock break timeout (about 43 seconds) */ 494 servers oplock break timeout (about 43 seconds) */
432 else if (long_op > 2) { 495 else
433 timeout = MAX_SCHEDULE_TIMEOUT;
434 } else
435 timeout = 15 * HZ; 496 timeout = 15 * HZ;
497
436 /* wait for 15 seconds or until woken up due to response arriving or 498 /* wait for 15 seconds or until woken up due to response arriving or
437 due to last connection to this server being unmounted */ 499 due to last connection to this server being unmounted */
438 if (signal_pending(current)) { 500 if (signal_pending(current)) {
@@ -442,53 +504,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
442 } 504 }
443 505
444 /* No user interrupts in wait - wreaks havoc with performance */ 506 /* No user interrupts in wait - wreaks havoc with performance */
445 if(timeout != MAX_SCHEDULE_TIMEOUT) { 507 wait_for_response(ses, midQ, timeout, 10 * HZ);
446 unsigned long curr_timeout;
447
448 for (;;) {
449 curr_timeout = timeout + jiffies;
450 wait_event(ses->server->response_q,
451 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
452 time_after(jiffies, curr_timeout) ||
453 ((ses->server->tcpStatus != CifsGood) &&
454 (ses->server->tcpStatus != CifsNew)));
455
456 if (time_after(jiffies, curr_timeout) &&
457 (midQ->midState == MID_REQUEST_SUBMITTED) &&
458 ((ses->server->tcpStatus == CifsGood) ||
459 (ses->server->tcpStatus == CifsNew))) {
460
461 unsigned long lrt;
462
463 /* We timed out. Is the server still
464 sending replies ? */
465 spin_lock(&GlobalMid_Lock);
466 lrt = ses->server->lstrp;
467 spin_unlock(&GlobalMid_Lock);
468
469 /* Calculate 10 seconds past last receive time.
470 Although we prefer not to time out if the
471 server is still responding - we will time
472 out if the server takes more than 15 (or 45
473 or 180) seconds to respond to this request
474 and has not responded to any request from
475 other threads on the client within 10 seconds */
476 lrt += (10 * HZ);
477 if (time_after(jiffies, lrt)) {
478 /* No replies for 10 seconds. */
479 cERROR(1,("server not responding"));
480 break;
481 }
482 } else {
483 break;
484 }
485 }
486 } else {
487 wait_event(ses->server->response_q,
488 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
489 ((ses->server->tcpStatus != CifsGood) &&
490 (ses->server->tcpStatus != CifsNew)));
491 }
492 508
493 spin_lock(&GlobalMid_Lock); 509 spin_lock(&GlobalMid_Lock);
494 if (midQ->resp_buf) { 510 if (midQ->resp_buf) {
@@ -516,11 +532,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
516 } 532 }
517 spin_unlock(&GlobalMid_Lock); 533 spin_unlock(&GlobalMid_Lock);
518 DeleteMidQEntry(midQ); 534 DeleteMidQEntry(midQ);
519 /* If not lock req, update # of requests on wire to server */ 535 /* Update # of requests on wire to server */
520 if(long_op < 3) { 536 atomic_dec(&ses->server->inFlight);
521 atomic_dec(&ses->server->inFlight); 537 wake_up(&ses->server->request_q);
522 wake_up(&ses->server->request_q);
523 }
524 return rc; 538 return rc;
525 } 539 }
526 540
@@ -571,24 +585,12 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
571 cFYI(1,("Bad MID state?")); 585 cFYI(1,("Bad MID state?"));
572 } 586 }
573 } 587 }
574cifs_no_response_exit2:
575 DeleteMidQEntry(midQ);
576
577 if(long_op < 3) {
578 atomic_dec(&ses->server->inFlight);
579 wake_up(&ses->server->request_q);
580 }
581 588
582 return rc; 589out:
583 590
584out_unlock2: 591 DeleteMidQEntry(midQ);
585 up(&ses->server->tcpSem); 592 atomic_dec(&ses->server->inFlight);
586 cifs_small_buf_release(in_buf); 593 wake_up(&ses->server->request_q);
587 /* If not lock req, update # of requests on wire to server */
588 if(long_op < 3) {
589 atomic_dec(&ses->server->inFlight);
590 wake_up(&ses->server->request_q);
591 }
592 594
593 return rc; 595 return rc;
594} 596}
@@ -618,85 +620,34 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
618 /* Ensure that we do not send more than 50 overlapping requests 620 /* Ensure that we do not send more than 50 overlapping requests
619 to the same server. We may make this configurable later or 621 to the same server. We may make this configurable later or
620 use ses->maxReq */ 622 use ses->maxReq */
621 if(long_op == -1) {
622 /* oplock breaks must not be held up */
623 atomic_inc(&ses->server->inFlight);
624 } else {
625 spin_lock(&GlobalMid_Lock);
626 while(1) {
627 if(atomic_read(&ses->server->inFlight) >=
628 cifs_max_pending){
629 spin_unlock(&GlobalMid_Lock);
630#ifdef CONFIG_CIFS_STATS2
631 atomic_inc(&ses->server->num_waiters);
632#endif
633 wait_event(ses->server->request_q,
634 atomic_read(&ses->server->inFlight)
635 < cifs_max_pending);
636#ifdef CONFIG_CIFS_STATS2
637 atomic_dec(&ses->server->num_waiters);
638#endif
639 spin_lock(&GlobalMid_Lock);
640 } else {
641 if(ses->server->tcpStatus == CifsExiting) {
642 spin_unlock(&GlobalMid_Lock);
643 return -ENOENT;
644 }
645 623
646 /* can not count locking commands against total since 624 rc = wait_for_free_request(ses, long_op);
647 they are allowed to block on server */ 625 if (rc)
648 626 return rc;
649 if(long_op < 3) { 627
650 /* update # of requests on the wire to server */
651 atomic_inc(&ses->server->inFlight);
652 }
653 spin_unlock(&GlobalMid_Lock);
654 break;
655 }
656 }
657 }
658 /* make sure that we sign in the same order that we send on this socket 628 /* make sure that we sign in the same order that we send on this socket
659 and avoid races inside tcp sendmsg code that could cause corruption 629 and avoid races inside tcp sendmsg code that could cause corruption
660 of smb data */ 630 of smb data */
661 631
662 down(&ses->server->tcpSem); 632 down(&ses->server->tcpSem);
663 633
664 if (ses->server->tcpStatus == CifsExiting) { 634 rc = allocate_mid(ses, in_buf, &midQ);
665 rc = -ENOENT; 635 if (rc) {
666 goto out_unlock;
667 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
668 cFYI(1,("tcp session dead - return to caller to retry"));
669 rc = -EAGAIN;
670 goto out_unlock;
671 } else if (ses->status != CifsGood) {
672 /* check if SMB session is bad because we are setting it up */
673 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
674 (in_buf->Command != SMB_COM_NEGOTIATE)) {
675 rc = -EAGAIN;
676 goto out_unlock;
677 } /* else ok - we are setting up session */
678 }
679 midQ = AllocMidQEntry(in_buf, ses);
680 if (midQ == NULL) {
681 up(&ses->server->tcpSem); 636 up(&ses->server->tcpSem);
682 /* If not lock req, update # of requests on wire to server */ 637 /* Update # of requests on wire to server */
683 if(long_op < 3) { 638 atomic_dec(&ses->server->inFlight);
684 atomic_dec(&ses->server->inFlight); 639 wake_up(&ses->server->request_q);
685 wake_up(&ses->server->request_q); 640 return rc;
686 }
687 return -ENOMEM;
688 } 641 }
689 642
690 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { 643 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
691 up(&ses->server->tcpSem);
692 cERROR(1, ("Illegal length, greater than maximum frame, %d", 644 cERROR(1, ("Illegal length, greater than maximum frame, %d",
693 in_buf->smb_buf_length)); 645 in_buf->smb_buf_length));
694 DeleteMidQEntry(midQ); 646 DeleteMidQEntry(midQ);
695 /* If not lock req, update # of requests on wire to server */ 647 up(&ses->server->tcpSem);
696 if(long_op < 3) { 648 /* Update # of requests on wire to server */
697 atomic_dec(&ses->server->inFlight); 649 atomic_dec(&ses->server->inFlight);
698 wake_up(&ses->server->request_q); 650 wake_up(&ses->server->request_q);
699 }
700 return -EIO; 651 return -EIO;
701 } 652 }
702 653
@@ -712,27 +663,19 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
712 atomic_dec(&ses->server->inSend); 663 atomic_dec(&ses->server->inSend);
713 midQ->when_sent = jiffies; 664 midQ->when_sent = jiffies;
714#endif 665#endif
715 if(rc < 0) { 666 up(&ses->server->tcpSem);
716 DeleteMidQEntry(midQ); 667
717 up(&ses->server->tcpSem); 668 if(rc < 0)
718 /* If not lock req, update # of requests on wire to server */ 669 goto out;
719 if(long_op < 3) { 670
720 atomic_dec(&ses->server->inFlight);
721 wake_up(&ses->server->request_q);
722 }
723 return rc;
724 } else
725 up(&ses->server->tcpSem);
726 if (long_op == -1) 671 if (long_op == -1)
727 goto cifs_no_response_exit; 672 goto out;
728 else if (long_op == 2) /* writes past end of file can take loong time */ 673 else if (long_op == 2) /* writes past end of file can take loong time */
729 timeout = 180 * HZ; 674 timeout = 180 * HZ;
730 else if (long_op == 1) 675 else if (long_op == 1)
731 timeout = 45 * HZ; /* should be greater than 676 timeout = 45 * HZ; /* should be greater than
732 servers oplock break timeout (about 43 seconds) */ 677 servers oplock break timeout (about 43 seconds) */
733 else if (long_op > 2) { 678 else
734 timeout = MAX_SCHEDULE_TIMEOUT;
735 } else
736 timeout = 15 * HZ; 679 timeout = 15 * HZ;
737 /* wait for 15 seconds or until woken up due to response arriving or 680 /* wait for 15 seconds or until woken up due to response arriving or
738 due to last connection to this server being unmounted */ 681 due to last connection to this server being unmounted */
@@ -743,47 +686,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
743 } 686 }
744 687
745 /* No user interrupts in wait - wreaks havoc with performance */ 688 /* No user interrupts in wait - wreaks havoc with performance */
746 if(timeout != MAX_SCHEDULE_TIMEOUT) { 689 wait_for_response(ses, midQ, timeout, 10 * HZ);
747 unsigned long curr_timeout;
748
749 for (;;) {
750 curr_timeout = timeout + jiffies;
751 wait_event(ses->server->response_q,
752 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
753 time_after(jiffies, curr_timeout) ||
754 ((ses->server->tcpStatus != CifsGood) &&
755 (ses->server->tcpStatus != CifsNew)));
756
757 if (time_after(jiffies, curr_timeout) &&
758 (midQ->midState == MID_REQUEST_SUBMITTED) &&
759 ((ses->server->tcpStatus == CifsGood) ||
760 (ses->server->tcpStatus == CifsNew))) {
761
762 unsigned long lrt;
763
764 /* We timed out. Is the server still
765 sending replies ? */
766 spin_lock(&GlobalMid_Lock);
767 lrt = ses->server->lstrp;
768 spin_unlock(&GlobalMid_Lock);
769
770 /* Calculate 10 seconds past last receive time*/
771 lrt += (10 * HZ);
772 if (time_after(jiffies, lrt)) {
773 /* Server sent no reply in 10 seconds */
774 cERROR(1,("Server not responding"));
775 break;
776 }
777 } else {
778 break;
779 }
780 }
781 } else {
782 wait_event(ses->server->response_q,
783 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
784 ((ses->server->tcpStatus != CifsGood) &&
785 (ses->server->tcpStatus != CifsNew)));
786 }
787 690
788 spin_lock(&GlobalMid_Lock); 691 spin_lock(&GlobalMid_Lock);
789 if (midQ->resp_buf) { 692 if (midQ->resp_buf) {
@@ -811,11 +714,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
811 } 714 }
812 spin_unlock(&GlobalMid_Lock); 715 spin_unlock(&GlobalMid_Lock);
813 DeleteMidQEntry(midQ); 716 DeleteMidQEntry(midQ);
814 /* If not lock req, update # of requests on wire to server */ 717 /* Update # of requests on wire to server */
815 if(long_op < 3) { 718 atomic_dec(&ses->server->inFlight);
816 atomic_dec(&ses->server->inFlight); 719 wake_up(&ses->server->request_q);
817 wake_up(&ses->server->request_q);
818 }
819 return rc; 720 return rc;
820 } 721 }
821 722
@@ -862,23 +763,253 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
862 cERROR(1,("Bad MID state?")); 763 cERROR(1,("Bad MID state?"));
863 } 764 }
864 } 765 }
865cifs_no_response_exit: 766
767out:
768
866 DeleteMidQEntry(midQ); 769 DeleteMidQEntry(midQ);
770 atomic_dec(&ses->server->inFlight);
771 wake_up(&ses->server->request_q);
867 772
868 if(long_op < 3) { 773 return rc;
869 atomic_dec(&ses->server->inFlight); 774}
870 wake_up(&ses->server->request_q);
871 }
872 775
776/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
777
778static int
779send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
780 struct mid_q_entry *midQ)
781{
782 int rc = 0;
783 struct cifsSesInfo *ses = tcon->ses;
784 __u16 mid = in_buf->Mid;
785
786 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
787 in_buf->Mid = mid;
788 down(&ses->server->tcpSem);
789 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
790 if (rc) {
791 up(&ses->server->tcpSem);
792 return rc;
793 }
794 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
795 (struct sockaddr *) &(ses->server->addr.sockAddr));
796 up(&ses->server->tcpSem);
873 return rc; 797 return rc;
798}
799
800/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
801 blocking lock to return. */
802
803static int
804send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
805 struct smb_hdr *in_buf,
806 struct smb_hdr *out_buf)
807{
808 int bytes_returned;
809 struct cifsSesInfo *ses = tcon->ses;
810 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
811
812 /* We just modify the current in_buf to change
813 the type of lock from LOCKING_ANDX_SHARED_LOCK
814 or LOCKING_ANDX_EXCLUSIVE_LOCK to
815 LOCKING_ANDX_CANCEL_LOCK. */
816
817 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
818 pSMB->Timeout = 0;
819 pSMB->hdr.Mid = GetNextMid(ses->server);
820
821 return SendReceive(xid, ses, in_buf, out_buf,
822 &bytes_returned, 0);
823}
824
825int
826SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
827 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
828 int *pbytes_returned)
829{
830 int rc = 0;
831 int rstart = 0;
832 unsigned int receive_len;
833 struct mid_q_entry *midQ;
834 struct cifsSesInfo *ses;
835
836 if (tcon == NULL || tcon->ses == NULL) {
837 cERROR(1,("Null smb session"));
838 return -EIO;
839 }
840 ses = tcon->ses;
841
842 if(ses->server == NULL) {
843 cERROR(1,("Null tcp session"));
844 return -EIO;
845 }
846
847 if(ses->server->tcpStatus == CifsExiting)
848 return -ENOENT;
849
850 /* Ensure that we do not send more than 50 overlapping requests
851 to the same server. We may make this configurable later or
852 use ses->maxReq */
853
854 rc = wait_for_free_request(ses, 3);
855 if (rc)
856 return rc;
857
858 /* make sure that we sign in the same order that we send on this socket
859 and avoid races inside tcp sendmsg code that could cause corruption
860 of smb data */
861
862 down(&ses->server->tcpSem);
863
864 rc = allocate_mid(ses, in_buf, &midQ);
865 if (rc) {
866 up(&ses->server->tcpSem);
867 return rc;
868 }
869
870 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
871 up(&ses->server->tcpSem);
872 cERROR(1, ("Illegal length, greater than maximum frame, %d",
873 in_buf->smb_buf_length));
874 DeleteMidQEntry(midQ);
875 return -EIO;
876 }
877
878 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
874 879
875out_unlock: 880 midQ->midState = MID_REQUEST_SUBMITTED;
881#ifdef CONFIG_CIFS_STATS2
882 atomic_inc(&ses->server->inSend);
883#endif
884 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
885 (struct sockaddr *) &(ses->server->addr.sockAddr));
886#ifdef CONFIG_CIFS_STATS2
887 atomic_dec(&ses->server->inSend);
888 midQ->when_sent = jiffies;
889#endif
876 up(&ses->server->tcpSem); 890 up(&ses->server->tcpSem);
877 /* If not lock req, update # of requests on wire to server */ 891
878 if(long_op < 3) { 892 if(rc < 0) {
879 atomic_dec(&ses->server->inFlight); 893 DeleteMidQEntry(midQ);
880 wake_up(&ses->server->request_q); 894 return rc;
895 }
896
897 /* Wait for a reply - allow signals to interrupt. */
898 rc = wait_event_interruptible(ses->server->response_q,
899 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
900 ((ses->server->tcpStatus != CifsGood) &&
901 (ses->server->tcpStatus != CifsNew)));
902
903 /* Were we interrupted by a signal ? */
904 if ((rc == -ERESTARTSYS) &&
905 (midQ->midState == MID_REQUEST_SUBMITTED) &&
906 ((ses->server->tcpStatus == CifsGood) ||
907 (ses->server->tcpStatus == CifsNew))) {
908
909 if (in_buf->Command == SMB_COM_TRANSACTION2) {
910 /* POSIX lock. We send a NT_CANCEL SMB to cause the
911 blocking lock to return. */
912
913 rc = send_nt_cancel(tcon, in_buf, midQ);
914 if (rc) {
915 DeleteMidQEntry(midQ);
916 return rc;
917 }
918 } else {
919 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
920 to cause the blocking lock to return. */
921
922 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
923
924 /* If we get -ENOLCK back the lock may have
925 already been removed. Don't exit in this case. */
926 if (rc && rc != -ENOLCK) {
927 DeleteMidQEntry(midQ);
928 return rc;
929 }
930 }
931
932 /* Wait 5 seconds for the response. */
933 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ)==0) {
934 /* We got the response - restart system call. */
935 rstart = 1;
936 }
937 }
938
939 spin_lock(&GlobalMid_Lock);
940 if (midQ->resp_buf) {
941 spin_unlock(&GlobalMid_Lock);
942 receive_len = midQ->resp_buf->smb_buf_length;
943 } else {
944 cERROR(1,("No response for cmd %d mid %d",
945 midQ->command, midQ->mid));
946 if(midQ->midState == MID_REQUEST_SUBMITTED) {
947 if(ses->server->tcpStatus == CifsExiting)
948 rc = -EHOSTDOWN;
949 else {
950 ses->server->tcpStatus = CifsNeedReconnect;
951 midQ->midState = MID_RETRY_NEEDED;
952 }
953 }
954
955 if (rc != -EHOSTDOWN) {
956 if(midQ->midState == MID_RETRY_NEEDED) {
957 rc = -EAGAIN;
958 cFYI(1,("marking request for retry"));
959 } else {
960 rc = -EIO;
961 }
962 }
963 spin_unlock(&GlobalMid_Lock);
964 DeleteMidQEntry(midQ);
965 return rc;
881 } 966 }
967
968 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
969 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
970 receive_len, xid));
971 rc = -EIO;
972 } else { /* rcvd frame is ok */
973
974 if (midQ->resp_buf && out_buf
975 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
976 out_buf->smb_buf_length = receive_len;
977 memcpy((char *)out_buf + 4,
978 (char *)midQ->resp_buf + 4,
979 receive_len);
980
981 dump_smb(out_buf, 92);
982 /* convert the length into a more usable form */
983 if((receive_len > 24) &&
984 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
985 SECMODE_SIGN_ENABLED))) {
986 rc = cifs_verify_signature(out_buf,
987 ses->server->mac_signing_key,
988 midQ->sequence_number+1);
989 if(rc) {
990 cERROR(1,("Unexpected SMB signature"));
991 /* BB FIXME add code to kill session */
992 }
993 }
994
995 *pbytes_returned = out_buf->smb_buf_length;
996
997 /* BB special case reconnect tid and uid here? */
998 rc = map_smb_to_linux_error(out_buf);
882 999
1000 /* convert ByteCount if necessary */
1001 if (receive_len >=
1002 sizeof (struct smb_hdr) -
1003 4 /* do not count RFC1001 header */ +
1004 (2 * out_buf->WordCount) + 2 /* bcc */ )
1005 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1006 } else {
1007 rc = -EIO;
1008 cERROR(1,("Bad MID state?"));
1009 }
1010 }
1011 DeleteMidQEntry(midQ);
1012 if (rstart && rc == -EACCES)
1013 return -ERESTARTSYS;
883 return rc; 1014 return rc;
884} 1015}