diff options
author | Pavel Shilovsky <piastry@etersoft.ru> | 2012-03-23 14:28:02 -0400 |
---|---|---|
committer | Jeff Layton <jlayton@redhat.com> | 2012-03-23 14:28:02 -0400 |
commit | 792af7b05b8a78def080ec757a4d4420b9fd0cc2 (patch) | |
tree | 6f6d556f155194295375f3d4ad6cbfabbd7aeeeb /fs/cifs/transport.c | |
parent | 934e18b5cb4531cc6e81865bf54115cfd21d1ac6 (diff) |
CIFS: Separate protocol-specific code from transport routines
that lets us use this functions for SMB2.
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r-- | fs/cifs/transport.c | 171 |
1 files changed, 99 insertions, 72 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 310918b6fcb4..3bb447d07a1d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -126,11 +126,11 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | |||
126 | int rc = 0; | 126 | int rc = 0; |
127 | int i = 0; | 127 | int i = 0; |
128 | struct msghdr smb_msg; | 128 | struct msghdr smb_msg; |
129 | struct smb_hdr *smb_buffer = iov[0].iov_base; | 129 | __be32 *buf_len = (__be32 *)(iov[0].iov_base); |
130 | unsigned int len = iov[0].iov_len; | 130 | unsigned int len = iov[0].iov_len; |
131 | unsigned int total_len; | 131 | unsigned int total_len; |
132 | int first_vec = 0; | 132 | int first_vec = 0; |
133 | unsigned int smb_buf_length = be32_to_cpu(smb_buffer->smb_buf_length); | 133 | unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); |
134 | struct socket *ssocket = server->ssocket; | 134 | struct socket *ssocket = server->ssocket; |
135 | 135 | ||
136 | if (ssocket == NULL) | 136 | if (ssocket == NULL) |
@@ -150,7 +150,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | |||
150 | total_len += iov[i].iov_len; | 150 | total_len += iov[i].iov_len; |
151 | 151 | ||
152 | cFYI(1, "Sending smb: total_len %d", total_len); | 152 | cFYI(1, "Sending smb: total_len %d", total_len); |
153 | dump_smb(smb_buffer, len); | 153 | dump_smb(iov[0].iov_base, len); |
154 | 154 | ||
155 | i = 0; | 155 | i = 0; |
156 | while (total_len) { | 156 | while (total_len) { |
@@ -158,24 +158,24 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | |||
158 | n_vec - first_vec, total_len); | 158 | n_vec - first_vec, total_len); |
159 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 159 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
160 | i++; | 160 | i++; |
161 | /* if blocking send we try 3 times, since each can block | 161 | /* |
162 | for 5 seconds. For nonblocking we have to try more | 162 | * If blocking send we try 3 times, since each can block |
163 | but wait increasing amounts of time allowing time for | 163 | * for 5 seconds. For nonblocking we have to try more |
164 | socket to clear. The overall time we wait in either | 164 | * but wait increasing amounts of time allowing time for |
165 | case to send on the socket is about 15 seconds. | 165 | * socket to clear. The overall time we wait in either |
166 | Similarly we wait for 15 seconds for | 166 | * case to send on the socket is about 15 seconds. |
167 | a response from the server in SendReceive[2] | 167 | * Similarly we wait for 15 seconds for a response from |
168 | for the server to send a response back for | 168 | * the server in SendReceive[2] for the server to send |
169 | most types of requests (except SMB Write | 169 | * a response back for most types of requests (except |
170 | past end of file which can be slow, and | 170 | * SMB Write past end of file which can be slow, and |
171 | blocking lock operations). NFS waits slightly longer | 171 | * blocking lock operations). NFS waits slightly longer |
172 | than CIFS, but this can make it take longer for | 172 | * than CIFS, but this can make it take longer for |
173 | nonresponsive servers to be detected and 15 seconds | 173 | * nonresponsive servers to be detected and 15 seconds |
174 | is more than enough time for modern networks to | 174 | * is more than enough time for modern networks to |
175 | send a packet. In most cases if we fail to send | 175 | * send a packet. In most cases if we fail to send |
176 | after the retries we will kill the socket and | 176 | * after the retries we will kill the socket and |
177 | reconnect which may clear the network problem. | 177 | * reconnect which may clear the network problem. |
178 | */ | 178 | */ |
179 | if ((i >= 14) || (!server->noblocksnd && (i > 2))) { | 179 | if ((i >= 14) || (!server->noblocksnd && (i > 2))) { |
180 | cERROR(1, "sends on sock %p stuck for 15 seconds", | 180 | cERROR(1, "sends on sock %p stuck for 15 seconds", |
181 | ssocket); | 181 | ssocket); |
@@ -235,9 +235,8 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | |||
235 | else | 235 | else |
236 | rc = 0; | 236 | rc = 0; |
237 | 237 | ||
238 | /* Don't want to modify the buffer as a | 238 | /* Don't want to modify the buffer as a side effect of this call. */ |
239 | side effect of this call. */ | 239 | *buf_len = cpu_to_be32(smb_buf_length); |
240 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buf_length); | ||
241 | 240 | ||
242 | return rc; | 241 | return rc; |
243 | } | 242 | } |
@@ -349,6 +348,33 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ) | |||
349 | return 0; | 348 | return 0; |
350 | } | 349 | } |
351 | 350 | ||
351 | static int | ||
352 | cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov, | ||
353 | unsigned int nvec, struct mid_q_entry **ret_mid) | ||
354 | { | ||
355 | int rc; | ||
356 | struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base; | ||
357 | struct mid_q_entry *mid; | ||
358 | |||
359 | /* enable signing if server requires it */ | ||
360 | if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
361 | hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
362 | |||
363 | mid = AllocMidQEntry(hdr, server); | ||
364 | if (mid == NULL) | ||
365 | return -ENOMEM; | ||
366 | |||
367 | /* put it on the pending_mid_q */ | ||
368 | spin_lock(&GlobalMid_Lock); | ||
369 | list_add_tail(&mid->qhead, &server->pending_mid_q); | ||
370 | spin_unlock(&GlobalMid_Lock); | ||
371 | |||
372 | rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number); | ||
373 | if (rc) | ||
374 | delete_mid(mid); | ||
375 | *ret_mid = mid; | ||
376 | return rc; | ||
377 | } | ||
352 | 378 | ||
353 | /* | 379 | /* |
354 | * Send a SMB request and set the callback function in the mid to handle | 380 | * Send a SMB request and set the callback function in the mid to handle |
@@ -361,34 +387,18 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, | |||
361 | { | 387 | { |
362 | int rc; | 388 | int rc; |
363 | struct mid_q_entry *mid; | 389 | struct mid_q_entry *mid; |
364 | struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base; | ||
365 | 390 | ||
366 | rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0); | 391 | rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0); |
367 | if (rc) | 392 | if (rc) |
368 | return rc; | 393 | return rc; |
369 | 394 | ||
370 | /* enable signing if server requires it */ | ||
371 | if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
372 | hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
373 | |||
374 | mutex_lock(&server->srv_mutex); | 395 | mutex_lock(&server->srv_mutex); |
375 | mid = AllocMidQEntry(hdr, server); | 396 | rc = cifs_setup_async_request(server, iov, nvec, &mid); |
376 | if (mid == NULL) { | 397 | if (rc) { |
377 | mutex_unlock(&server->srv_mutex); | 398 | mutex_unlock(&server->srv_mutex); |
378 | cifs_add_credits(server, 1); | 399 | cifs_add_credits(server, 1); |
379 | wake_up(&server->request_q); | 400 | wake_up(&server->request_q); |
380 | return -ENOMEM; | 401 | return rc; |
381 | } | ||
382 | |||
383 | /* put it on the pending_mid_q */ | ||
384 | spin_lock(&GlobalMid_Lock); | ||
385 | list_add_tail(&mid->qhead, &server->pending_mid_q); | ||
386 | spin_unlock(&GlobalMid_Lock); | ||
387 | |||
388 | rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number); | ||
389 | if (rc) { | ||
390 | mutex_unlock(&server->srv_mutex); | ||
391 | goto out_err; | ||
392 | } | 402 | } |
393 | 403 | ||
394 | mid->receive = receive; | 404 | mid->receive = receive; |
@@ -424,14 +434,14 @@ out_err: | |||
424 | */ | 434 | */ |
425 | int | 435 | int |
426 | SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, | 436 | SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, |
427 | struct smb_hdr *in_buf, int flags) | 437 | char *in_buf, int flags) |
428 | { | 438 | { |
429 | int rc; | 439 | int rc; |
430 | struct kvec iov[1]; | 440 | struct kvec iov[1]; |
431 | int resp_buf_type; | 441 | int resp_buf_type; |
432 | 442 | ||
433 | iov[0].iov_base = (char *)in_buf; | 443 | iov[0].iov_base = in_buf; |
434 | iov[0].iov_len = be32_to_cpu(in_buf->smb_buf_length) + 4; | 444 | iov[0].iov_len = get_rfc1002_length(in_buf) + 4; |
435 | flags |= CIFS_NO_RESP; | 445 | flags |= CIFS_NO_RESP; |
436 | rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags); | 446 | rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags); |
437 | cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc); | 447 | cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc); |
@@ -514,7 +524,7 @@ int | |||
514 | cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, | 524 | cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, |
515 | bool log_error) | 525 | bool log_error) |
516 | { | 526 | { |
517 | unsigned int len = be32_to_cpu(mid->resp_buf->smb_buf_length) + 4; | 527 | unsigned int len = get_rfc1002_length(mid->resp_buf) + 4; |
518 | 528 | ||
519 | dump_smb(mid->resp_buf, min_t(u32, 92, len)); | 529 | dump_smb(mid->resp_buf, min_t(u32, 92, len)); |
520 | 530 | ||
@@ -534,6 +544,24 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, | |||
534 | return map_smb_to_linux_error(mid->resp_buf, log_error); | 544 | return map_smb_to_linux_error(mid->resp_buf, log_error); |
535 | } | 545 | } |
536 | 546 | ||
547 | static int | ||
548 | cifs_setup_request(struct cifs_ses *ses, struct kvec *iov, | ||
549 | unsigned int nvec, struct mid_q_entry **ret_mid) | ||
550 | { | ||
551 | int rc; | ||
552 | struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base; | ||
553 | struct mid_q_entry *mid; | ||
554 | |||
555 | rc = allocate_mid(ses, hdr, &mid); | ||
556 | if (rc) | ||
557 | return rc; | ||
558 | rc = cifs_sign_smb2(iov, nvec, ses->server, &mid->sequence_number); | ||
559 | if (rc) | ||
560 | delete_mid(mid); | ||
561 | *ret_mid = mid; | ||
562 | return rc; | ||
563 | } | ||
564 | |||
537 | int | 565 | int |
538 | SendReceive2(const unsigned int xid, struct cifs_ses *ses, | 566 | SendReceive2(const unsigned int xid, struct cifs_ses *ses, |
539 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, | 567 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, |
@@ -542,53 +570,51 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
542 | int rc = 0; | 570 | int rc = 0; |
543 | int long_op; | 571 | int long_op; |
544 | struct mid_q_entry *midQ; | 572 | struct mid_q_entry *midQ; |
545 | struct smb_hdr *in_buf = iov[0].iov_base; | 573 | char *buf = iov[0].iov_base; |
546 | 574 | ||
547 | long_op = flags & CIFS_TIMEOUT_MASK; | 575 | long_op = flags & CIFS_TIMEOUT_MASK; |
548 | 576 | ||
549 | *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ | 577 | *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ |
550 | 578 | ||
551 | if ((ses == NULL) || (ses->server == NULL)) { | 579 | if ((ses == NULL) || (ses->server == NULL)) { |
552 | cifs_small_buf_release(in_buf); | 580 | cifs_small_buf_release(buf); |
553 | cERROR(1, "Null session"); | 581 | cERROR(1, "Null session"); |
554 | return -EIO; | 582 | return -EIO; |
555 | } | 583 | } |
556 | 584 | ||
557 | if (ses->server->tcpStatus == CifsExiting) { | 585 | if (ses->server->tcpStatus == CifsExiting) { |
558 | cifs_small_buf_release(in_buf); | 586 | cifs_small_buf_release(buf); |
559 | return -ENOENT; | 587 | return -ENOENT; |
560 | } | 588 | } |
561 | 589 | ||
562 | /* Ensure that we do not send more than 50 overlapping requests | 590 | /* |
563 | to the same server. We may make this configurable later or | 591 | * Ensure that we do not send more than 50 overlapping requests |
564 | use ses->maxReq */ | 592 | * to the same server. We may make this configurable later or |
593 | * use ses->maxReq. | ||
594 | */ | ||
565 | 595 | ||
566 | rc = wait_for_free_request(ses->server, long_op); | 596 | rc = wait_for_free_request(ses->server, long_op); |
567 | if (rc) { | 597 | if (rc) { |
568 | cifs_small_buf_release(in_buf); | 598 | cifs_small_buf_release(buf); |
569 | return rc; | 599 | return rc; |
570 | } | 600 | } |
571 | 601 | ||
572 | /* make sure that we sign in the same order that we send on this socket | 602 | /* |
573 | and avoid races inside tcp sendmsg code that could cause corruption | 603 | * Make sure that we sign in the same order that we send on this socket |
574 | of smb data */ | 604 | * and avoid races inside tcp sendmsg code that could cause corruption |
605 | * of smb data. | ||
606 | */ | ||
575 | 607 | ||
576 | mutex_lock(&ses->server->srv_mutex); | 608 | mutex_lock(&ses->server->srv_mutex); |
577 | 609 | ||
578 | rc = allocate_mid(ses, in_buf, &midQ); | 610 | rc = cifs_setup_request(ses, iov, n_vec, &midQ); |
579 | if (rc) { | 611 | if (rc) { |
580 | mutex_unlock(&ses->server->srv_mutex); | 612 | mutex_unlock(&ses->server->srv_mutex); |
581 | cifs_small_buf_release(in_buf); | 613 | cifs_small_buf_release(buf); |
582 | /* Update # of requests on wire to server */ | 614 | /* Update # of requests on wire to server */ |
583 | cifs_add_credits(ses->server, 1); | 615 | cifs_add_credits(ses->server, 1); |
584 | return rc; | 616 | return rc; |
585 | } | 617 | } |
586 | rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); | ||
587 | if (rc) { | ||
588 | mutex_unlock(&ses->server->srv_mutex); | ||
589 | cifs_small_buf_release(in_buf); | ||
590 | goto out; | ||
591 | } | ||
592 | 618 | ||
593 | midQ->midState = MID_REQUEST_SUBMITTED; | 619 | midQ->midState = MID_REQUEST_SUBMITTED; |
594 | cifs_in_send_inc(ses->server); | 620 | cifs_in_send_inc(ses->server); |
@@ -599,30 +625,30 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
599 | mutex_unlock(&ses->server->srv_mutex); | 625 | mutex_unlock(&ses->server->srv_mutex); |
600 | 626 | ||
601 | if (rc < 0) { | 627 | if (rc < 0) { |
602 | cifs_small_buf_release(in_buf); | 628 | cifs_small_buf_release(buf); |
603 | goto out; | 629 | goto out; |
604 | } | 630 | } |
605 | 631 | ||
606 | if (long_op == CIFS_ASYNC_OP) { | 632 | if (long_op == CIFS_ASYNC_OP) { |
607 | cifs_small_buf_release(in_buf); | 633 | cifs_small_buf_release(buf); |
608 | goto out; | 634 | goto out; |
609 | } | 635 | } |
610 | 636 | ||
611 | rc = wait_for_response(ses->server, midQ); | 637 | rc = wait_for_response(ses->server, midQ); |
612 | if (rc != 0) { | 638 | if (rc != 0) { |
613 | send_nt_cancel(ses->server, in_buf, midQ); | 639 | send_nt_cancel(ses->server, (struct smb_hdr *)buf, midQ); |
614 | spin_lock(&GlobalMid_Lock); | 640 | spin_lock(&GlobalMid_Lock); |
615 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | 641 | if (midQ->midState == MID_REQUEST_SUBMITTED) { |
616 | midQ->callback = DeleteMidQEntry; | 642 | midQ->callback = DeleteMidQEntry; |
617 | spin_unlock(&GlobalMid_Lock); | 643 | spin_unlock(&GlobalMid_Lock); |
618 | cifs_small_buf_release(in_buf); | 644 | cifs_small_buf_release(buf); |
619 | cifs_add_credits(ses->server, 1); | 645 | cifs_add_credits(ses->server, 1); |
620 | return rc; | 646 | return rc; |
621 | } | 647 | } |
622 | spin_unlock(&GlobalMid_Lock); | 648 | spin_unlock(&GlobalMid_Lock); |
623 | } | 649 | } |
624 | 650 | ||
625 | cifs_small_buf_release(in_buf); | 651 | cifs_small_buf_release(buf); |
626 | 652 | ||
627 | rc = cifs_sync_mid_result(midQ, ses->server); | 653 | rc = cifs_sync_mid_result(midQ, ses->server); |
628 | if (rc != 0) { | 654 | if (rc != 0) { |
@@ -636,8 +662,9 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
636 | goto out; | 662 | goto out; |
637 | } | 663 | } |
638 | 664 | ||
639 | iov[0].iov_base = (char *)midQ->resp_buf; | 665 | buf = (char *)midQ->resp_buf; |
640 | iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4; | 666 | iov[0].iov_base = buf; |
667 | iov[0].iov_len = get_rfc1002_length(buf) + 4; | ||
641 | if (midQ->largeBuf) | 668 | if (midQ->largeBuf) |
642 | *pRespBufType = CIFS_LARGE_BUFFER; | 669 | *pRespBufType = CIFS_LARGE_BUFFER; |
643 | else | 670 | else |