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 59ca81b1691..c1ccca1a933 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; |
