| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2017, Microsoft Corporation. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Author(s): Long Li <longli@microsoft.com> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 9 | | - * (at your option) any later version. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
|---|
| 14 | | - * the GNU General Public License for more details. |
|---|
| 15 | 6 | */ |
|---|
| 16 | 7 | #include <linux/module.h> |
|---|
| 17 | 8 | #include <linux/highmem.h> |
|---|
| .. | .. |
|---|
| 164 | 155 | #define log_rdma_mr(level, fmt, args...) \ |
|---|
| 165 | 156 | log_rdma(level, LOG_RDMA_MR, fmt, ##args) |
|---|
| 166 | 157 | |
|---|
| 167 | | -/* |
|---|
| 168 | | - * Destroy the transport and related RDMA and memory resources |
|---|
| 169 | | - * Need to go through all the pending counters and make sure on one is using |
|---|
| 170 | | - * the transport while it is destroyed |
|---|
| 171 | | - */ |
|---|
| 172 | | -static void smbd_destroy_rdma_work(struct work_struct *work) |
|---|
| 173 | | -{ |
|---|
| 174 | | - struct smbd_response *response; |
|---|
| 175 | | - struct smbd_connection *info = |
|---|
| 176 | | - container_of(work, struct smbd_connection, destroy_work); |
|---|
| 177 | | - unsigned long flags; |
|---|
| 178 | | - |
|---|
| 179 | | - log_rdma_event(INFO, "destroying qp\n"); |
|---|
| 180 | | - ib_drain_qp(info->id->qp); |
|---|
| 181 | | - rdma_destroy_qp(info->id); |
|---|
| 182 | | - |
|---|
| 183 | | - /* Unblock all I/O waiting on the send queue */ |
|---|
| 184 | | - wake_up_interruptible_all(&info->wait_send_queue); |
|---|
| 185 | | - |
|---|
| 186 | | - log_rdma_event(INFO, "cancelling idle timer\n"); |
|---|
| 187 | | - cancel_delayed_work_sync(&info->idle_timer_work); |
|---|
| 188 | | - log_rdma_event(INFO, "cancelling send immediate work\n"); |
|---|
| 189 | | - cancel_delayed_work_sync(&info->send_immediate_work); |
|---|
| 190 | | - |
|---|
| 191 | | - log_rdma_event(INFO, "wait for all send to finish\n"); |
|---|
| 192 | | - wait_event(info->wait_smbd_send_pending, |
|---|
| 193 | | - info->smbd_send_pending == 0); |
|---|
| 194 | | - |
|---|
| 195 | | - log_rdma_event(INFO, "wait for all recv to finish\n"); |
|---|
| 196 | | - wake_up_interruptible(&info->wait_reassembly_queue); |
|---|
| 197 | | - wait_event(info->wait_smbd_recv_pending, |
|---|
| 198 | | - info->smbd_recv_pending == 0); |
|---|
| 199 | | - |
|---|
| 200 | | - log_rdma_event(INFO, "wait for all send posted to IB to finish\n"); |
|---|
| 201 | | - wait_event(info->wait_send_pending, |
|---|
| 202 | | - atomic_read(&info->send_pending) == 0); |
|---|
| 203 | | - wait_event(info->wait_send_payload_pending, |
|---|
| 204 | | - atomic_read(&info->send_payload_pending) == 0); |
|---|
| 205 | | - |
|---|
| 206 | | - log_rdma_event(INFO, "freeing mr list\n"); |
|---|
| 207 | | - wake_up_interruptible_all(&info->wait_mr); |
|---|
| 208 | | - wait_event(info->wait_for_mr_cleanup, |
|---|
| 209 | | - atomic_read(&info->mr_used_count) == 0); |
|---|
| 210 | | - destroy_mr_list(info); |
|---|
| 211 | | - |
|---|
| 212 | | - /* It's not posssible for upper layer to get to reassembly */ |
|---|
| 213 | | - log_rdma_event(INFO, "drain the reassembly queue\n"); |
|---|
| 214 | | - do { |
|---|
| 215 | | - spin_lock_irqsave(&info->reassembly_queue_lock, flags); |
|---|
| 216 | | - response = _get_first_reassembly(info); |
|---|
| 217 | | - if (response) { |
|---|
| 218 | | - list_del(&response->list); |
|---|
| 219 | | - spin_unlock_irqrestore( |
|---|
| 220 | | - &info->reassembly_queue_lock, flags); |
|---|
| 221 | | - put_receive_buffer(info, response); |
|---|
| 222 | | - } else |
|---|
| 223 | | - spin_unlock_irqrestore(&info->reassembly_queue_lock, flags); |
|---|
| 224 | | - } while (response); |
|---|
| 225 | | - |
|---|
| 226 | | - info->reassembly_data_length = 0; |
|---|
| 227 | | - |
|---|
| 228 | | - log_rdma_event(INFO, "free receive buffers\n"); |
|---|
| 229 | | - wait_event(info->wait_receive_queues, |
|---|
| 230 | | - info->count_receive_queue + info->count_empty_packet_queue |
|---|
| 231 | | - == info->receive_credit_max); |
|---|
| 232 | | - destroy_receive_buffers(info); |
|---|
| 233 | | - |
|---|
| 234 | | - ib_free_cq(info->send_cq); |
|---|
| 235 | | - ib_free_cq(info->recv_cq); |
|---|
| 236 | | - ib_dealloc_pd(info->pd); |
|---|
| 237 | | - rdma_destroy_id(info->id); |
|---|
| 238 | | - |
|---|
| 239 | | - /* free mempools */ |
|---|
| 240 | | - mempool_destroy(info->request_mempool); |
|---|
| 241 | | - kmem_cache_destroy(info->request_cache); |
|---|
| 242 | | - |
|---|
| 243 | | - mempool_destroy(info->response_mempool); |
|---|
| 244 | | - kmem_cache_destroy(info->response_cache); |
|---|
| 245 | | - |
|---|
| 246 | | - info->transport_status = SMBD_DESTROYED; |
|---|
| 247 | | - wake_up_all(&info->wait_destroy); |
|---|
| 248 | | -} |
|---|
| 249 | | - |
|---|
| 250 | | -static int smbd_process_disconnected(struct smbd_connection *info) |
|---|
| 251 | | -{ |
|---|
| 252 | | - schedule_work(&info->destroy_work); |
|---|
| 253 | | - return 0; |
|---|
| 254 | | -} |
|---|
| 255 | | - |
|---|
| 256 | 158 | static void smbd_disconnect_rdma_work(struct work_struct *work) |
|---|
| 257 | 159 | { |
|---|
| 258 | 160 | struct smbd_connection *info = |
|---|
| .. | .. |
|---|
| 319 | 221 | } |
|---|
| 320 | 222 | |
|---|
| 321 | 223 | info->transport_status = SMBD_DISCONNECTED; |
|---|
| 322 | | - smbd_process_disconnected(info); |
|---|
| 224 | + wake_up_interruptible(&info->disconn_wait); |
|---|
| 225 | + wake_up_interruptible(&info->wait_reassembly_queue); |
|---|
| 226 | + wake_up_interruptible_all(&info->wait_send_queue); |
|---|
| 323 | 227 | break; |
|---|
| 324 | 228 | |
|---|
| 325 | 229 | default: |
|---|
| .. | .. |
|---|
| 380 | 284 | request->sge[i].length, |
|---|
| 381 | 285 | DMA_TO_DEVICE); |
|---|
| 382 | 286 | |
|---|
| 383 | | - if (request->has_payload) { |
|---|
| 384 | | - if (atomic_dec_and_test(&request->info->send_payload_pending)) |
|---|
| 385 | | - wake_up(&request->info->wait_send_payload_pending); |
|---|
| 386 | | - } else { |
|---|
| 387 | | - if (atomic_dec_and_test(&request->info->send_pending)) |
|---|
| 388 | | - wake_up(&request->info->wait_send_pending); |
|---|
| 389 | | - } |
|---|
| 287 | + if (atomic_dec_and_test(&request->info->send_pending)) |
|---|
| 288 | + wake_up(&request->info->wait_send_pending); |
|---|
| 289 | + |
|---|
| 290 | + wake_up(&request->info->wait_post_send); |
|---|
| 390 | 291 | |
|---|
| 391 | 292 | mempool_free(request, request->info->request_mempool); |
|---|
| 392 | 293 | } |
|---|
| 393 | 294 | |
|---|
| 394 | 295 | static void dump_smbd_negotiate_resp(struct smbd_negotiate_resp *resp) |
|---|
| 395 | 296 | { |
|---|
| 396 | | - log_rdma_event(INFO, "resp message min_version %u max_version %u " |
|---|
| 397 | | - "negotiated_version %u credits_requested %u " |
|---|
| 398 | | - "credits_granted %u status %u max_readwrite_size %u " |
|---|
| 399 | | - "preferred_send_size %u max_receive_size %u " |
|---|
| 400 | | - "max_fragmented_size %u\n", |
|---|
| 401 | | - resp->min_version, resp->max_version, resp->negotiated_version, |
|---|
| 402 | | - resp->credits_requested, resp->credits_granted, resp->status, |
|---|
| 403 | | - resp->max_readwrite_size, resp->preferred_send_size, |
|---|
| 404 | | - resp->max_receive_size, resp->max_fragmented_size); |
|---|
| 297 | + log_rdma_event(INFO, "resp message min_version %u max_version %u negotiated_version %u credits_requested %u credits_granted %u status %u max_readwrite_size %u preferred_send_size %u max_receive_size %u max_fragmented_size %u\n", |
|---|
| 298 | + resp->min_version, resp->max_version, |
|---|
| 299 | + resp->negotiated_version, resp->credits_requested, |
|---|
| 300 | + resp->credits_granted, resp->status, |
|---|
| 301 | + resp->max_readwrite_size, resp->preferred_send_size, |
|---|
| 302 | + resp->max_receive_size, resp->max_fragmented_size); |
|---|
| 405 | 303 | } |
|---|
| 406 | 304 | |
|---|
| 407 | 305 | /* |
|---|
| .. | .. |
|---|
| 479 | 377 | return true; |
|---|
| 480 | 378 | } |
|---|
| 481 | 379 | |
|---|
| 482 | | -/* |
|---|
| 483 | | - * Check and schedule to send an immediate packet |
|---|
| 484 | | - * This is used to extend credtis to remote peer to keep the transport busy |
|---|
| 485 | | - */ |
|---|
| 486 | | -static void check_and_send_immediate(struct smbd_connection *info) |
|---|
| 487 | | -{ |
|---|
| 488 | | - if (info->transport_status != SMBD_CONNECTED) |
|---|
| 489 | | - return; |
|---|
| 490 | | - |
|---|
| 491 | | - info->send_immediate = true; |
|---|
| 492 | | - |
|---|
| 493 | | - /* |
|---|
| 494 | | - * Promptly send a packet if our peer is running low on receive |
|---|
| 495 | | - * credits |
|---|
| 496 | | - */ |
|---|
| 497 | | - if (atomic_read(&info->receive_credits) < |
|---|
| 498 | | - info->receive_credit_target - 1) |
|---|
| 499 | | - queue_delayed_work( |
|---|
| 500 | | - info->workqueue, &info->send_immediate_work, 0); |
|---|
| 501 | | -} |
|---|
| 502 | | - |
|---|
| 503 | 380 | static void smbd_post_send_credits(struct work_struct *work) |
|---|
| 504 | 381 | { |
|---|
| 505 | 382 | int ret = 0; |
|---|
| .. | .. |
|---|
| 549 | 426 | info->new_credits_offered += ret; |
|---|
| 550 | 427 | spin_unlock(&info->lock_new_credits_offered); |
|---|
| 551 | 428 | |
|---|
| 552 | | - atomic_add(ret, &info->receive_credits); |
|---|
| 553 | | - |
|---|
| 554 | | - /* Check if we can post new receive and grant credits to peer */ |
|---|
| 555 | | - check_and_send_immediate(info); |
|---|
| 556 | | -} |
|---|
| 557 | | - |
|---|
| 558 | | -static void smbd_recv_done_work(struct work_struct *work) |
|---|
| 559 | | -{ |
|---|
| 560 | | - struct smbd_connection *info = |
|---|
| 561 | | - container_of(work, struct smbd_connection, recv_done_work); |
|---|
| 562 | | - |
|---|
| 563 | | - /* |
|---|
| 564 | | - * We may have new send credits granted from remote peer |
|---|
| 565 | | - * If any sender is blcoked on lack of credets, unblock it |
|---|
| 566 | | - */ |
|---|
| 567 | | - if (atomic_read(&info->send_credits)) |
|---|
| 568 | | - wake_up_interruptible(&info->wait_send_queue); |
|---|
| 569 | | - |
|---|
| 570 | | - /* |
|---|
| 571 | | - * Check if we need to send something to remote peer to |
|---|
| 572 | | - * grant more credits or respond to KEEP_ALIVE packet |
|---|
| 573 | | - */ |
|---|
| 574 | | - check_and_send_immediate(info); |
|---|
| 429 | + /* Promptly send an immediate packet as defined in [MS-SMBD] 3.1.1.1 */ |
|---|
| 430 | + info->send_immediate = true; |
|---|
| 431 | + if (atomic_read(&info->receive_credits) < |
|---|
| 432 | + info->receive_credit_target - 1) { |
|---|
| 433 | + if (info->keep_alive_requested == KEEP_ALIVE_PENDING || |
|---|
| 434 | + info->send_immediate) { |
|---|
| 435 | + log_keep_alive(INFO, "send an empty message\n"); |
|---|
| 436 | + smbd_post_send_empty(info); |
|---|
| 437 | + } |
|---|
| 438 | + } |
|---|
| 575 | 439 | } |
|---|
| 576 | 440 | |
|---|
| 577 | 441 | /* Called from softirq, when recv is done */ |
|---|
| .. | .. |
|---|
| 583 | 447 | struct smbd_connection *info = response->info; |
|---|
| 584 | 448 | int data_length = 0; |
|---|
| 585 | 449 | |
|---|
| 586 | | - log_rdma_recv(INFO, "response=%p type=%d wc status=%d wc opcode %d " |
|---|
| 587 | | - "byte_len=%d pkey_index=%x\n", |
|---|
| 588 | | - response, response->type, wc->status, wc->opcode, |
|---|
| 589 | | - wc->byte_len, wc->pkey_index); |
|---|
| 450 | + log_rdma_recv(INFO, "response=%p type=%d wc status=%d wc opcode %d byte_len=%d pkey_index=%x\n", |
|---|
| 451 | + response, response->type, wc->status, wc->opcode, |
|---|
| 452 | + wc->byte_len, wc->pkey_index); |
|---|
| 590 | 453 | |
|---|
| 591 | 454 | if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) { |
|---|
| 592 | 455 | log_rdma_recv(INFO, "wc->status=%d opcode=%d\n", |
|---|
| .. | .. |
|---|
| 642 | 505 | atomic_dec(&info->receive_credits); |
|---|
| 643 | 506 | info->receive_credit_target = |
|---|
| 644 | 507 | le16_to_cpu(data_transfer->credits_requested); |
|---|
| 645 | | - atomic_add(le16_to_cpu(data_transfer->credits_granted), |
|---|
| 646 | | - &info->send_credits); |
|---|
| 508 | + if (le16_to_cpu(data_transfer->credits_granted)) { |
|---|
| 509 | + atomic_add(le16_to_cpu(data_transfer->credits_granted), |
|---|
| 510 | + &info->send_credits); |
|---|
| 511 | + /* |
|---|
| 512 | + * We have new send credits granted from remote peer |
|---|
| 513 | + * If any sender is waiting for credits, unblock it |
|---|
| 514 | + */ |
|---|
| 515 | + wake_up_interruptible(&info->wait_send_queue); |
|---|
| 516 | + } |
|---|
| 647 | 517 | |
|---|
| 648 | | - log_incoming(INFO, "data flags %d data_offset %d " |
|---|
| 649 | | - "data_length %d remaining_data_length %d\n", |
|---|
| 650 | | - le16_to_cpu(data_transfer->flags), |
|---|
| 651 | | - le32_to_cpu(data_transfer->data_offset), |
|---|
| 652 | | - le32_to_cpu(data_transfer->data_length), |
|---|
| 653 | | - le32_to_cpu(data_transfer->remaining_data_length)); |
|---|
| 518 | + log_incoming(INFO, "data flags %d data_offset %d data_length %d remaining_data_length %d\n", |
|---|
| 519 | + le16_to_cpu(data_transfer->flags), |
|---|
| 520 | + le32_to_cpu(data_transfer->data_offset), |
|---|
| 521 | + le32_to_cpu(data_transfer->data_length), |
|---|
| 522 | + le32_to_cpu(data_transfer->remaining_data_length)); |
|---|
| 654 | 523 | |
|---|
| 655 | 524 | /* Send a KEEP_ALIVE response right away if requested */ |
|---|
| 656 | 525 | info->keep_alive_requested = KEEP_ALIVE_NONE; |
|---|
| .. | .. |
|---|
| 659 | 528 | info->keep_alive_requested = KEEP_ALIVE_PENDING; |
|---|
| 660 | 529 | } |
|---|
| 661 | 530 | |
|---|
| 662 | | - queue_work(info->workqueue, &info->recv_done_work); |
|---|
| 663 | 531 | return; |
|---|
| 664 | 532 | |
|---|
| 665 | 533 | default: |
|---|
| .. | .. |
|---|
| 759 | 627 | } |
|---|
| 760 | 628 | |
|---|
| 761 | 629 | if (!frwr_is_supported(&info->id->device->attrs)) { |
|---|
| 762 | | - log_rdma_event(ERR, |
|---|
| 763 | | - "Fast Registration Work Requests " |
|---|
| 764 | | - "(FRWR) is not supported\n"); |
|---|
| 765 | | - log_rdma_event(ERR, |
|---|
| 766 | | - "Device capability flags = %llx " |
|---|
| 767 | | - "max_fast_reg_page_list_len = %u\n", |
|---|
| 768 | | - info->id->device->attrs.device_cap_flags, |
|---|
| 769 | | - info->id->device->attrs.max_fast_reg_page_list_len); |
|---|
| 630 | + log_rdma_event(ERR, "Fast Registration Work Requests (FRWR) is not supported\n"); |
|---|
| 631 | + log_rdma_event(ERR, "Device capability flags = %llx max_fast_reg_page_list_len = %u\n", |
|---|
| 632 | + info->id->device->attrs.device_cap_flags, |
|---|
| 633 | + info->id->device->attrs.max_fast_reg_page_list_len); |
|---|
| 770 | 634 | rc = -EPROTONOSUPPORT; |
|---|
| 771 | 635 | goto out2; |
|---|
| 772 | 636 | } |
|---|
| .. | .. |
|---|
| 852 | 716 | request->sge[0].addr, |
|---|
| 853 | 717 | request->sge[0].length, request->sge[0].lkey); |
|---|
| 854 | 718 | |
|---|
| 855 | | - request->has_payload = false; |
|---|
| 856 | 719 | atomic_inc(&info->send_pending); |
|---|
| 857 | 720 | rc = ib_post_send(info->id->qp, &send_wr, NULL); |
|---|
| 858 | 721 | if (!rc) |
|---|
| .. | .. |
|---|
| 909 | 772 | return 0; |
|---|
| 910 | 773 | } |
|---|
| 911 | 774 | |
|---|
| 912 | | -/* |
|---|
| 913 | | - * Build and prepare the SMBD packet header |
|---|
| 914 | | - * This function waits for avaialbe send credits and build a SMBD packet |
|---|
| 915 | | - * header. The caller then optional append payload to the packet after |
|---|
| 916 | | - * the header |
|---|
| 917 | | - * intput values |
|---|
| 918 | | - * size: the size of the payload |
|---|
| 919 | | - * remaining_data_length: remaining data to send if this is part of a |
|---|
| 920 | | - * fragmented packet |
|---|
| 921 | | - * output values |
|---|
| 922 | | - * request_out: the request allocated from this function |
|---|
| 923 | | - * return values: 0 on success, otherwise actual error code returned |
|---|
| 924 | | - */ |
|---|
| 925 | | -static int smbd_create_header(struct smbd_connection *info, |
|---|
| 926 | | - int size, int remaining_data_length, |
|---|
| 927 | | - struct smbd_request **request_out) |
|---|
| 928 | | -{ |
|---|
| 929 | | - struct smbd_request *request; |
|---|
| 930 | | - struct smbd_data_transfer *packet; |
|---|
| 931 | | - int header_length; |
|---|
| 932 | | - int rc; |
|---|
| 933 | | - |
|---|
| 934 | | - /* Wait for send credits. A SMBD packet needs one credit */ |
|---|
| 935 | | - rc = wait_event_interruptible(info->wait_send_queue, |
|---|
| 936 | | - atomic_read(&info->send_credits) > 0 || |
|---|
| 937 | | - info->transport_status != SMBD_CONNECTED); |
|---|
| 938 | | - if (rc) |
|---|
| 939 | | - return rc; |
|---|
| 940 | | - |
|---|
| 941 | | - if (info->transport_status != SMBD_CONNECTED) { |
|---|
| 942 | | - log_outgoing(ERR, "disconnected not sending\n"); |
|---|
| 943 | | - return -ENOENT; |
|---|
| 944 | | - } |
|---|
| 945 | | - atomic_dec(&info->send_credits); |
|---|
| 946 | | - |
|---|
| 947 | | - request = mempool_alloc(info->request_mempool, GFP_KERNEL); |
|---|
| 948 | | - if (!request) { |
|---|
| 949 | | - rc = -ENOMEM; |
|---|
| 950 | | - goto err; |
|---|
| 951 | | - } |
|---|
| 952 | | - |
|---|
| 953 | | - request->info = info; |
|---|
| 954 | | - |
|---|
| 955 | | - /* Fill in the packet header */ |
|---|
| 956 | | - packet = smbd_request_payload(request); |
|---|
| 957 | | - packet->credits_requested = cpu_to_le16(info->send_credit_target); |
|---|
| 958 | | - packet->credits_granted = |
|---|
| 959 | | - cpu_to_le16(manage_credits_prior_sending(info)); |
|---|
| 960 | | - info->send_immediate = false; |
|---|
| 961 | | - |
|---|
| 962 | | - packet->flags = 0; |
|---|
| 963 | | - if (manage_keep_alive_before_sending(info)) |
|---|
| 964 | | - packet->flags |= cpu_to_le16(SMB_DIRECT_RESPONSE_REQUESTED); |
|---|
| 965 | | - |
|---|
| 966 | | - packet->reserved = 0; |
|---|
| 967 | | - if (!size) |
|---|
| 968 | | - packet->data_offset = 0; |
|---|
| 969 | | - else |
|---|
| 970 | | - packet->data_offset = cpu_to_le32(24); |
|---|
| 971 | | - packet->data_length = cpu_to_le32(size); |
|---|
| 972 | | - packet->remaining_data_length = cpu_to_le32(remaining_data_length); |
|---|
| 973 | | - packet->padding = 0; |
|---|
| 974 | | - |
|---|
| 975 | | - log_outgoing(INFO, "credits_requested=%d credits_granted=%d " |
|---|
| 976 | | - "data_offset=%d data_length=%d remaining_data_length=%d\n", |
|---|
| 977 | | - le16_to_cpu(packet->credits_requested), |
|---|
| 978 | | - le16_to_cpu(packet->credits_granted), |
|---|
| 979 | | - le32_to_cpu(packet->data_offset), |
|---|
| 980 | | - le32_to_cpu(packet->data_length), |
|---|
| 981 | | - le32_to_cpu(packet->remaining_data_length)); |
|---|
| 982 | | - |
|---|
| 983 | | - /* Map the packet to DMA */ |
|---|
| 984 | | - header_length = sizeof(struct smbd_data_transfer); |
|---|
| 985 | | - /* If this is a packet without payload, don't send padding */ |
|---|
| 986 | | - if (!size) |
|---|
| 987 | | - header_length = offsetof(struct smbd_data_transfer, padding); |
|---|
| 988 | | - |
|---|
| 989 | | - request->num_sge = 1; |
|---|
| 990 | | - request->sge[0].addr = ib_dma_map_single(info->id->device, |
|---|
| 991 | | - (void *)packet, |
|---|
| 992 | | - header_length, |
|---|
| 993 | | - DMA_BIDIRECTIONAL); |
|---|
| 994 | | - if (ib_dma_mapping_error(info->id->device, request->sge[0].addr)) { |
|---|
| 995 | | - mempool_free(request, info->request_mempool); |
|---|
| 996 | | - rc = -EIO; |
|---|
| 997 | | - goto err; |
|---|
| 998 | | - } |
|---|
| 999 | | - |
|---|
| 1000 | | - request->sge[0].length = header_length; |
|---|
| 1001 | | - request->sge[0].lkey = info->pd->local_dma_lkey; |
|---|
| 1002 | | - |
|---|
| 1003 | | - *request_out = request; |
|---|
| 1004 | | - return 0; |
|---|
| 1005 | | - |
|---|
| 1006 | | -err: |
|---|
| 1007 | | - atomic_inc(&info->send_credits); |
|---|
| 1008 | | - return rc; |
|---|
| 1009 | | -} |
|---|
| 1010 | | - |
|---|
| 1011 | | -static void smbd_destroy_header(struct smbd_connection *info, |
|---|
| 1012 | | - struct smbd_request *request) |
|---|
| 1013 | | -{ |
|---|
| 1014 | | - |
|---|
| 1015 | | - ib_dma_unmap_single(info->id->device, |
|---|
| 1016 | | - request->sge[0].addr, |
|---|
| 1017 | | - request->sge[0].length, |
|---|
| 1018 | | - DMA_TO_DEVICE); |
|---|
| 1019 | | - mempool_free(request, info->request_mempool); |
|---|
| 1020 | | - atomic_inc(&info->send_credits); |
|---|
| 1021 | | -} |
|---|
| 1022 | | - |
|---|
| 1023 | 775 | /* Post the send request */ |
|---|
| 1024 | 776 | static int smbd_post_send(struct smbd_connection *info, |
|---|
| 1025 | | - struct smbd_request *request, bool has_payload) |
|---|
| 777 | + struct smbd_request *request) |
|---|
| 1026 | 778 | { |
|---|
| 1027 | 779 | struct ib_send_wr send_wr; |
|---|
| 1028 | 780 | int rc, i; |
|---|
| .. | .. |
|---|
| 1047 | 799 | send_wr.opcode = IB_WR_SEND; |
|---|
| 1048 | 800 | send_wr.send_flags = IB_SEND_SIGNALED; |
|---|
| 1049 | 801 | |
|---|
| 1050 | | - if (has_payload) { |
|---|
| 1051 | | - request->has_payload = true; |
|---|
| 1052 | | - atomic_inc(&info->send_payload_pending); |
|---|
| 1053 | | - } else { |
|---|
| 1054 | | - request->has_payload = false; |
|---|
| 1055 | | - atomic_inc(&info->send_pending); |
|---|
| 1056 | | - } |
|---|
| 1057 | | - |
|---|
| 1058 | 802 | rc = ib_post_send(info->id->qp, &send_wr, NULL); |
|---|
| 1059 | 803 | if (rc) { |
|---|
| 1060 | 804 | log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc); |
|---|
| 1061 | | - if (has_payload) { |
|---|
| 1062 | | - if (atomic_dec_and_test(&info->send_payload_pending)) |
|---|
| 1063 | | - wake_up(&info->wait_send_payload_pending); |
|---|
| 1064 | | - } else { |
|---|
| 1065 | | - if (atomic_dec_and_test(&info->send_pending)) |
|---|
| 1066 | | - wake_up(&info->wait_send_pending); |
|---|
| 1067 | | - } |
|---|
| 1068 | 805 | smbd_disconnect_rdma_connection(info); |
|---|
| 806 | + rc = -EAGAIN; |
|---|
| 1069 | 807 | } else |
|---|
| 1070 | 808 | /* Reset timer for idle connection after packet is sent */ |
|---|
| 1071 | 809 | mod_delayed_work(info->workqueue, &info->idle_timer_work, |
|---|
| .. | .. |
|---|
| 1079 | 817 | { |
|---|
| 1080 | 818 | int num_sgs; |
|---|
| 1081 | 819 | int i, rc; |
|---|
| 820 | + int header_length; |
|---|
| 1082 | 821 | struct smbd_request *request; |
|---|
| 822 | + struct smbd_data_transfer *packet; |
|---|
| 823 | + int new_credits; |
|---|
| 1083 | 824 | struct scatterlist *sg; |
|---|
| 1084 | 825 | |
|---|
| 1085 | | - rc = smbd_create_header( |
|---|
| 1086 | | - info, data_length, remaining_data_length, &request); |
|---|
| 826 | +wait_credit: |
|---|
| 827 | + /* Wait for send credits. A SMBD packet needs one credit */ |
|---|
| 828 | + rc = wait_event_interruptible(info->wait_send_queue, |
|---|
| 829 | + atomic_read(&info->send_credits) > 0 || |
|---|
| 830 | + info->transport_status != SMBD_CONNECTED); |
|---|
| 1087 | 831 | if (rc) |
|---|
| 1088 | | - return rc; |
|---|
| 832 | + goto err_wait_credit; |
|---|
| 1089 | 833 | |
|---|
| 834 | + if (info->transport_status != SMBD_CONNECTED) { |
|---|
| 835 | + log_outgoing(ERR, "disconnected not sending on wait_credit\n"); |
|---|
| 836 | + rc = -EAGAIN; |
|---|
| 837 | + goto err_wait_credit; |
|---|
| 838 | + } |
|---|
| 839 | + if (unlikely(atomic_dec_return(&info->send_credits) < 0)) { |
|---|
| 840 | + atomic_inc(&info->send_credits); |
|---|
| 841 | + goto wait_credit; |
|---|
| 842 | + } |
|---|
| 843 | + |
|---|
| 844 | +wait_send_queue: |
|---|
| 845 | + wait_event(info->wait_post_send, |
|---|
| 846 | + atomic_read(&info->send_pending) < info->send_credit_target || |
|---|
| 847 | + info->transport_status != SMBD_CONNECTED); |
|---|
| 848 | + |
|---|
| 849 | + if (info->transport_status != SMBD_CONNECTED) { |
|---|
| 850 | + log_outgoing(ERR, "disconnected not sending on wait_send_queue\n"); |
|---|
| 851 | + rc = -EAGAIN; |
|---|
| 852 | + goto err_wait_send_queue; |
|---|
| 853 | + } |
|---|
| 854 | + |
|---|
| 855 | + if (unlikely(atomic_inc_return(&info->send_pending) > |
|---|
| 856 | + info->send_credit_target)) { |
|---|
| 857 | + atomic_dec(&info->send_pending); |
|---|
| 858 | + goto wait_send_queue; |
|---|
| 859 | + } |
|---|
| 860 | + |
|---|
| 861 | + request = mempool_alloc(info->request_mempool, GFP_KERNEL); |
|---|
| 862 | + if (!request) { |
|---|
| 863 | + rc = -ENOMEM; |
|---|
| 864 | + goto err_alloc; |
|---|
| 865 | + } |
|---|
| 866 | + |
|---|
| 867 | + request->info = info; |
|---|
| 868 | + |
|---|
| 869 | + /* Fill in the packet header */ |
|---|
| 870 | + packet = smbd_request_payload(request); |
|---|
| 871 | + packet->credits_requested = cpu_to_le16(info->send_credit_target); |
|---|
| 872 | + |
|---|
| 873 | + new_credits = manage_credits_prior_sending(info); |
|---|
| 874 | + atomic_add(new_credits, &info->receive_credits); |
|---|
| 875 | + packet->credits_granted = cpu_to_le16(new_credits); |
|---|
| 876 | + |
|---|
| 877 | + info->send_immediate = false; |
|---|
| 878 | + |
|---|
| 879 | + packet->flags = 0; |
|---|
| 880 | + if (manage_keep_alive_before_sending(info)) |
|---|
| 881 | + packet->flags |= cpu_to_le16(SMB_DIRECT_RESPONSE_REQUESTED); |
|---|
| 882 | + |
|---|
| 883 | + packet->reserved = 0; |
|---|
| 884 | + if (!data_length) |
|---|
| 885 | + packet->data_offset = 0; |
|---|
| 886 | + else |
|---|
| 887 | + packet->data_offset = cpu_to_le32(24); |
|---|
| 888 | + packet->data_length = cpu_to_le32(data_length); |
|---|
| 889 | + packet->remaining_data_length = cpu_to_le32(remaining_data_length); |
|---|
| 890 | + packet->padding = 0; |
|---|
| 891 | + |
|---|
| 892 | + log_outgoing(INFO, "credits_requested=%d credits_granted=%d data_offset=%d data_length=%d remaining_data_length=%d\n", |
|---|
| 893 | + le16_to_cpu(packet->credits_requested), |
|---|
| 894 | + le16_to_cpu(packet->credits_granted), |
|---|
| 895 | + le32_to_cpu(packet->data_offset), |
|---|
| 896 | + le32_to_cpu(packet->data_length), |
|---|
| 897 | + le32_to_cpu(packet->remaining_data_length)); |
|---|
| 898 | + |
|---|
| 899 | + /* Map the packet to DMA */ |
|---|
| 900 | + header_length = sizeof(struct smbd_data_transfer); |
|---|
| 901 | + /* If this is a packet without payload, don't send padding */ |
|---|
| 902 | + if (!data_length) |
|---|
| 903 | + header_length = offsetof(struct smbd_data_transfer, padding); |
|---|
| 904 | + |
|---|
| 905 | + request->num_sge = 1; |
|---|
| 906 | + request->sge[0].addr = ib_dma_map_single(info->id->device, |
|---|
| 907 | + (void *)packet, |
|---|
| 908 | + header_length, |
|---|
| 909 | + DMA_TO_DEVICE); |
|---|
| 910 | + if (ib_dma_mapping_error(info->id->device, request->sge[0].addr)) { |
|---|
| 911 | + rc = -EIO; |
|---|
| 912 | + request->sge[0].addr = 0; |
|---|
| 913 | + goto err_dma; |
|---|
| 914 | + } |
|---|
| 915 | + |
|---|
| 916 | + request->sge[0].length = header_length; |
|---|
| 917 | + request->sge[0].lkey = info->pd->local_dma_lkey; |
|---|
| 918 | + |
|---|
| 919 | + /* Fill in the packet data payload */ |
|---|
| 1090 | 920 | num_sgs = sgl ? sg_nents(sgl) : 0; |
|---|
| 1091 | 921 | for_each_sg(sgl, sg, num_sgs, i) { |
|---|
| 1092 | 922 | request->sge[i+1].addr = |
|---|
| 1093 | 923 | ib_dma_map_page(info->id->device, sg_page(sg), |
|---|
| 1094 | | - sg->offset, sg->length, DMA_BIDIRECTIONAL); |
|---|
| 924 | + sg->offset, sg->length, DMA_TO_DEVICE); |
|---|
| 1095 | 925 | if (ib_dma_mapping_error( |
|---|
| 1096 | 926 | info->id->device, request->sge[i+1].addr)) { |
|---|
| 1097 | 927 | rc = -EIO; |
|---|
| 1098 | 928 | request->sge[i+1].addr = 0; |
|---|
| 1099 | | - goto dma_mapping_failure; |
|---|
| 929 | + goto err_dma; |
|---|
| 1100 | 930 | } |
|---|
| 1101 | 931 | request->sge[i+1].length = sg->length; |
|---|
| 1102 | 932 | request->sge[i+1].lkey = info->pd->local_dma_lkey; |
|---|
| 1103 | 933 | request->num_sge++; |
|---|
| 1104 | 934 | } |
|---|
| 1105 | 935 | |
|---|
| 1106 | | - rc = smbd_post_send(info, request, data_length); |
|---|
| 936 | + rc = smbd_post_send(info, request); |
|---|
| 1107 | 937 | if (!rc) |
|---|
| 1108 | 938 | return 0; |
|---|
| 1109 | 939 | |
|---|
| 1110 | | -dma_mapping_failure: |
|---|
| 1111 | | - for (i = 1; i < request->num_sge; i++) |
|---|
| 940 | +err_dma: |
|---|
| 941 | + for (i = 0; i < request->num_sge; i++) |
|---|
| 1112 | 942 | if (request->sge[i].addr) |
|---|
| 1113 | 943 | ib_dma_unmap_single(info->id->device, |
|---|
| 1114 | 944 | request->sge[i].addr, |
|---|
| 1115 | 945 | request->sge[i].length, |
|---|
| 1116 | 946 | DMA_TO_DEVICE); |
|---|
| 1117 | | - smbd_destroy_header(info, request); |
|---|
| 947 | + mempool_free(request, info->request_mempool); |
|---|
| 948 | + |
|---|
| 949 | + /* roll back receive credits and credits to be offered */ |
|---|
| 950 | + spin_lock(&info->lock_new_credits_offered); |
|---|
| 951 | + info->new_credits_offered += new_credits; |
|---|
| 952 | + spin_unlock(&info->lock_new_credits_offered); |
|---|
| 953 | + atomic_sub(new_credits, &info->receive_credits); |
|---|
| 954 | + |
|---|
| 955 | +err_alloc: |
|---|
| 956 | + if (atomic_dec_and_test(&info->send_pending)) |
|---|
| 957 | + wake_up(&info->wait_send_pending); |
|---|
| 958 | + |
|---|
| 959 | +err_wait_send_queue: |
|---|
| 960 | + /* roll back send credits and pending */ |
|---|
| 961 | + atomic_inc(&info->send_credits); |
|---|
| 962 | + |
|---|
| 963 | +err_wait_credit: |
|---|
| 1118 | 964 | return rc; |
|---|
| 1119 | 965 | } |
|---|
| 1120 | 966 | |
|---|
| .. | .. |
|---|
| 1222 | 1068 | |
|---|
| 1223 | 1069 | response->type = SMBD_NEGOTIATE_RESP; |
|---|
| 1224 | 1070 | rc = smbd_post_recv(info, response); |
|---|
| 1225 | | - log_rdma_event(INFO, |
|---|
| 1226 | | - "smbd_post_recv rc=%d iov.addr=%llx iov.length=%x " |
|---|
| 1227 | | - "iov.lkey=%x\n", |
|---|
| 1228 | | - rc, response->sge.addr, |
|---|
| 1229 | | - response->sge.length, response->sge.lkey); |
|---|
| 1071 | + log_rdma_event(INFO, "smbd_post_recv rc=%d iov.addr=%llx iov.length=%x iov.lkey=%x\n", |
|---|
| 1072 | + rc, response->sge.addr, |
|---|
| 1073 | + response->sge.length, response->sge.lkey); |
|---|
| 1230 | 1074 | if (rc) |
|---|
| 1231 | 1075 | return rc; |
|---|
| 1232 | 1076 | |
|---|
| .. | .. |
|---|
| 1436 | 1280 | mempool_free(response, info->response_mempool); |
|---|
| 1437 | 1281 | } |
|---|
| 1438 | 1282 | |
|---|
| 1439 | | -/* |
|---|
| 1440 | | - * Check and send an immediate or keep alive packet |
|---|
| 1441 | | - * The condition to send those packets are defined in [MS-SMBD] 3.1.1.1 |
|---|
| 1442 | | - * Connection.KeepaliveRequested and Connection.SendImmediate |
|---|
| 1443 | | - * The idea is to extend credits to server as soon as it becomes available |
|---|
| 1444 | | - */ |
|---|
| 1445 | | -static void send_immediate_work(struct work_struct *work) |
|---|
| 1446 | | -{ |
|---|
| 1447 | | - struct smbd_connection *info = container_of( |
|---|
| 1448 | | - work, struct smbd_connection, |
|---|
| 1449 | | - send_immediate_work.work); |
|---|
| 1450 | | - |
|---|
| 1451 | | - if (info->keep_alive_requested == KEEP_ALIVE_PENDING || |
|---|
| 1452 | | - info->send_immediate) { |
|---|
| 1453 | | - log_keep_alive(INFO, "send an empty message\n"); |
|---|
| 1454 | | - smbd_post_send_empty(info); |
|---|
| 1455 | | - } |
|---|
| 1456 | | -} |
|---|
| 1457 | | - |
|---|
| 1458 | 1283 | /* Implement idle connection timer [MS-SMBD] 3.1.6.2 */ |
|---|
| 1459 | 1284 | static void idle_connection_timer(struct work_struct *work) |
|---|
| 1460 | 1285 | { |
|---|
| .. | .. |
|---|
| 1478 | 1303 | info->keep_alive_interval*HZ); |
|---|
| 1479 | 1304 | } |
|---|
| 1480 | 1305 | |
|---|
| 1481 | | -/* Destroy this SMBD connection, called from upper layer */ |
|---|
| 1482 | | -void smbd_destroy(struct smbd_connection *info) |
|---|
| 1306 | +/* |
|---|
| 1307 | + * Destroy the transport and related RDMA and memory resources |
|---|
| 1308 | + * Need to go through all the pending counters and make sure on one is using |
|---|
| 1309 | + * the transport while it is destroyed |
|---|
| 1310 | + */ |
|---|
| 1311 | +void smbd_destroy(struct TCP_Server_Info *server) |
|---|
| 1483 | 1312 | { |
|---|
| 1313 | + struct smbd_connection *info = server->smbd_conn; |
|---|
| 1314 | + struct smbd_response *response; |
|---|
| 1315 | + unsigned long flags; |
|---|
| 1316 | + |
|---|
| 1317 | + if (!info) { |
|---|
| 1318 | + log_rdma_event(INFO, "rdma session already destroyed\n"); |
|---|
| 1319 | + return; |
|---|
| 1320 | + } |
|---|
| 1321 | + |
|---|
| 1484 | 1322 | log_rdma_event(INFO, "destroying rdma session\n"); |
|---|
| 1323 | + if (info->transport_status != SMBD_DISCONNECTED) { |
|---|
| 1324 | + rdma_disconnect(server->smbd_conn->id); |
|---|
| 1325 | + log_rdma_event(INFO, "wait for transport being disconnected\n"); |
|---|
| 1326 | + wait_event_interruptible( |
|---|
| 1327 | + info->disconn_wait, |
|---|
| 1328 | + info->transport_status == SMBD_DISCONNECTED); |
|---|
| 1329 | + } |
|---|
| 1485 | 1330 | |
|---|
| 1486 | | - /* Kick off the disconnection process */ |
|---|
| 1487 | | - smbd_disconnect_rdma_connection(info); |
|---|
| 1331 | + log_rdma_event(INFO, "destroying qp\n"); |
|---|
| 1332 | + ib_drain_qp(info->id->qp); |
|---|
| 1333 | + rdma_destroy_qp(info->id); |
|---|
| 1488 | 1334 | |
|---|
| 1489 | | - log_rdma_event(INFO, "wait for transport being destroyed\n"); |
|---|
| 1490 | | - wait_event(info->wait_destroy, |
|---|
| 1491 | | - info->transport_status == SMBD_DESTROYED); |
|---|
| 1335 | + log_rdma_event(INFO, "cancelling idle timer\n"); |
|---|
| 1336 | + cancel_delayed_work_sync(&info->idle_timer_work); |
|---|
| 1337 | + |
|---|
| 1338 | + log_rdma_event(INFO, "wait for all send posted to IB to finish\n"); |
|---|
| 1339 | + wait_event(info->wait_send_pending, |
|---|
| 1340 | + atomic_read(&info->send_pending) == 0); |
|---|
| 1341 | + |
|---|
| 1342 | + /* It's not posssible for upper layer to get to reassembly */ |
|---|
| 1343 | + log_rdma_event(INFO, "drain the reassembly queue\n"); |
|---|
| 1344 | + do { |
|---|
| 1345 | + spin_lock_irqsave(&info->reassembly_queue_lock, flags); |
|---|
| 1346 | + response = _get_first_reassembly(info); |
|---|
| 1347 | + if (response) { |
|---|
| 1348 | + list_del(&response->list); |
|---|
| 1349 | + spin_unlock_irqrestore( |
|---|
| 1350 | + &info->reassembly_queue_lock, flags); |
|---|
| 1351 | + put_receive_buffer(info, response); |
|---|
| 1352 | + } else |
|---|
| 1353 | + spin_unlock_irqrestore( |
|---|
| 1354 | + &info->reassembly_queue_lock, flags); |
|---|
| 1355 | + } while (response); |
|---|
| 1356 | + info->reassembly_data_length = 0; |
|---|
| 1357 | + |
|---|
| 1358 | + log_rdma_event(INFO, "free receive buffers\n"); |
|---|
| 1359 | + wait_event(info->wait_receive_queues, |
|---|
| 1360 | + info->count_receive_queue + info->count_empty_packet_queue |
|---|
| 1361 | + == info->receive_credit_max); |
|---|
| 1362 | + destroy_receive_buffers(info); |
|---|
| 1363 | + |
|---|
| 1364 | + /* |
|---|
| 1365 | + * For performance reasons, memory registration and deregistration |
|---|
| 1366 | + * are not locked by srv_mutex. It is possible some processes are |
|---|
| 1367 | + * blocked on transport srv_mutex while holding memory registration. |
|---|
| 1368 | + * Release the transport srv_mutex to allow them to hit the failure |
|---|
| 1369 | + * path when sending data, and then release memory registartions. |
|---|
| 1370 | + */ |
|---|
| 1371 | + log_rdma_event(INFO, "freeing mr list\n"); |
|---|
| 1372 | + wake_up_interruptible_all(&info->wait_mr); |
|---|
| 1373 | + while (atomic_read(&info->mr_used_count)) { |
|---|
| 1374 | + mutex_unlock(&server->srv_mutex); |
|---|
| 1375 | + msleep(1000); |
|---|
| 1376 | + mutex_lock(&server->srv_mutex); |
|---|
| 1377 | + } |
|---|
| 1378 | + destroy_mr_list(info); |
|---|
| 1379 | + |
|---|
| 1380 | + ib_free_cq(info->send_cq); |
|---|
| 1381 | + ib_free_cq(info->recv_cq); |
|---|
| 1382 | + ib_dealloc_pd(info->pd); |
|---|
| 1383 | + rdma_destroy_id(info->id); |
|---|
| 1384 | + |
|---|
| 1385 | + /* free mempools */ |
|---|
| 1386 | + mempool_destroy(info->request_mempool); |
|---|
| 1387 | + kmem_cache_destroy(info->request_cache); |
|---|
| 1388 | + |
|---|
| 1389 | + mempool_destroy(info->response_mempool); |
|---|
| 1390 | + kmem_cache_destroy(info->response_cache); |
|---|
| 1391 | + |
|---|
| 1392 | + info->transport_status = SMBD_DESTROYED; |
|---|
| 1492 | 1393 | |
|---|
| 1493 | 1394 | destroy_workqueue(info->workqueue); |
|---|
| 1494 | 1395 | log_rdma_event(INFO, "rdma session destroyed\n"); |
|---|
| 1495 | 1396 | kfree(info); |
|---|
| 1397 | + server->smbd_conn = NULL; |
|---|
| 1496 | 1398 | } |
|---|
| 1497 | 1399 | |
|---|
| 1498 | 1400 | /* |
|---|
| .. | .. |
|---|
| 1514 | 1416 | */ |
|---|
| 1515 | 1417 | if (server->smbd_conn->transport_status == SMBD_CONNECTED) { |
|---|
| 1516 | 1418 | log_rdma_event(INFO, "disconnecting transport\n"); |
|---|
| 1517 | | - smbd_disconnect_rdma_connection(server->smbd_conn); |
|---|
| 1419 | + smbd_destroy(server); |
|---|
| 1518 | 1420 | } |
|---|
| 1519 | | - |
|---|
| 1520 | | - /* wait until the transport is destroyed */ |
|---|
| 1521 | | - if (!wait_event_timeout(server->smbd_conn->wait_destroy, |
|---|
| 1522 | | - server->smbd_conn->transport_status == SMBD_DESTROYED, 5*HZ)) |
|---|
| 1523 | | - return -EAGAIN; |
|---|
| 1524 | | - |
|---|
| 1525 | | - destroy_workqueue(server->smbd_conn->workqueue); |
|---|
| 1526 | | - kfree(server->smbd_conn); |
|---|
| 1527 | 1421 | |
|---|
| 1528 | 1422 | create_conn: |
|---|
| 1529 | 1423 | log_rdma_event(INFO, "creating rdma session\n"); |
|---|
| .. | .. |
|---|
| 1552 | 1446 | char name[MAX_NAME_LEN]; |
|---|
| 1553 | 1447 | int rc; |
|---|
| 1554 | 1448 | |
|---|
| 1555 | | - snprintf(name, MAX_NAME_LEN, "smbd_request_%p", info); |
|---|
| 1449 | + scnprintf(name, MAX_NAME_LEN, "smbd_request_%p", info); |
|---|
| 1556 | 1450 | info->request_cache = |
|---|
| 1557 | 1451 | kmem_cache_create( |
|---|
| 1558 | 1452 | name, |
|---|
| .. | .. |
|---|
| 1568 | 1462 | if (!info->request_mempool) |
|---|
| 1569 | 1463 | goto out1; |
|---|
| 1570 | 1464 | |
|---|
| 1571 | | - snprintf(name, MAX_NAME_LEN, "smbd_response_%p", info); |
|---|
| 1465 | + scnprintf(name, MAX_NAME_LEN, "smbd_response_%p", info); |
|---|
| 1572 | 1466 | info->response_cache = |
|---|
| 1573 | 1467 | kmem_cache_create( |
|---|
| 1574 | 1468 | name, |
|---|
| .. | .. |
|---|
| 1584 | 1478 | if (!info->response_mempool) |
|---|
| 1585 | 1479 | goto out3; |
|---|
| 1586 | 1480 | |
|---|
| 1587 | | - snprintf(name, MAX_NAME_LEN, "smbd_%p", info); |
|---|
| 1481 | + scnprintf(name, MAX_NAME_LEN, "smbd_%p", info); |
|---|
| 1588 | 1482 | info->workqueue = create_workqueue(name); |
|---|
| 1589 | 1483 | if (!info->workqueue) |
|---|
| 1590 | 1484 | goto out4; |
|---|
| .. | .. |
|---|
| 1635 | 1529 | |
|---|
| 1636 | 1530 | if (smbd_send_credit_target > info->id->device->attrs.max_cqe || |
|---|
| 1637 | 1531 | smbd_send_credit_target > info->id->device->attrs.max_qp_wr) { |
|---|
| 1638 | | - log_rdma_event(ERR, |
|---|
| 1639 | | - "consider lowering send_credit_target = %d. " |
|---|
| 1640 | | - "Possible CQE overrun, device " |
|---|
| 1641 | | - "reporting max_cpe %d max_qp_wr %d\n", |
|---|
| 1642 | | - smbd_send_credit_target, |
|---|
| 1643 | | - info->id->device->attrs.max_cqe, |
|---|
| 1644 | | - info->id->device->attrs.max_qp_wr); |
|---|
| 1532 | + log_rdma_event(ERR, "consider lowering send_credit_target = %d. Possible CQE overrun, device reporting max_cpe %d max_qp_wr %d\n", |
|---|
| 1533 | + smbd_send_credit_target, |
|---|
| 1534 | + info->id->device->attrs.max_cqe, |
|---|
| 1535 | + info->id->device->attrs.max_qp_wr); |
|---|
| 1645 | 1536 | goto config_failed; |
|---|
| 1646 | 1537 | } |
|---|
| 1647 | 1538 | |
|---|
| 1648 | 1539 | if (smbd_receive_credit_max > info->id->device->attrs.max_cqe || |
|---|
| 1649 | 1540 | smbd_receive_credit_max > info->id->device->attrs.max_qp_wr) { |
|---|
| 1650 | | - log_rdma_event(ERR, |
|---|
| 1651 | | - "consider lowering receive_credit_max = %d. " |
|---|
| 1652 | | - "Possible CQE overrun, device " |
|---|
| 1653 | | - "reporting max_cpe %d max_qp_wr %d\n", |
|---|
| 1654 | | - smbd_receive_credit_max, |
|---|
| 1655 | | - info->id->device->attrs.max_cqe, |
|---|
| 1656 | | - info->id->device->attrs.max_qp_wr); |
|---|
| 1541 | + log_rdma_event(ERR, "consider lowering receive_credit_max = %d. Possible CQE overrun, device reporting max_cpe %d max_qp_wr %d\n", |
|---|
| 1542 | + smbd_receive_credit_max, |
|---|
| 1543 | + info->id->device->attrs.max_cqe, |
|---|
| 1544 | + info->id->device->attrs.max_qp_wr); |
|---|
| 1657 | 1545 | goto config_failed; |
|---|
| 1658 | 1546 | } |
|---|
| 1659 | 1547 | |
|---|
| .. | .. |
|---|
| 1679 | 1567 | |
|---|
| 1680 | 1568 | info->send_cq = NULL; |
|---|
| 1681 | 1569 | info->recv_cq = NULL; |
|---|
| 1682 | | - info->send_cq = ib_alloc_cq(info->id->device, info, |
|---|
| 1683 | | - info->send_credit_target, 0, IB_POLL_SOFTIRQ); |
|---|
| 1570 | + info->send_cq = |
|---|
| 1571 | + ib_alloc_cq_any(info->id->device, info, |
|---|
| 1572 | + info->send_credit_target, IB_POLL_SOFTIRQ); |
|---|
| 1684 | 1573 | if (IS_ERR(info->send_cq)) { |
|---|
| 1685 | 1574 | info->send_cq = NULL; |
|---|
| 1686 | 1575 | goto alloc_cq_failed; |
|---|
| 1687 | 1576 | } |
|---|
| 1688 | 1577 | |
|---|
| 1689 | | - info->recv_cq = ib_alloc_cq(info->id->device, info, |
|---|
| 1690 | | - info->receive_credit_max, 0, IB_POLL_SOFTIRQ); |
|---|
| 1578 | + info->recv_cq = |
|---|
| 1579 | + ib_alloc_cq_any(info->id->device, info, |
|---|
| 1580 | + info->receive_credit_max, IB_POLL_SOFTIRQ); |
|---|
| 1691 | 1581 | if (IS_ERR(info->recv_cq)) { |
|---|
| 1692 | 1582 | info->recv_cq = NULL; |
|---|
| 1693 | 1583 | goto alloc_cq_failed; |
|---|
| .. | .. |
|---|
| 1726 | 1616 | info->responder_resources); |
|---|
| 1727 | 1617 | |
|---|
| 1728 | 1618 | /* Need to send IRD/ORD in private data for iWARP */ |
|---|
| 1729 | | - info->id->device->get_port_immutable( |
|---|
| 1619 | + info->id->device->ops.get_port_immutable( |
|---|
| 1730 | 1620 | info->id->device, info->id->port_num, &port_immutable); |
|---|
| 1731 | 1621 | if (port_immutable.core_cap_flags & RDMA_CORE_PORT_IWARP) { |
|---|
| 1732 | 1622 | ird_ord_hdr[0] = info->responder_resources; |
|---|
| .. | .. |
|---|
| 1741 | 1631 | conn_param.retry_count = SMBD_CM_RETRY; |
|---|
| 1742 | 1632 | conn_param.rnr_retry_count = SMBD_CM_RNR_RETRY; |
|---|
| 1743 | 1633 | conn_param.flow_control = 0; |
|---|
| 1744 | | - init_waitqueue_head(&info->wait_destroy); |
|---|
| 1745 | 1634 | |
|---|
| 1746 | 1635 | log_rdma_event(INFO, "connecting to IP %pI4 port %d\n", |
|---|
| 1747 | 1636 | &addr_in->sin_addr, port); |
|---|
| 1748 | 1637 | |
|---|
| 1749 | 1638 | init_waitqueue_head(&info->conn_wait); |
|---|
| 1639 | + init_waitqueue_head(&info->disconn_wait); |
|---|
| 1640 | + init_waitqueue_head(&info->wait_reassembly_queue); |
|---|
| 1750 | 1641 | rc = rdma_connect(info->id, &conn_param); |
|---|
| 1751 | 1642 | if (rc) { |
|---|
| 1752 | 1643 | log_rdma_event(ERR, "rdma_connect() failed with %i\n", rc); |
|---|
| .. | .. |
|---|
| 1770 | 1661 | } |
|---|
| 1771 | 1662 | |
|---|
| 1772 | 1663 | init_waitqueue_head(&info->wait_send_queue); |
|---|
| 1773 | | - init_waitqueue_head(&info->wait_reassembly_queue); |
|---|
| 1774 | | - |
|---|
| 1775 | 1664 | INIT_DELAYED_WORK(&info->idle_timer_work, idle_connection_timer); |
|---|
| 1776 | | - INIT_DELAYED_WORK(&info->send_immediate_work, send_immediate_work); |
|---|
| 1777 | 1665 | queue_delayed_work(info->workqueue, &info->idle_timer_work, |
|---|
| 1778 | 1666 | info->keep_alive_interval*HZ); |
|---|
| 1779 | | - |
|---|
| 1780 | | - init_waitqueue_head(&info->wait_smbd_send_pending); |
|---|
| 1781 | | - info->smbd_send_pending = 0; |
|---|
| 1782 | | - |
|---|
| 1783 | | - init_waitqueue_head(&info->wait_smbd_recv_pending); |
|---|
| 1784 | | - info->smbd_recv_pending = 0; |
|---|
| 1785 | 1667 | |
|---|
| 1786 | 1668 | init_waitqueue_head(&info->wait_send_pending); |
|---|
| 1787 | 1669 | atomic_set(&info->send_pending, 0); |
|---|
| 1788 | 1670 | |
|---|
| 1789 | | - init_waitqueue_head(&info->wait_send_payload_pending); |
|---|
| 1790 | | - atomic_set(&info->send_payload_pending, 0); |
|---|
| 1671 | + init_waitqueue_head(&info->wait_post_send); |
|---|
| 1791 | 1672 | |
|---|
| 1792 | 1673 | INIT_WORK(&info->disconnect_work, smbd_disconnect_rdma_work); |
|---|
| 1793 | | - INIT_WORK(&info->destroy_work, smbd_destroy_rdma_work); |
|---|
| 1794 | | - INIT_WORK(&info->recv_done_work, smbd_recv_done_work); |
|---|
| 1795 | 1674 | INIT_WORK(&info->post_send_credits_work, smbd_post_send_credits); |
|---|
| 1796 | 1675 | info->new_credits_offered = 0; |
|---|
| 1797 | 1676 | spin_lock_init(&info->lock_new_credits_offered); |
|---|
| .. | .. |
|---|
| 1812 | 1691 | |
|---|
| 1813 | 1692 | allocate_mr_failed: |
|---|
| 1814 | 1693 | /* At this point, need to a full transport shutdown */ |
|---|
| 1815 | | - smbd_destroy(info); |
|---|
| 1694 | + server->smbd_conn = info; |
|---|
| 1695 | + smbd_destroy(server); |
|---|
| 1816 | 1696 | return NULL; |
|---|
| 1817 | 1697 | |
|---|
| 1818 | 1698 | negotiation_failed: |
|---|
| .. | .. |
|---|
| 1884 | 1764 | int rc; |
|---|
| 1885 | 1765 | |
|---|
| 1886 | 1766 | again: |
|---|
| 1887 | | - if (info->transport_status != SMBD_CONNECTED) { |
|---|
| 1888 | | - log_read(ERR, "disconnected\n"); |
|---|
| 1889 | | - return -ENODEV; |
|---|
| 1890 | | - } |
|---|
| 1891 | | - |
|---|
| 1892 | 1767 | /* |
|---|
| 1893 | 1768 | * No need to hold the reassembly queue lock all the time as we are |
|---|
| 1894 | 1769 | * the only one reading from the front of the queue. The transport |
|---|
| .. | .. |
|---|
| 1974 | 1849 | to_read -= to_copy; |
|---|
| 1975 | 1850 | data_read += to_copy; |
|---|
| 1976 | 1851 | |
|---|
| 1977 | | - log_read(INFO, "_get_first_reassembly memcpy %d bytes " |
|---|
| 1978 | | - "data_transfer_length-offset=%d after that " |
|---|
| 1979 | | - "to_read=%d data_read=%d offset=%d\n", |
|---|
| 1980 | | - to_copy, data_length - offset, |
|---|
| 1981 | | - to_read, data_read, offset); |
|---|
| 1852 | + log_read(INFO, "_get_first_reassembly memcpy %d bytes data_transfer_length-offset=%d after that to_read=%d data_read=%d offset=%d\n", |
|---|
| 1853 | + to_copy, data_length - offset, |
|---|
| 1854 | + to_read, data_read, offset); |
|---|
| 1982 | 1855 | } |
|---|
| 1983 | 1856 | |
|---|
| 1984 | 1857 | spin_lock_irq(&info->reassembly_queue_lock); |
|---|
| .. | .. |
|---|
| 1987 | 1860 | spin_unlock_irq(&info->reassembly_queue_lock); |
|---|
| 1988 | 1861 | |
|---|
| 1989 | 1862 | info->first_entry_offset = offset; |
|---|
| 1990 | | - log_read(INFO, "returning to thread data_read=%d " |
|---|
| 1991 | | - "reassembly_data_length=%d first_entry_offset=%d\n", |
|---|
| 1992 | | - data_read, info->reassembly_data_length, |
|---|
| 1993 | | - info->first_entry_offset); |
|---|
| 1863 | + log_read(INFO, "returning to thread data_read=%d reassembly_data_length=%d first_entry_offset=%d\n", |
|---|
| 1864 | + data_read, info->reassembly_data_length, |
|---|
| 1865 | + info->first_entry_offset); |
|---|
| 1994 | 1866 | read_rfc1002_done: |
|---|
| 1995 | 1867 | return data_read; |
|---|
| 1996 | 1868 | } |
|---|
| .. | .. |
|---|
| 2002 | 1874 | info->transport_status != SMBD_CONNECTED); |
|---|
| 2003 | 1875 | /* Don't return any data if interrupted */ |
|---|
| 2004 | 1876 | if (rc) |
|---|
| 2005 | | - return -ENODEV; |
|---|
| 1877 | + return rc; |
|---|
| 1878 | + |
|---|
| 1879 | + if (info->transport_status != SMBD_CONNECTED) { |
|---|
| 1880 | + log_read(ERR, "disconnected\n"); |
|---|
| 1881 | + return -ECONNABORTED; |
|---|
| 1882 | + } |
|---|
| 2006 | 1883 | |
|---|
| 2007 | 1884 | goto again; |
|---|
| 2008 | 1885 | } |
|---|
| .. | .. |
|---|
| 2054 | 1931 | unsigned int to_read, page_offset; |
|---|
| 2055 | 1932 | int rc; |
|---|
| 2056 | 1933 | |
|---|
| 2057 | | - info->smbd_recv_pending++; |
|---|
| 1934 | + if (iov_iter_rw(&msg->msg_iter) == WRITE) { |
|---|
| 1935 | + /* It's a bug in upper layer to get there */ |
|---|
| 1936 | + cifs_dbg(VFS, "Invalid msg iter dir %u\n", |
|---|
| 1937 | + iov_iter_rw(&msg->msg_iter)); |
|---|
| 1938 | + rc = -EINVAL; |
|---|
| 1939 | + goto out; |
|---|
| 1940 | + } |
|---|
| 2058 | 1941 | |
|---|
| 2059 | | - switch (msg->msg_iter.type) { |
|---|
| 2060 | | - case READ | ITER_KVEC: |
|---|
| 1942 | + switch (iov_iter_type(&msg->msg_iter)) { |
|---|
| 1943 | + case ITER_KVEC: |
|---|
| 2061 | 1944 | buf = msg->msg_iter.kvec->iov_base; |
|---|
| 2062 | 1945 | to_read = msg->msg_iter.kvec->iov_len; |
|---|
| 2063 | 1946 | rc = smbd_recv_buf(info, buf, to_read); |
|---|
| 2064 | 1947 | break; |
|---|
| 2065 | 1948 | |
|---|
| 2066 | | - case READ | ITER_BVEC: |
|---|
| 1949 | + case ITER_BVEC: |
|---|
| 2067 | 1950 | page = msg->msg_iter.bvec->bv_page; |
|---|
| 2068 | 1951 | page_offset = msg->msg_iter.bvec->bv_offset; |
|---|
| 2069 | 1952 | to_read = msg->msg_iter.bvec->bv_len; |
|---|
| .. | .. |
|---|
| 2072 | 1955 | |
|---|
| 2073 | 1956 | default: |
|---|
| 2074 | 1957 | /* It's a bug in upper layer to get there */ |
|---|
| 2075 | | - cifs_dbg(VFS, "CIFS: invalid msg type %d\n", |
|---|
| 2076 | | - msg->msg_iter.type); |
|---|
| 1958 | + cifs_dbg(VFS, "Invalid msg type %d\n", |
|---|
| 1959 | + iov_iter_type(&msg->msg_iter)); |
|---|
| 2077 | 1960 | rc = -EINVAL; |
|---|
| 2078 | 1961 | } |
|---|
| 2079 | 1962 | |
|---|
| 2080 | | - info->smbd_recv_pending--; |
|---|
| 2081 | | - wake_up(&info->wait_smbd_recv_pending); |
|---|
| 2082 | | - |
|---|
| 1963 | +out: |
|---|
| 2083 | 1964 | /* SMBDirect will read it all or nothing */ |
|---|
| 2084 | 1965 | if (rc > 0) |
|---|
| 2085 | 1966 | msg->msg_iter.count = 0; |
|---|
| .. | .. |
|---|
| 2108 | 1989 | struct smb_rqst *rqst; |
|---|
| 2109 | 1990 | int rqst_idx; |
|---|
| 2110 | 1991 | |
|---|
| 2111 | | - info->smbd_send_pending++; |
|---|
| 2112 | 1992 | if (info->transport_status != SMBD_CONNECTED) { |
|---|
| 2113 | | - rc = -ENODEV; |
|---|
| 1993 | + rc = -EAGAIN; |
|---|
| 2114 | 1994 | goto done; |
|---|
| 2115 | 1995 | } |
|---|
| 2116 | 1996 | |
|---|
| .. | .. |
|---|
| 2123 | 2003 | for (i = 0; i < num_rqst; i++) |
|---|
| 2124 | 2004 | remaining_data_length += smb_rqst_len(server, &rqst_array[i]); |
|---|
| 2125 | 2005 | |
|---|
| 2126 | | - if (remaining_data_length + sizeof(struct smbd_data_transfer) > |
|---|
| 2127 | | - info->max_fragmented_send_size) { |
|---|
| 2006 | + if (remaining_data_length > info->max_fragmented_send_size) { |
|---|
| 2128 | 2007 | log_write(ERR, "payload size %d > max size %d\n", |
|---|
| 2129 | 2008 | remaining_data_length, info->max_fragmented_send_size); |
|---|
| 2130 | 2009 | rc = -EINVAL; |
|---|
| 2131 | 2010 | goto done; |
|---|
| 2132 | 2011 | } |
|---|
| 2133 | 2012 | |
|---|
| 2134 | | - rqst_idx = 0; |
|---|
| 2013 | + log_write(INFO, "num_rqst=%d total length=%u\n", |
|---|
| 2014 | + num_rqst, remaining_data_length); |
|---|
| 2135 | 2015 | |
|---|
| 2016 | + rqst_idx = 0; |
|---|
| 2136 | 2017 | next_rqst: |
|---|
| 2137 | 2018 | rqst = &rqst_array[rqst_idx]; |
|---|
| 2138 | 2019 | iov = rqst->rq_iov; |
|---|
| .. | .. |
|---|
| 2143 | 2024 | dump_smb(iov[i].iov_base, iov[i].iov_len); |
|---|
| 2144 | 2025 | |
|---|
| 2145 | 2026 | |
|---|
| 2146 | | - log_write(INFO, "rqst_idx=%d nvec=%d rqst->rq_npages=%d rq_pagesz=%d " |
|---|
| 2147 | | - "rq_tailsz=%d buflen=%lu\n", |
|---|
| 2148 | | - rqst_idx, rqst->rq_nvec, rqst->rq_npages, rqst->rq_pagesz, |
|---|
| 2149 | | - rqst->rq_tailsz, smb_rqst_len(server, rqst)); |
|---|
| 2027 | + log_write(INFO, "rqst_idx=%d nvec=%d rqst->rq_npages=%d rq_pagesz=%d rq_tailsz=%d buflen=%lu\n", |
|---|
| 2028 | + rqst_idx, rqst->rq_nvec, rqst->rq_npages, rqst->rq_pagesz, |
|---|
| 2029 | + rqst->rq_tailsz, smb_rqst_len(server, rqst)); |
|---|
| 2150 | 2030 | |
|---|
| 2151 | 2031 | start = i = 0; |
|---|
| 2152 | 2032 | buflen = 0; |
|---|
| .. | .. |
|---|
| 2156 | 2036 | if (i > start) { |
|---|
| 2157 | 2037 | remaining_data_length -= |
|---|
| 2158 | 2038 | (buflen-iov[i].iov_len); |
|---|
| 2159 | | - log_write(INFO, "sending iov[] from start=%d " |
|---|
| 2160 | | - "i=%d nvecs=%d " |
|---|
| 2161 | | - "remaining_data_length=%d\n", |
|---|
| 2162 | | - start, i, i-start, |
|---|
| 2163 | | - remaining_data_length); |
|---|
| 2039 | + log_write(INFO, "sending iov[] from start=%d i=%d nvecs=%d remaining_data_length=%d\n", |
|---|
| 2040 | + start, i, i - start, |
|---|
| 2041 | + remaining_data_length); |
|---|
| 2164 | 2042 | rc = smbd_post_send_data( |
|---|
| 2165 | 2043 | info, &iov[start], i-start, |
|---|
| 2166 | 2044 | remaining_data_length); |
|---|
| .. | .. |
|---|
| 2169 | 2047 | } else { |
|---|
| 2170 | 2048 | /* iov[start] is too big, break it */ |
|---|
| 2171 | 2049 | nvecs = (buflen+max_iov_size-1)/max_iov_size; |
|---|
| 2172 | | - log_write(INFO, "iov[%d] iov_base=%p buflen=%d" |
|---|
| 2173 | | - " break to %d vectors\n", |
|---|
| 2174 | | - start, iov[start].iov_base, |
|---|
| 2175 | | - buflen, nvecs); |
|---|
| 2050 | + log_write(INFO, "iov[%d] iov_base=%p buflen=%d break to %d vectors\n", |
|---|
| 2051 | + start, iov[start].iov_base, |
|---|
| 2052 | + buflen, nvecs); |
|---|
| 2176 | 2053 | for (j = 0; j < nvecs; j++) { |
|---|
| 2177 | 2054 | vec.iov_base = |
|---|
| 2178 | 2055 | (char *)iov[start].iov_base + |
|---|
| .. | .. |
|---|
| 2184 | 2061 | max_iov_size*(nvecs-1); |
|---|
| 2185 | 2062 | remaining_data_length -= vec.iov_len; |
|---|
| 2186 | 2063 | log_write(INFO, |
|---|
| 2187 | | - "sending vec j=%d iov_base=%p" |
|---|
| 2188 | | - " iov_len=%zu " |
|---|
| 2189 | | - "remaining_data_length=%d\n", |
|---|
| 2190 | | - j, vec.iov_base, vec.iov_len, |
|---|
| 2191 | | - remaining_data_length); |
|---|
| 2064 | + "sending vec j=%d iov_base=%p iov_len=%zu remaining_data_length=%d\n", |
|---|
| 2065 | + j, vec.iov_base, vec.iov_len, |
|---|
| 2066 | + remaining_data_length); |
|---|
| 2192 | 2067 | rc = smbd_post_send_data( |
|---|
| 2193 | 2068 | info, &vec, 1, |
|---|
| 2194 | 2069 | remaining_data_length); |
|---|
| .. | .. |
|---|
| 2206 | 2081 | if (i == rqst->rq_nvec) { |
|---|
| 2207 | 2082 | /* send out all remaining vecs */ |
|---|
| 2208 | 2083 | remaining_data_length -= buflen; |
|---|
| 2209 | | - log_write(INFO, |
|---|
| 2210 | | - "sending iov[] from start=%d i=%d " |
|---|
| 2211 | | - "nvecs=%d remaining_data_length=%d\n", |
|---|
| 2212 | | - start, i, i-start, |
|---|
| 2213 | | - remaining_data_length); |
|---|
| 2084 | + log_write(INFO, "sending iov[] from start=%d i=%d nvecs=%d remaining_data_length=%d\n", |
|---|
| 2085 | + start, i, i - start, |
|---|
| 2086 | + remaining_data_length); |
|---|
| 2214 | 2087 | rc = smbd_post_send_data(info, &iov[start], |
|---|
| 2215 | 2088 | i-start, remaining_data_length); |
|---|
| 2216 | 2089 | if (rc) |
|---|
| .. | .. |
|---|
| 2234 | 2107 | if (j == nvecs-1) |
|---|
| 2235 | 2108 | size = buflen - j*max_iov_size; |
|---|
| 2236 | 2109 | remaining_data_length -= size; |
|---|
| 2237 | | - log_write(INFO, "sending pages i=%d offset=%d size=%d" |
|---|
| 2238 | | - " remaining_data_length=%d\n", |
|---|
| 2239 | | - i, j*max_iov_size+offset, size, |
|---|
| 2240 | | - remaining_data_length); |
|---|
| 2110 | + log_write(INFO, "sending pages i=%d offset=%d size=%d remaining_data_length=%d\n", |
|---|
| 2111 | + i, j * max_iov_size + offset, size, |
|---|
| 2112 | + remaining_data_length); |
|---|
| 2241 | 2113 | rc = smbd_post_send_page( |
|---|
| 2242 | 2114 | info, rqst->rq_pages[i], |
|---|
| 2243 | 2115 | j*max_iov_size + offset, |
|---|
| .. | .. |
|---|
| 2259 | 2131 | * that means all the I/Os have been out and we are good to return |
|---|
| 2260 | 2132 | */ |
|---|
| 2261 | 2133 | |
|---|
| 2262 | | - wait_event(info->wait_send_payload_pending, |
|---|
| 2263 | | - atomic_read(&info->send_payload_pending) == 0); |
|---|
| 2264 | | - |
|---|
| 2265 | | - info->smbd_send_pending--; |
|---|
| 2266 | | - wake_up(&info->wait_smbd_send_pending); |
|---|
| 2134 | + wait_event(info->wait_send_pending, |
|---|
| 2135 | + atomic_read(&info->send_pending) == 0); |
|---|
| 2267 | 2136 | |
|---|
| 2268 | 2137 | return rc; |
|---|
| 2269 | 2138 | } |
|---|
| .. | .. |
|---|
| 2298 | 2167 | int rc; |
|---|
| 2299 | 2168 | |
|---|
| 2300 | 2169 | list_for_each_entry(smbdirect_mr, &info->mr_list, list) { |
|---|
| 2301 | | - if (smbdirect_mr->state == MR_INVALIDATED || |
|---|
| 2302 | | - smbdirect_mr->state == MR_ERROR) { |
|---|
| 2170 | + if (smbdirect_mr->state == MR_ERROR) { |
|---|
| 2303 | 2171 | |
|---|
| 2304 | 2172 | /* recover this MR entry */ |
|---|
| 2305 | 2173 | rc = ib_dereg_mr(smbdirect_mr->mr); |
|---|
| .. | .. |
|---|
| 2315 | 2183 | info->pd, info->mr_type, |
|---|
| 2316 | 2184 | info->max_frmr_depth); |
|---|
| 2317 | 2185 | if (IS_ERR(smbdirect_mr->mr)) { |
|---|
| 2318 | | - log_rdma_mr(ERR, |
|---|
| 2319 | | - "ib_alloc_mr failed mr_type=%x " |
|---|
| 2320 | | - "max_frmr_depth=%x\n", |
|---|
| 2321 | | - info->mr_type, |
|---|
| 2322 | | - info->max_frmr_depth); |
|---|
| 2186 | + log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n", |
|---|
| 2187 | + info->mr_type, |
|---|
| 2188 | + info->max_frmr_depth); |
|---|
| 2323 | 2189 | smbd_disconnect_rdma_connection(info); |
|---|
| 2324 | 2190 | continue; |
|---|
| 2325 | 2191 | } |
|---|
| 2192 | + } else |
|---|
| 2193 | + /* This MR is being used, don't recover it */ |
|---|
| 2194 | + continue; |
|---|
| 2326 | 2195 | |
|---|
| 2327 | | - if (smbdirect_mr->state == MR_INVALIDATED) |
|---|
| 2328 | | - ib_dma_unmap_sg( |
|---|
| 2329 | | - info->id->device, smbdirect_mr->sgl, |
|---|
| 2330 | | - smbdirect_mr->sgl_count, |
|---|
| 2331 | | - smbdirect_mr->dir); |
|---|
| 2196 | + smbdirect_mr->state = MR_READY; |
|---|
| 2332 | 2197 | |
|---|
| 2333 | | - smbdirect_mr->state = MR_READY; |
|---|
| 2334 | | - |
|---|
| 2335 | | - /* smbdirect_mr->state is updated by this function |
|---|
| 2336 | | - * and is read and updated by I/O issuing CPUs trying |
|---|
| 2337 | | - * to get a MR, the call to atomic_inc_return |
|---|
| 2338 | | - * implicates a memory barrier and guarantees this |
|---|
| 2339 | | - * value is updated before waking up any calls to |
|---|
| 2340 | | - * get_mr() from the I/O issuing CPUs |
|---|
| 2341 | | - */ |
|---|
| 2342 | | - if (atomic_inc_return(&info->mr_ready_count) == 1) |
|---|
| 2343 | | - wake_up_interruptible(&info->wait_mr); |
|---|
| 2344 | | - } |
|---|
| 2198 | + /* smbdirect_mr->state is updated by this function |
|---|
| 2199 | + * and is read and updated by I/O issuing CPUs trying |
|---|
| 2200 | + * to get a MR, the call to atomic_inc_return |
|---|
| 2201 | + * implicates a memory barrier and guarantees this |
|---|
| 2202 | + * value is updated before waking up any calls to |
|---|
| 2203 | + * get_mr() from the I/O issuing CPUs |
|---|
| 2204 | + */ |
|---|
| 2205 | + if (atomic_inc_return(&info->mr_ready_count) == 1) |
|---|
| 2206 | + wake_up_interruptible(&info->wait_mr); |
|---|
| 2345 | 2207 | } |
|---|
| 2346 | 2208 | } |
|---|
| 2347 | 2209 | |
|---|
| .. | .. |
|---|
| 2378 | 2240 | atomic_set(&info->mr_ready_count, 0); |
|---|
| 2379 | 2241 | atomic_set(&info->mr_used_count, 0); |
|---|
| 2380 | 2242 | init_waitqueue_head(&info->wait_for_mr_cleanup); |
|---|
| 2243 | + INIT_WORK(&info->mr_recovery_work, smbd_mr_recovery_work); |
|---|
| 2381 | 2244 | /* Allocate more MRs (2x) than hardware responder_resources */ |
|---|
| 2382 | 2245 | for (i = 0; i < info->responder_resources * 2; i++) { |
|---|
| 2383 | 2246 | smbdirect_mr = kzalloc(sizeof(*smbdirect_mr), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 2386 | 2249 | smbdirect_mr->mr = ib_alloc_mr(info->pd, info->mr_type, |
|---|
| 2387 | 2250 | info->max_frmr_depth); |
|---|
| 2388 | 2251 | if (IS_ERR(smbdirect_mr->mr)) { |
|---|
| 2389 | | - log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x " |
|---|
| 2390 | | - "max_frmr_depth=%x\n", |
|---|
| 2391 | | - info->mr_type, info->max_frmr_depth); |
|---|
| 2252 | + log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n", |
|---|
| 2253 | + info->mr_type, info->max_frmr_depth); |
|---|
| 2392 | 2254 | goto out; |
|---|
| 2393 | 2255 | } |
|---|
| 2394 | 2256 | smbdirect_mr->sgl = kcalloc( |
|---|
| .. | .. |
|---|
| 2406 | 2268 | list_add_tail(&smbdirect_mr->list, &info->mr_list); |
|---|
| 2407 | 2269 | atomic_inc(&info->mr_ready_count); |
|---|
| 2408 | 2270 | } |
|---|
| 2409 | | - INIT_WORK(&info->mr_recovery_work, smbd_mr_recovery_work); |
|---|
| 2410 | 2271 | return 0; |
|---|
| 2411 | 2272 | |
|---|
| 2412 | 2273 | out: |
|---|
| 2413 | 2274 | kfree(smbdirect_mr); |
|---|
| 2414 | 2275 | |
|---|
| 2415 | 2276 | list_for_each_entry_safe(smbdirect_mr, tmp, &info->mr_list, list) { |
|---|
| 2277 | + list_del(&smbdirect_mr->list); |
|---|
| 2416 | 2278 | ib_dereg_mr(smbdirect_mr->mr); |
|---|
| 2417 | 2279 | kfree(smbdirect_mr->sgl); |
|---|
| 2418 | 2280 | kfree(smbdirect_mr); |
|---|
| .. | .. |
|---|
| 2631 | 2493 | */ |
|---|
| 2632 | 2494 | smbdirect_mr->state = MR_INVALIDATED; |
|---|
| 2633 | 2495 | |
|---|
| 2634 | | - /* |
|---|
| 2635 | | - * Schedule the work to do MR recovery for future I/Os |
|---|
| 2636 | | - * MR recovery is slow and we don't want it to block the current I/O |
|---|
| 2637 | | - */ |
|---|
| 2638 | | - queue_work(info->workqueue, &info->mr_recovery_work); |
|---|
| 2496 | + if (smbdirect_mr->state == MR_INVALIDATED) { |
|---|
| 2497 | + ib_dma_unmap_sg( |
|---|
| 2498 | + info->id->device, smbdirect_mr->sgl, |
|---|
| 2499 | + smbdirect_mr->sgl_count, |
|---|
| 2500 | + smbdirect_mr->dir); |
|---|
| 2501 | + smbdirect_mr->state = MR_READY; |
|---|
| 2502 | + if (atomic_inc_return(&info->mr_ready_count) == 1) |
|---|
| 2503 | + wake_up_interruptible(&info->wait_mr); |
|---|
| 2504 | + } else |
|---|
| 2505 | + /* |
|---|
| 2506 | + * Schedule the work to do MR recovery for future I/Os MR |
|---|
| 2507 | + * recovery is slow and don't want it to block current I/O |
|---|
| 2508 | + */ |
|---|
| 2509 | + queue_work(info->workqueue, &info->mr_recovery_work); |
|---|
| 2639 | 2510 | |
|---|
| 2640 | 2511 | done: |
|---|
| 2641 | 2512 | if (atomic_dec_and_test(&info->mr_used_count)) |
|---|