diff options
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r-- | fs/cifs/transport.c | 434 |
1 files changed, 206 insertions, 228 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 59ca81b16919..c1ccca1a933f 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -36,7 +36,13 @@ | |||
36 | 36 | ||
37 | extern mempool_t *cifs_mid_poolp; | 37 | extern mempool_t *cifs_mid_poolp; |
38 | 38 | ||
39 | static struct mid_q_entry * | 39 | static void |
40 | wake_up_task(struct mid_q_entry *mid) | ||
41 | { | ||
42 | wake_up_process(mid->callback_data); | ||
43 | } | ||
44 | |||
45 | struct mid_q_entry * | ||
40 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) | 46 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) |
41 | { | 47 | { |
42 | struct mid_q_entry *temp; | 48 | struct mid_q_entry *temp; |
@@ -58,28 +64,28 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) | |||
58 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ | 64 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ |
59 | /* when mid allocated can be before when sent */ | 65 | /* when mid allocated can be before when sent */ |
60 | temp->when_alloc = jiffies; | 66 | temp->when_alloc = jiffies; |
61 | temp->tsk = current; | 67 | |
68 | /* | ||
69 | * The default is for the mid to be synchronous, so the | ||
70 | * default callback just wakes up the current task. | ||
71 | */ | ||
72 | temp->callback = wake_up_task; | ||
73 | temp->callback_data = current; | ||
62 | } | 74 | } |
63 | 75 | ||
64 | spin_lock(&GlobalMid_Lock); | ||
65 | list_add_tail(&temp->qhead, &server->pending_mid_q); | ||
66 | atomic_inc(&midCount); | 76 | atomic_inc(&midCount); |
67 | temp->midState = MID_REQUEST_ALLOCATED; | 77 | temp->midState = MID_REQUEST_ALLOCATED; |
68 | spin_unlock(&GlobalMid_Lock); | ||
69 | return temp; | 78 | return temp; |
70 | } | 79 | } |
71 | 80 | ||
72 | static void | 81 | void |
73 | DeleteMidQEntry(struct mid_q_entry *midEntry) | 82 | DeleteMidQEntry(struct mid_q_entry *midEntry) |
74 | { | 83 | { |
75 | #ifdef CONFIG_CIFS_STATS2 | 84 | #ifdef CONFIG_CIFS_STATS2 |
76 | unsigned long now; | 85 | unsigned long now; |
77 | #endif | 86 | #endif |
78 | spin_lock(&GlobalMid_Lock); | ||
79 | midEntry->midState = MID_FREE; | 87 | midEntry->midState = MID_FREE; |
80 | list_del(&midEntry->qhead); | ||
81 | atomic_dec(&midCount); | 88 | atomic_dec(&midCount); |
82 | spin_unlock(&GlobalMid_Lock); | ||
83 | if (midEntry->largeBuf) | 89 | if (midEntry->largeBuf) |
84 | cifs_buf_release(midEntry->resp_buf); | 90 | cifs_buf_release(midEntry->resp_buf); |
85 | else | 91 | else |
@@ -103,6 +109,16 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) | |||
103 | mempool_free(midEntry, cifs_mid_poolp); | 109 | mempool_free(midEntry, cifs_mid_poolp); |
104 | } | 110 | } |
105 | 111 | ||
112 | static void | ||
113 | delete_mid(struct mid_q_entry *mid) | ||
114 | { | ||
115 | spin_lock(&GlobalMid_Lock); | ||
116 | list_del(&mid->qhead); | ||
117 | spin_unlock(&GlobalMid_Lock); | ||
118 | |||
119 | DeleteMidQEntry(mid); | ||
120 | } | ||
121 | |||
106 | static int | 122 | static int |
107 | smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | 123 | smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) |
108 | { | 124 | { |
@@ -244,31 +260,31 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, | |||
244 | return smb_sendv(server, &iov, 1); | 260 | return smb_sendv(server, &iov, 1); |
245 | } | 261 | } |
246 | 262 | ||
247 | static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | 263 | static int wait_for_free_request(struct TCP_Server_Info *server, |
264 | const int long_op) | ||
248 | { | 265 | { |
249 | if (long_op == CIFS_ASYNC_OP) { | 266 | if (long_op == CIFS_ASYNC_OP) { |
250 | /* oplock breaks must not be held up */ | 267 | /* oplock breaks must not be held up */ |
251 | atomic_inc(&ses->server->inFlight); | 268 | atomic_inc(&server->inFlight); |
252 | return 0; | 269 | return 0; |
253 | } | 270 | } |
254 | 271 | ||
255 | spin_lock(&GlobalMid_Lock); | 272 | spin_lock(&GlobalMid_Lock); |
256 | while (1) { | 273 | while (1) { |
257 | if (atomic_read(&ses->server->inFlight) >= | 274 | if (atomic_read(&server->inFlight) >= cifs_max_pending) { |
258 | cifs_max_pending){ | ||
259 | spin_unlock(&GlobalMid_Lock); | 275 | spin_unlock(&GlobalMid_Lock); |
260 | #ifdef CONFIG_CIFS_STATS2 | 276 | #ifdef CONFIG_CIFS_STATS2 |
261 | atomic_inc(&ses->server->num_waiters); | 277 | atomic_inc(&server->num_waiters); |
262 | #endif | 278 | #endif |
263 | wait_event(ses->server->request_q, | 279 | wait_event(server->request_q, |
264 | atomic_read(&ses->server->inFlight) | 280 | atomic_read(&server->inFlight) |
265 | < cifs_max_pending); | 281 | < cifs_max_pending); |
266 | #ifdef CONFIG_CIFS_STATS2 | 282 | #ifdef CONFIG_CIFS_STATS2 |
267 | atomic_dec(&ses->server->num_waiters); | 283 | atomic_dec(&server->num_waiters); |
268 | #endif | 284 | #endif |
269 | spin_lock(&GlobalMid_Lock); | 285 | spin_lock(&GlobalMid_Lock); |
270 | } else { | 286 | } else { |
271 | if (ses->server->tcpStatus == CifsExiting) { | 287 | if (server->tcpStatus == CifsExiting) { |
272 | spin_unlock(&GlobalMid_Lock); | 288 | spin_unlock(&GlobalMid_Lock); |
273 | return -ENOENT; | 289 | return -ENOENT; |
274 | } | 290 | } |
@@ -278,7 +294,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | |||
278 | 294 | ||
279 | /* update # of requests on the wire to server */ | 295 | /* update # of requests on the wire to server */ |
280 | if (long_op != CIFS_BLOCKING_OP) | 296 | if (long_op != CIFS_BLOCKING_OP) |
281 | atomic_inc(&ses->server->inFlight); | 297 | atomic_inc(&server->inFlight); |
282 | spin_unlock(&GlobalMid_Lock); | 298 | spin_unlock(&GlobalMid_Lock); |
283 | break; | 299 | break; |
284 | } | 300 | } |
@@ -308,53 +324,81 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, | |||
308 | *ppmidQ = AllocMidQEntry(in_buf, ses->server); | 324 | *ppmidQ = AllocMidQEntry(in_buf, ses->server); |
309 | if (*ppmidQ == NULL) | 325 | if (*ppmidQ == NULL) |
310 | return -ENOMEM; | 326 | return -ENOMEM; |
327 | spin_lock(&GlobalMid_Lock); | ||
328 | list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q); | ||
329 | spin_unlock(&GlobalMid_Lock); | ||
311 | return 0; | 330 | return 0; |
312 | } | 331 | } |
313 | 332 | ||
314 | static int wait_for_response(struct cifsSesInfo *ses, | 333 | static int |
315 | struct mid_q_entry *midQ, | 334 | wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ) |
316 | unsigned long timeout, | ||
317 | unsigned long time_to_wait) | ||
318 | { | 335 | { |
319 | unsigned long curr_timeout; | 336 | int error; |
320 | 337 | ||
321 | for (;;) { | 338 | error = wait_event_killable(server->response_q, |
322 | curr_timeout = timeout + jiffies; | 339 | midQ->midState != MID_REQUEST_SUBMITTED); |
323 | wait_event_timeout(ses->server->response_q, | 340 | if (error < 0) |
324 | midQ->midState != MID_REQUEST_SUBMITTED, timeout); | 341 | return -ERESTARTSYS; |
325 | 342 | ||
326 | if (time_after(jiffies, curr_timeout) && | 343 | return 0; |
327 | (midQ->midState == MID_REQUEST_SUBMITTED) && | 344 | } |
328 | ((ses->server->tcpStatus == CifsGood) || | ||
329 | (ses->server->tcpStatus == CifsNew))) { | ||
330 | 345 | ||
331 | unsigned long lrt; | ||
332 | 346 | ||
333 | /* We timed out. Is the server still | 347 | /* |
334 | sending replies ? */ | 348 | * Send a SMB request and set the callback function in the mid to handle |
335 | spin_lock(&GlobalMid_Lock); | 349 | * the result. Caller is responsible for dealing with timeouts. |
336 | lrt = ses->server->lstrp; | 350 | */ |
337 | spin_unlock(&GlobalMid_Lock); | 351 | int |
352 | cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf, | ||
353 | mid_callback_t *callback, void *cbdata) | ||
354 | { | ||
355 | int rc; | ||
356 | struct mid_q_entry *mid; | ||
338 | 357 | ||
339 | /* Calculate time_to_wait past last receive time. | 358 | rc = wait_for_free_request(server, CIFS_ASYNC_OP); |
340 | Although we prefer not to time out if the | 359 | if (rc) |
341 | server is still responding - we will time | 360 | return rc; |
342 | out if the server takes more than 15 (or 45 | 361 | |
343 | or 180) seconds to respond to this request | 362 | mutex_lock(&server->srv_mutex); |
344 | and has not responded to any request from | 363 | mid = AllocMidQEntry(in_buf, server); |
345 | other threads on the client within 10 seconds */ | 364 | if (mid == NULL) { |
346 | lrt += time_to_wait; | 365 | mutex_unlock(&server->srv_mutex); |
347 | if (time_after(jiffies, lrt)) { | 366 | return -ENOMEM; |
348 | /* No replies for time_to_wait. */ | ||
349 | cERROR(1, "server not responding"); | ||
350 | return -1; | ||
351 | } | ||
352 | } else { | ||
353 | return 0; | ||
354 | } | ||
355 | } | 367 | } |
356 | } | ||
357 | 368 | ||
369 | /* put it on the pending_mid_q */ | ||
370 | spin_lock(&GlobalMid_Lock); | ||
371 | list_add_tail(&mid->qhead, &server->pending_mid_q); | ||
372 | spin_unlock(&GlobalMid_Lock); | ||
373 | |||
374 | rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); | ||
375 | if (rc) { | ||
376 | mutex_unlock(&server->srv_mutex); | ||
377 | goto out_err; | ||
378 | } | ||
379 | |||
380 | mid->callback = callback; | ||
381 | mid->callback_data = cbdata; | ||
382 | mid->midState = MID_REQUEST_SUBMITTED; | ||
383 | #ifdef CONFIG_CIFS_STATS2 | ||
384 | atomic_inc(&server->inSend); | ||
385 | #endif | ||
386 | rc = smb_send(server, in_buf, in_buf->smb_buf_length); | ||
387 | #ifdef CONFIG_CIFS_STATS2 | ||
388 | atomic_dec(&server->inSend); | ||
389 | mid->when_sent = jiffies; | ||
390 | #endif | ||
391 | mutex_unlock(&server->srv_mutex); | ||
392 | if (rc) | ||
393 | goto out_err; | ||
394 | |||
395 | return rc; | ||
396 | out_err: | ||
397 | delete_mid(mid); | ||
398 | atomic_dec(&server->inFlight); | ||
399 | wake_up(&server->request_q); | ||
400 | return rc; | ||
401 | } | ||
358 | 402 | ||
359 | /* | 403 | /* |
360 | * | 404 | * |
@@ -382,6 +426,81 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | |||
382 | return rc; | 426 | return rc; |
383 | } | 427 | } |
384 | 428 | ||
429 | static int | ||
430 | sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) | ||
431 | { | ||
432 | int rc = 0; | ||
433 | |||
434 | cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command, | ||
435 | mid->mid, mid->midState); | ||
436 | |||
437 | spin_lock(&GlobalMid_Lock); | ||
438 | /* ensure that it's no longer on the pending_mid_q */ | ||
439 | list_del_init(&mid->qhead); | ||
440 | |||
441 | switch (mid->midState) { | ||
442 | case MID_RESPONSE_RECEIVED: | ||
443 | spin_unlock(&GlobalMid_Lock); | ||
444 | return rc; | ||
445 | case MID_REQUEST_SUBMITTED: | ||
446 | /* socket is going down, reject all calls */ | ||
447 | if (server->tcpStatus == CifsExiting) { | ||
448 | cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d", | ||
449 | __func__, mid->mid, mid->command, mid->midState); | ||
450 | rc = -EHOSTDOWN; | ||
451 | break; | ||
452 | } | ||
453 | case MID_RETRY_NEEDED: | ||
454 | rc = -EAGAIN; | ||
455 | break; | ||
456 | default: | ||
457 | cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__, | ||
458 | mid->mid, mid->midState); | ||
459 | rc = -EIO; | ||
460 | } | ||
461 | spin_unlock(&GlobalMid_Lock); | ||
462 | |||
463 | DeleteMidQEntry(mid); | ||
464 | return rc; | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * An NT cancel request header looks just like the original request except: | ||
469 | * | ||
470 | * The Command is SMB_COM_NT_CANCEL | ||
471 | * The WordCount is zeroed out | ||
472 | * The ByteCount is zeroed out | ||
473 | * | ||
474 | * This function mangles an existing request buffer into a | ||
475 | * SMB_COM_NT_CANCEL request and then sends it. | ||
476 | */ | ||
477 | static int | ||
478 | send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, | ||
479 | struct mid_q_entry *mid) | ||
480 | { | ||
481 | int rc = 0; | ||
482 | |||
483 | /* -4 for RFC1001 length and +2 for BCC field */ | ||
484 | in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2; | ||
485 | in_buf->Command = SMB_COM_NT_CANCEL; | ||
486 | in_buf->WordCount = 0; | ||
487 | put_bcc_le(0, in_buf); | ||
488 | |||
489 | mutex_lock(&server->srv_mutex); | ||
490 | rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); | ||
491 | if (rc) { | ||
492 | mutex_unlock(&server->srv_mutex); | ||
493 | return rc; | ||
494 | } | ||
495 | rc = smb_send(server, in_buf, in_buf->smb_buf_length); | ||
496 | mutex_unlock(&server->srv_mutex); | ||
497 | |||
498 | cFYI(1, "issued NT_CANCEL for mid %u, rc = %d", | ||
499 | in_buf->Mid, rc); | ||
500 | |||
501 | return rc; | ||
502 | } | ||
503 | |||
385 | int | 504 | int |
386 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | 505 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
387 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, | 506 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, |
@@ -390,7 +509,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
390 | int rc = 0; | 509 | int rc = 0; |
391 | int long_op; | 510 | int long_op; |
392 | unsigned int receive_len; | 511 | unsigned int receive_len; |
393 | unsigned long timeout; | ||
394 | struct mid_q_entry *midQ; | 512 | struct mid_q_entry *midQ; |
395 | struct smb_hdr *in_buf = iov[0].iov_base; | 513 | struct smb_hdr *in_buf = iov[0].iov_base; |
396 | 514 | ||
@@ -413,7 +531,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
413 | to the same server. We may make this configurable later or | 531 | to the same server. We may make this configurable later or |
414 | use ses->maxReq */ | 532 | use ses->maxReq */ |
415 | 533 | ||
416 | rc = wait_for_free_request(ses, long_op); | 534 | rc = wait_for_free_request(ses->server, long_op); |
417 | if (rc) { | 535 | if (rc) { |
418 | cifs_small_buf_release(in_buf); | 536 | cifs_small_buf_release(in_buf); |
419 | return rc; | 537 | return rc; |
@@ -457,65 +575,20 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
457 | if (rc < 0) | 575 | if (rc < 0) |
458 | goto out; | 576 | goto out; |
459 | 577 | ||
460 | if (long_op == CIFS_STD_OP) | 578 | if (long_op == CIFS_ASYNC_OP) |
461 | timeout = 15 * HZ; | ||
462 | else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */ | ||
463 | timeout = 180 * HZ; | ||
464 | else if (long_op == CIFS_LONG_OP) | ||
465 | timeout = 45 * HZ; /* should be greater than | ||
466 | servers oplock break timeout (about 43 seconds) */ | ||
467 | else if (long_op == CIFS_ASYNC_OP) | ||
468 | goto out; | 579 | goto out; |
469 | else if (long_op == CIFS_BLOCKING_OP) | ||
470 | timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */ | ||
471 | else { | ||
472 | cERROR(1, "unknown timeout flag %d", long_op); | ||
473 | rc = -EIO; | ||
474 | goto out; | ||
475 | } | ||
476 | |||
477 | /* wait for 15 seconds or until woken up due to response arriving or | ||
478 | due to last connection to this server being unmounted */ | ||
479 | if (signal_pending(current)) { | ||
480 | /* if signal pending do not hold up user for full smb timeout | ||
481 | but we still give response a chance to complete */ | ||
482 | timeout = 2 * HZ; | ||
483 | } | ||
484 | |||
485 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
486 | wait_for_response(ses, midQ, timeout, 10 * HZ); | ||
487 | |||
488 | spin_lock(&GlobalMid_Lock); | ||
489 | 580 | ||
490 | if (midQ->resp_buf == NULL) { | 581 | rc = wait_for_response(ses->server, midQ); |
491 | cERROR(1, "No response to cmd %d mid %d", | 582 | if (rc != 0) |
492 | midQ->command, midQ->mid); | 583 | goto out; |
493 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | ||
494 | if (ses->server->tcpStatus == CifsExiting) | ||
495 | rc = -EHOSTDOWN; | ||
496 | else { | ||
497 | ses->server->tcpStatus = CifsNeedReconnect; | ||
498 | midQ->midState = MID_RETRY_NEEDED; | ||
499 | } | ||
500 | } | ||
501 | 584 | ||
502 | if (rc != -EHOSTDOWN) { | 585 | rc = sync_mid_result(midQ, ses->server); |
503 | if (midQ->midState == MID_RETRY_NEEDED) { | 586 | if (rc != 0) { |
504 | rc = -EAGAIN; | ||
505 | cFYI(1, "marking request for retry"); | ||
506 | } else { | ||
507 | rc = -EIO; | ||
508 | } | ||
509 | } | ||
510 | spin_unlock(&GlobalMid_Lock); | ||
511 | DeleteMidQEntry(midQ); | ||
512 | /* Update # of requests on wire to server */ | ||
513 | atomic_dec(&ses->server->inFlight); | 587 | atomic_dec(&ses->server->inFlight); |
514 | wake_up(&ses->server->request_q); | 588 | wake_up(&ses->server->request_q); |
515 | return rc; | 589 | return rc; |
516 | } | 590 | } |
517 | 591 | ||
518 | spin_unlock(&GlobalMid_Lock); | ||
519 | receive_len = midQ->resp_buf->smb_buf_length; | 592 | receive_len = midQ->resp_buf->smb_buf_length; |
520 | 593 | ||
521 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 594 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
@@ -559,19 +632,18 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
559 | if (receive_len >= sizeof(struct smb_hdr) - 4 | 632 | if (receive_len >= sizeof(struct smb_hdr) - 4 |
560 | /* do not count RFC1001 header */ + | 633 | /* do not count RFC1001 header */ + |
561 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) | 634 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) |
562 | BCC(midQ->resp_buf) = | 635 | put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); |
563 | le16_to_cpu(BCC_LE(midQ->resp_buf)); | ||
564 | if ((flags & CIFS_NO_RESP) == 0) | 636 | if ((flags & CIFS_NO_RESP) == 0) |
565 | midQ->resp_buf = NULL; /* mark it so buf will | 637 | midQ->resp_buf = NULL; /* mark it so buf will |
566 | not be freed by | 638 | not be freed by |
567 | DeleteMidQEntry */ | 639 | delete_mid */ |
568 | } else { | 640 | } else { |
569 | rc = -EIO; | 641 | rc = -EIO; |
570 | cFYI(1, "Bad MID state?"); | 642 | cFYI(1, "Bad MID state?"); |
571 | } | 643 | } |
572 | 644 | ||
573 | out: | 645 | out: |
574 | DeleteMidQEntry(midQ); | 646 | delete_mid(midQ); |
575 | atomic_dec(&ses->server->inFlight); | 647 | atomic_dec(&ses->server->inFlight); |
576 | wake_up(&ses->server->request_q); | 648 | wake_up(&ses->server->request_q); |
577 | 649 | ||
@@ -585,7 +657,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
585 | { | 657 | { |
586 | int rc = 0; | 658 | int rc = 0; |
587 | unsigned int receive_len; | 659 | unsigned int receive_len; |
588 | unsigned long timeout; | ||
589 | struct mid_q_entry *midQ; | 660 | struct mid_q_entry *midQ; |
590 | 661 | ||
591 | if (ses == NULL) { | 662 | if (ses == NULL) { |
@@ -610,7 +681,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
610 | return -EIO; | 681 | return -EIO; |
611 | } | 682 | } |
612 | 683 | ||
613 | rc = wait_for_free_request(ses, long_op); | 684 | rc = wait_for_free_request(ses->server, long_op); |
614 | if (rc) | 685 | if (rc) |
615 | return rc; | 686 | return rc; |
616 | 687 | ||
@@ -649,64 +720,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
649 | if (rc < 0) | 720 | if (rc < 0) |
650 | goto out; | 721 | goto out; |
651 | 722 | ||
652 | if (long_op == CIFS_STD_OP) | 723 | if (long_op == CIFS_ASYNC_OP) |
653 | timeout = 15 * HZ; | ||
654 | /* wait for 15 seconds or until woken up due to response arriving or | ||
655 | due to last connection to this server being unmounted */ | ||
656 | else if (long_op == CIFS_ASYNC_OP) | ||
657 | goto out; | 724 | goto out; |
658 | else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */ | ||
659 | timeout = 180 * HZ; | ||
660 | else if (long_op == CIFS_LONG_OP) | ||
661 | timeout = 45 * HZ; /* should be greater than | ||
662 | servers oplock break timeout (about 43 seconds) */ | ||
663 | else if (long_op == CIFS_BLOCKING_OP) | ||
664 | timeout = 0x7FFFFFFF; /* large but no so large as to wrap */ | ||
665 | else { | ||
666 | cERROR(1, "unknown timeout flag %d", long_op); | ||
667 | rc = -EIO; | ||
668 | goto out; | ||
669 | } | ||
670 | 725 | ||
671 | if (signal_pending(current)) { | 726 | rc = wait_for_response(ses->server, midQ); |
672 | /* if signal pending do not hold up user for full smb timeout | 727 | if (rc != 0) |
673 | but we still give response a chance to complete */ | 728 | goto out; |
674 | timeout = 2 * HZ; | ||
675 | } | ||
676 | |||
677 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
678 | wait_for_response(ses, midQ, timeout, 10 * HZ); | ||
679 | |||
680 | spin_lock(&GlobalMid_Lock); | ||
681 | if (midQ->resp_buf == NULL) { | ||
682 | cERROR(1, "No response for cmd %d mid %d", | ||
683 | midQ->command, midQ->mid); | ||
684 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | ||
685 | if (ses->server->tcpStatus == CifsExiting) | ||
686 | rc = -EHOSTDOWN; | ||
687 | else { | ||
688 | ses->server->tcpStatus = CifsNeedReconnect; | ||
689 | midQ->midState = MID_RETRY_NEEDED; | ||
690 | } | ||
691 | } | ||
692 | 729 | ||
693 | if (rc != -EHOSTDOWN) { | 730 | rc = sync_mid_result(midQ, ses->server); |
694 | if (midQ->midState == MID_RETRY_NEEDED) { | 731 | if (rc != 0) { |
695 | rc = -EAGAIN; | ||
696 | cFYI(1, "marking request for retry"); | ||
697 | } else { | ||
698 | rc = -EIO; | ||
699 | } | ||
700 | } | ||
701 | spin_unlock(&GlobalMid_Lock); | ||
702 | DeleteMidQEntry(midQ); | ||
703 | /* Update # of requests on wire to server */ | ||
704 | atomic_dec(&ses->server->inFlight); | 732 | atomic_dec(&ses->server->inFlight); |
705 | wake_up(&ses->server->request_q); | 733 | wake_up(&ses->server->request_q); |
706 | return rc; | 734 | return rc; |
707 | } | 735 | } |
708 | 736 | ||
709 | spin_unlock(&GlobalMid_Lock); | ||
710 | receive_len = midQ->resp_buf->smb_buf_length; | 737 | receive_len = midQ->resp_buf->smb_buf_length; |
711 | 738 | ||
712 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 739 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
@@ -748,43 +775,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
748 | if (receive_len >= sizeof(struct smb_hdr) - 4 | 775 | if (receive_len >= sizeof(struct smb_hdr) - 4 |
749 | /* do not count RFC1001 header */ + | 776 | /* do not count RFC1001 header */ + |
750 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | 777 | (2 * out_buf->WordCount) + 2 /* bcc */ ) |
751 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | 778 | put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); |
752 | } else { | 779 | } else { |
753 | rc = -EIO; | 780 | rc = -EIO; |
754 | cERROR(1, "Bad MID state?"); | 781 | cERROR(1, "Bad MID state?"); |
755 | } | 782 | } |
756 | 783 | ||
757 | out: | 784 | out: |
758 | DeleteMidQEntry(midQ); | 785 | delete_mid(midQ); |
759 | atomic_dec(&ses->server->inFlight); | 786 | atomic_dec(&ses->server->inFlight); |
760 | wake_up(&ses->server->request_q); | 787 | wake_up(&ses->server->request_q); |
761 | 788 | ||
762 | return rc; | 789 | return rc; |
763 | } | 790 | } |
764 | 791 | ||
765 | /* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */ | ||
766 | |||
767 | static int | ||
768 | send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, | ||
769 | struct mid_q_entry *midQ) | ||
770 | { | ||
771 | int rc = 0; | ||
772 | struct cifsSesInfo *ses = tcon->ses; | ||
773 | __u16 mid = in_buf->Mid; | ||
774 | |||
775 | header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0); | ||
776 | in_buf->Mid = mid; | ||
777 | mutex_lock(&ses->server->srv_mutex); | ||
778 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | ||
779 | if (rc) { | ||
780 | mutex_unlock(&ses->server->srv_mutex); | ||
781 | return rc; | ||
782 | } | ||
783 | rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); | ||
784 | mutex_unlock(&ses->server->srv_mutex); | ||
785 | return rc; | ||
786 | } | ||
787 | |||
788 | /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows | 792 | /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows |
789 | blocking lock to return. */ | 793 | blocking lock to return. */ |
790 | 794 | ||
@@ -807,7 +811,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon, | |||
807 | pSMB->hdr.Mid = GetNextMid(ses->server); | 811 | pSMB->hdr.Mid = GetNextMid(ses->server); |
808 | 812 | ||
809 | return SendReceive(xid, ses, in_buf, out_buf, | 813 | return SendReceive(xid, ses, in_buf, out_buf, |
810 | &bytes_returned, CIFS_STD_OP); | 814 | &bytes_returned, 0); |
811 | } | 815 | } |
812 | 816 | ||
813 | int | 817 | int |
@@ -845,7 +849,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
845 | return -EIO; | 849 | return -EIO; |
846 | } | 850 | } |
847 | 851 | ||
848 | rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); | 852 | rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP); |
849 | if (rc) | 853 | if (rc) |
850 | return rc; | 854 | return rc; |
851 | 855 | ||
@@ -863,7 +867,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
863 | 867 | ||
864 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 868 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
865 | if (rc) { | 869 | if (rc) { |
866 | DeleteMidQEntry(midQ); | 870 | delete_mid(midQ); |
867 | mutex_unlock(&ses->server->srv_mutex); | 871 | mutex_unlock(&ses->server->srv_mutex); |
868 | return rc; | 872 | return rc; |
869 | } | 873 | } |
@@ -880,7 +884,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
880 | mutex_unlock(&ses->server->srv_mutex); | 884 | mutex_unlock(&ses->server->srv_mutex); |
881 | 885 | ||
882 | if (rc < 0) { | 886 | if (rc < 0) { |
883 | DeleteMidQEntry(midQ); | 887 | delete_mid(midQ); |
884 | return rc; | 888 | return rc; |
885 | } | 889 | } |
886 | 890 | ||
@@ -899,10 +903,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
899 | if (in_buf->Command == SMB_COM_TRANSACTION2) { | 903 | if (in_buf->Command == SMB_COM_TRANSACTION2) { |
900 | /* POSIX lock. We send a NT_CANCEL SMB to cause the | 904 | /* POSIX lock. We send a NT_CANCEL SMB to cause the |
901 | blocking lock to return. */ | 905 | blocking lock to return. */ |
902 | 906 | rc = send_nt_cancel(ses->server, in_buf, midQ); | |
903 | rc = send_nt_cancel(tcon, in_buf, midQ); | ||
904 | if (rc) { | 907 | if (rc) { |
905 | DeleteMidQEntry(midQ); | 908 | delete_mid(midQ); |
906 | return rc; | 909 | return rc; |
907 | } | 910 | } |
908 | } else { | 911 | } else { |
@@ -914,47 +917,22 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
914 | /* If we get -ENOLCK back the lock may have | 917 | /* If we get -ENOLCK back the lock may have |
915 | already been removed. Don't exit in this case. */ | 918 | already been removed. Don't exit in this case. */ |
916 | if (rc && rc != -ENOLCK) { | 919 | if (rc && rc != -ENOLCK) { |
917 | DeleteMidQEntry(midQ); | 920 | delete_mid(midQ); |
918 | return rc; | 921 | return rc; |
919 | } | 922 | } |
920 | } | 923 | } |
921 | 924 | ||
922 | /* Wait 5 seconds for the response. */ | 925 | if (wait_for_response(ses->server, midQ) == 0) { |
923 | if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) { | ||
924 | /* We got the response - restart system call. */ | 926 | /* We got the response - restart system call. */ |
925 | rstart = 1; | 927 | rstart = 1; |
926 | } | 928 | } |
927 | } | 929 | } |
928 | 930 | ||
929 | spin_lock(&GlobalMid_Lock); | 931 | rc = sync_mid_result(midQ, ses->server); |
930 | if (midQ->resp_buf) { | 932 | if (rc != 0) |
931 | spin_unlock(&GlobalMid_Lock); | ||
932 | receive_len = midQ->resp_buf->smb_buf_length; | ||
933 | } else { | ||
934 | cERROR(1, "No response for cmd %d mid %d", | ||
935 | midQ->command, midQ->mid); | ||
936 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | ||
937 | if (ses->server->tcpStatus == CifsExiting) | ||
938 | rc = -EHOSTDOWN; | ||
939 | else { | ||
940 | ses->server->tcpStatus = CifsNeedReconnect; | ||
941 | midQ->midState = MID_RETRY_NEEDED; | ||
942 | } | ||
943 | } | ||
944 | |||
945 | if (rc != -EHOSTDOWN) { | ||
946 | if (midQ->midState == MID_RETRY_NEEDED) { | ||
947 | rc = -EAGAIN; | ||
948 | cFYI(1, "marking request for retry"); | ||
949 | } else { | ||
950 | rc = -EIO; | ||
951 | } | ||
952 | } | ||
953 | spin_unlock(&GlobalMid_Lock); | ||
954 | DeleteMidQEntry(midQ); | ||
955 | return rc; | 933 | return rc; |
956 | } | ||
957 | 934 | ||
935 | receive_len = midQ->resp_buf->smb_buf_length; | ||
958 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 936 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
959 | cERROR(1, "Frame too large received. Length: %d Xid: %d", | 937 | cERROR(1, "Frame too large received. Length: %d Xid: %d", |
960 | receive_len, xid); | 938 | receive_len, xid); |
@@ -998,10 +976,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
998 | if (receive_len >= sizeof(struct smb_hdr) - 4 | 976 | if (receive_len >= sizeof(struct smb_hdr) - 4 |
999 | /* do not count RFC1001 header */ + | 977 | /* do not count RFC1001 header */ + |
1000 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | 978 | (2 * out_buf->WordCount) + 2 /* bcc */ ) |
1001 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | 979 | put_bcc(get_bcc_le(out_buf), out_buf); |
1002 | 980 | ||
1003 | out: | 981 | out: |
1004 | DeleteMidQEntry(midQ); | 982 | delete_mid(midQ); |
1005 | if (rstart && rc == -EACCES) | 983 | if (rstart && rc == -EACCES) |
1006 | return -ERESTARTSYS; | 984 | return -ERESTARTSYS; |
1007 | return rc; | 985 | return rc; |