1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * RDMA transport layer based on the trans_fd.c implementation. 4 * 5 * Copyright (C) 2008 by Tom Tucker <tom@opengridcomputing.com> 6 * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> 7 * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> 8 * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com> 9 * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> 10 */ 11 12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13 14 #include <linux/in.h> 15 #include <linux/module.h> 16 #include <linux/net.h> 17 #include <linux/ipv6.h> 18 #include <linux/kthread.h> 19 #include <linux/errno.h> 20 #include <linux/kernel.h> 21 #include <linux/un.h> 22 #include <linux/uaccess.h> 23 #include <linux/inet.h> 24 #include <linux/file.h> 25 #include <linux/fs_context.h> 26 #include <linux/semaphore.h> 27 #include <linux/slab.h> 28 #include <linux/seq_file.h> 29 #include <net/9p/9p.h> 30 #include <net/9p/client.h> 31 #include <net/9p/transport.h> 32 #include <rdma/ib_verbs.h> 33 #include <rdma/rdma_cm.h> 34 35 #define P9_RDMA_SEND_SGE 4 36 #define P9_RDMA_RECV_SGE 4 37 #define P9_RDMA_IRD 0 38 #define P9_RDMA_ORD 0 39 #define P9_RDMA_MAXSIZE (1024*1024) /* 1MB */ 40 41 /** 42 * struct p9_trans_rdma - RDMA transport instance 43 * 44 * @state: tracks the transport state machine for connection setup and tear down 45 * @cm_id: The RDMA CM ID 46 * @pd: Protection Domain pointer 47 * @qp: Queue Pair pointer 48 * @cq: Completion Queue pointer 49 * @timeout: Number of uSecs to wait for connection management events 50 * @privport: Whether a privileged port may be used 51 * @port: The port to use 52 * @sq_depth: The depth of the Send Queue 53 * @sq_sem: Semaphore for the SQ 54 * @rq_depth: The depth of the Receive Queue. 55 * @rq_sem: Semaphore for the RQ 56 * @excess_rc : Amount of posted Receive Contexts without a pending request. 57 * See rdma_request() 58 * @addr: The remote peer's address 59 * @req_lock: Protects the active request list 60 * @cm_done: Completion event for connection management tracking 61 */ 62 struct p9_trans_rdma { 63 enum { 64 P9_RDMA_INIT, 65 P9_RDMA_ADDR_RESOLVED, 66 P9_RDMA_ROUTE_RESOLVED, 67 P9_RDMA_CONNECTED, 68 P9_RDMA_FLUSHING, 69 P9_RDMA_CLOSING, 70 P9_RDMA_CLOSED, 71 } state; 72 struct rdma_cm_id *cm_id; 73 struct ib_pd *pd; 74 struct ib_qp *qp; 75 struct ib_cq *cq; 76 long timeout; 77 bool privport; 78 u16 port; 79 int sq_depth; 80 struct semaphore sq_sem; 81 int rq_depth; 82 struct semaphore rq_sem; 83 atomic_t excess_rc; 84 struct sockaddr_in addr; 85 spinlock_t req_lock; 86 87 struct completion cm_done; 88 }; 89 90 struct p9_rdma_req; 91 92 /** 93 * struct p9_rdma_context - Keeps track of in-process WR 94 * 95 * @cqe: completion queue entry 96 * @busa: Bus address to unmap when the WR completes 97 * @req: Keeps track of requests (send) 98 * @rc: Keepts track of replies (receive) 99 */ 100 struct p9_rdma_context { 101 struct ib_cqe cqe; 102 dma_addr_t busa; 103 union { 104 struct p9_req_t *req; 105 struct p9_fcall rc; 106 }; 107 }; 108 109 static int p9_rdma_show_options(struct seq_file *m, struct p9_client *clnt) 110 { 111 struct p9_trans_rdma *rdma = clnt->trans; 112 113 if (rdma->port != P9_RDMA_PORT) 114 seq_printf(m, ",port=%u", rdma->port); 115 if (rdma->sq_depth != P9_RDMA_SQ_DEPTH) 116 seq_printf(m, ",sq=%u", rdma->sq_depth); 117 if (rdma->rq_depth != P9_RDMA_RQ_DEPTH) 118 seq_printf(m, ",rq=%u", rdma->rq_depth); 119 if (rdma->timeout != P9_RDMA_TIMEOUT) 120 seq_printf(m, ",timeout=%lu", rdma->timeout); 121 if (rdma->privport) 122 seq_puts(m, ",privport"); 123 return 0; 124 } 125 126 static int 127 p9_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) 128 { 129 struct p9_client *c = id->context; 130 struct p9_trans_rdma *rdma = c->trans; 131 unsigned long flags; 132 133 switch (event->event) { 134 case RDMA_CM_EVENT_ADDR_RESOLVED: 135 spin_lock_irqsave(&rdma->req_lock, flags); 136 BUG_ON(rdma->state != P9_RDMA_INIT); 137 rdma->state = P9_RDMA_ADDR_RESOLVED; 138 spin_unlock_irqrestore(&rdma->req_lock, flags); 139 break; 140 141 case RDMA_CM_EVENT_ROUTE_RESOLVED: 142 spin_lock_irqsave(&rdma->req_lock, flags); 143 BUG_ON(rdma->state != P9_RDMA_ADDR_RESOLVED); 144 rdma->state = P9_RDMA_ROUTE_RESOLVED; 145 spin_unlock_irqrestore(&rdma->req_lock, flags); 146 break; 147 148 case RDMA_CM_EVENT_ESTABLISHED: 149 spin_lock_irqsave(&rdma->req_lock, flags); 150 BUG_ON(rdma->state != P9_RDMA_ROUTE_RESOLVED); 151 rdma->state = P9_RDMA_CONNECTED; 152 spin_unlock_irqrestore(&rdma->req_lock, flags); 153 break; 154 155 case RDMA_CM_EVENT_DISCONNECTED: 156 if (rdma) { 157 spin_lock_irqsave(&rdma->req_lock, flags); 158 rdma->state = P9_RDMA_CLOSED; 159 spin_unlock_irqrestore(&rdma->req_lock, flags); 160 } 161 c->status = Disconnected; 162 break; 163 164 case RDMA_CM_EVENT_TIMEWAIT_EXIT: 165 break; 166 167 case RDMA_CM_EVENT_ADDR_CHANGE: 168 case RDMA_CM_EVENT_ROUTE_ERROR: 169 case RDMA_CM_EVENT_DEVICE_REMOVAL: 170 case RDMA_CM_EVENT_MULTICAST_JOIN: 171 case RDMA_CM_EVENT_MULTICAST_ERROR: 172 case RDMA_CM_EVENT_REJECTED: 173 case RDMA_CM_EVENT_CONNECT_REQUEST: 174 case RDMA_CM_EVENT_CONNECT_RESPONSE: 175 case RDMA_CM_EVENT_CONNECT_ERROR: 176 case RDMA_CM_EVENT_ADDR_ERROR: 177 case RDMA_CM_EVENT_UNREACHABLE: 178 c->status = Disconnected; 179 rdma_disconnect(rdma->cm_id); 180 break; 181 default: 182 BUG(); 183 } 184 complete(&rdma->cm_done); 185 return 0; 186 } 187 188 static void 189 recv_done(struct ib_cq *cq, struct ib_wc *wc) 190 { 191 struct p9_client *client = cq->cq_context; 192 struct p9_trans_rdma *rdma = client->trans; 193 struct p9_rdma_context *c = 194 container_of(wc->wr_cqe, struct p9_rdma_context, cqe); 195 struct p9_req_t *req; 196 int err = 0; 197 int16_t tag; 198 unsigned long flags; 199 200 req = NULL; 201 ib_dma_unmap_single(rdma->cm_id->device, c->busa, client->msize, 202 DMA_FROM_DEVICE); 203 204 if (wc->status != IB_WC_SUCCESS) 205 goto err_out; 206 207 c->rc.size = wc->byte_len; 208 err = p9_parse_header(&c->rc, NULL, NULL, &tag, 1); 209 if (err) 210 goto err_out; 211 212 req = p9_tag_lookup(client, tag); 213 if (!req) 214 goto err_out; 215 216 /* Check that we have not yet received a reply for this request. 217 */ 218 if (unlikely(req->rc.sdata)) { 219 pr_err("Duplicate reply for request %d", tag); 220 goto err_out; 221 } 222 223 req->rc.size = c->rc.size; 224 req->rc.sdata = c->rc.sdata; 225 p9_client_cb(client, req, REQ_STATUS_RCVD); 226 227 out: 228 up(&rdma->rq_sem); 229 kfree(c); 230 return; 231 232 err_out: 233 p9_debug(P9_DEBUG_ERROR, "req %p err %d status %d\n", 234 req, err, wc->status); 235 spin_lock_irqsave(&rdma->req_lock, flags); 236 if (rdma->state < P9_RDMA_FLUSHING) 237 rdma->state = P9_RDMA_FLUSHING; 238 spin_unlock_irqrestore(&rdma->req_lock, flags); 239 client->status = Disconnected; 240 goto out; 241 } 242 243 static void 244 send_done(struct ib_cq *cq, struct ib_wc *wc) 245 { 246 struct p9_client *client = cq->cq_context; 247 struct p9_trans_rdma *rdma = client->trans; 248 struct p9_rdma_context *c = 249 container_of(wc->wr_cqe, struct p9_rdma_context, cqe); 250 251 ib_dma_unmap_single(rdma->cm_id->device, 252 c->busa, c->req->tc.size, 253 DMA_TO_DEVICE); 254 up(&rdma->sq_sem); 255 p9_req_put(client, c->req); 256 kfree(c); 257 } 258 259 static void qp_event_handler(struct ib_event *event, void *context) 260 { 261 p9_debug(P9_DEBUG_ERROR, "QP event %d context %p\n", 262 event->event, context); 263 } 264 265 static void rdma_destroy_trans(struct p9_trans_rdma *rdma) 266 { 267 if (!rdma) 268 return; 269 270 if (rdma->qp && !IS_ERR(rdma->qp)) 271 ib_destroy_qp(rdma->qp); 272 273 if (rdma->pd && !IS_ERR(rdma->pd)) 274 ib_dealloc_pd(rdma->pd); 275 276 if (rdma->cq && !IS_ERR(rdma->cq)) 277 ib_free_cq(rdma->cq); 278 279 if (rdma->cm_id && !IS_ERR(rdma->cm_id)) 280 rdma_destroy_id(rdma->cm_id); 281 282 kfree(rdma); 283 } 284 285 static int 286 post_recv(struct p9_client *client, struct p9_rdma_context *c) 287 { 288 struct p9_trans_rdma *rdma = client->trans; 289 struct ib_recv_wr wr; 290 struct ib_sge sge; 291 int ret; 292 293 c->busa = ib_dma_map_single(rdma->cm_id->device, 294 c->rc.sdata, client->msize, 295 DMA_FROM_DEVICE); 296 if (ib_dma_mapping_error(rdma->cm_id->device, c->busa)) 297 goto error; 298 299 c->cqe.done = recv_done; 300 301 sge.addr = c->busa; 302 sge.length = client->msize; 303 sge.lkey = rdma->pd->local_dma_lkey; 304 305 wr.next = NULL; 306 wr.wr_cqe = &c->cqe; 307 wr.sg_list = &sge; 308 wr.num_sge = 1; 309 310 ret = ib_post_recv(rdma->qp, &wr, NULL); 311 if (ret) 312 ib_dma_unmap_single(rdma->cm_id->device, c->busa, 313 client->msize, DMA_FROM_DEVICE); 314 return ret; 315 316 error: 317 p9_debug(P9_DEBUG_ERROR, "EIO\n"); 318 return -EIO; 319 } 320 321 static int rdma_request(struct p9_client *client, struct p9_req_t *req) 322 { 323 struct p9_trans_rdma *rdma = client->trans; 324 struct ib_send_wr wr; 325 struct ib_sge sge; 326 int err = 0; 327 unsigned long flags; 328 struct p9_rdma_context *c = NULL; 329 struct p9_rdma_context *rpl_context = NULL; 330 331 /* When an error occurs between posting the recv and the send, 332 * there will be a receive context posted without a pending request. 333 * Since there is no way to "un-post" it, we remember it and skip 334 * post_recv() for the next request. 335 * So here, 336 * see if we are this `next request' and need to absorb an excess rc. 337 * If yes, then drop and free our own, and do not recv_post(). 338 **/ 339 if (unlikely(atomic_read(&rdma->excess_rc) > 0)) { 340 if ((atomic_sub_return(1, &rdma->excess_rc) >= 0)) { 341 /* Got one! */ 342 p9_fcall_fini(&req->rc); 343 req->rc.sdata = NULL; 344 goto dont_need_post_recv; 345 } else { 346 /* We raced and lost. */ 347 atomic_inc(&rdma->excess_rc); 348 } 349 } 350 351 /* Allocate an fcall for the reply */ 352 rpl_context = kmalloc_obj(*rpl_context, GFP_NOFS); 353 if (!rpl_context) { 354 err = -ENOMEM; 355 goto recv_error; 356 } 357 rpl_context->rc.sdata = req->rc.sdata; 358 359 /* 360 * Post a receive buffer for this request. We need to ensure 361 * there is a reply buffer available for every outstanding 362 * request. A flushed request can result in no reply for an 363 * outstanding request, so we must keep a count to avoid 364 * overflowing the RQ. 365 */ 366 if (down_interruptible(&rdma->rq_sem)) { 367 err = -EINTR; 368 goto recv_error; 369 } 370 371 err = post_recv(client, rpl_context); 372 if (err) { 373 p9_debug(P9_DEBUG_ERROR, "POST RECV failed: %d\n", err); 374 goto recv_error; 375 } 376 /* remove posted receive buffer from request structure */ 377 req->rc.sdata = NULL; 378 379 dont_need_post_recv: 380 /* Post the request */ 381 c = kmalloc_obj(*c, GFP_NOFS); 382 if (!c) { 383 err = -ENOMEM; 384 goto send_error; 385 } 386 c->req = req; 387 388 c->busa = ib_dma_map_single(rdma->cm_id->device, 389 c->req->tc.sdata, c->req->tc.size, 390 DMA_TO_DEVICE); 391 if (ib_dma_mapping_error(rdma->cm_id->device, c->busa)) { 392 err = -EIO; 393 goto send_error; 394 } 395 396 c->cqe.done = send_done; 397 398 sge.addr = c->busa; 399 sge.length = c->req->tc.size; 400 sge.lkey = rdma->pd->local_dma_lkey; 401 402 wr.next = NULL; 403 wr.wr_cqe = &c->cqe; 404 wr.opcode = IB_WR_SEND; 405 wr.send_flags = IB_SEND_SIGNALED; 406 wr.sg_list = &sge; 407 wr.num_sge = 1; 408 409 if (down_interruptible(&rdma->sq_sem)) { 410 err = -EINTR; 411 goto dma_unmap; 412 } 413 414 /* Mark request as `sent' *before* we actually send it, 415 * because doing if after could erase the REQ_STATUS_RCVD 416 * status in case of a very fast reply. 417 */ 418 WRITE_ONCE(req->status, REQ_STATUS_SENT); 419 err = ib_post_send(rdma->qp, &wr, NULL); 420 if (err) 421 goto dma_unmap; 422 423 /* Success */ 424 return 0; 425 426 dma_unmap: 427 ib_dma_unmap_single(rdma->cm_id->device, c->busa, 428 c->req->tc.size, DMA_TO_DEVICE); 429 /* Handle errors that happened during or while preparing the send: */ 430 send_error: 431 WRITE_ONCE(req->status, REQ_STATUS_ERROR); 432 kfree(c); 433 p9_debug(P9_DEBUG_ERROR, "Error %d in rdma_request()\n", err); 434 435 /* Ach. 436 * We did recv_post(), but not send. We have one recv_post in excess. 437 */ 438 atomic_inc(&rdma->excess_rc); 439 return err; 440 441 /* Handle errors that happened during or while preparing post_recv(): */ 442 recv_error: 443 kfree(rpl_context); 444 spin_lock_irqsave(&rdma->req_lock, flags); 445 if (err != -EINTR && rdma->state < P9_RDMA_CLOSING) { 446 rdma->state = P9_RDMA_CLOSING; 447 spin_unlock_irqrestore(&rdma->req_lock, flags); 448 rdma_disconnect(rdma->cm_id); 449 } else 450 spin_unlock_irqrestore(&rdma->req_lock, flags); 451 return err; 452 } 453 454 static void rdma_close(struct p9_client *client) 455 { 456 struct p9_trans_rdma *rdma; 457 458 if (!client) 459 return; 460 461 rdma = client->trans; 462 if (!rdma) 463 return; 464 465 client->status = Disconnected; 466 rdma_disconnect(rdma->cm_id); 467 rdma_destroy_trans(rdma); 468 } 469 470 /** 471 * alloc_rdma - Allocate and initialize the rdma transport structure 472 * @opts: Mount options structure 473 */ 474 static struct p9_trans_rdma *alloc_rdma(struct p9_rdma_opts *opts) 475 { 476 struct p9_trans_rdma *rdma; 477 478 rdma = kzalloc_obj(struct p9_trans_rdma); 479 if (!rdma) 480 return NULL; 481 482 rdma->port = opts->port; 483 rdma->privport = opts->privport; 484 rdma->sq_depth = opts->sq_depth; 485 rdma->rq_depth = opts->rq_depth; 486 rdma->timeout = opts->timeout; 487 spin_lock_init(&rdma->req_lock); 488 init_completion(&rdma->cm_done); 489 sema_init(&rdma->sq_sem, rdma->sq_depth); 490 sema_init(&rdma->rq_sem, rdma->rq_depth); 491 atomic_set(&rdma->excess_rc, 0); 492 493 return rdma; 494 } 495 496 static int rdma_cancel(struct p9_client *client, struct p9_req_t *req) 497 { 498 /* Nothing to do here. 499 * We will take care of it (if we have to) in rdma_cancelled() 500 */ 501 return 1; 502 } 503 504 /* A request has been fully flushed without a reply. 505 * That means we have posted one buffer in excess. 506 */ 507 static int rdma_cancelled(struct p9_client *client, struct p9_req_t *req) 508 { 509 struct p9_trans_rdma *rdma = client->trans; 510 atomic_inc(&rdma->excess_rc); 511 return 0; 512 } 513 514 static int p9_rdma_bind_privport(struct p9_trans_rdma *rdma) 515 { 516 struct sockaddr_in cl = { 517 .sin_family = AF_INET, 518 .sin_addr.s_addr = htonl(INADDR_ANY), 519 }; 520 int port, err = -EINVAL; 521 522 for (port = P9_DEF_MAX_RESVPORT; port >= P9_DEF_MIN_RESVPORT; port--) { 523 cl.sin_port = htons((ushort)port); 524 err = rdma_bind_addr(rdma->cm_id, (struct sockaddr *)&cl); 525 if (err != -EADDRINUSE) 526 break; 527 } 528 return err; 529 } 530 531 /** 532 * rdma_create_trans - Transport method for creating a transport instance 533 * @client: client instance 534 * @fc: The filesystem context 535 */ 536 static int 537 rdma_create_trans(struct p9_client *client, struct fs_context *fc) 538 { 539 const char *addr = fc->source; 540 struct v9fs_context *ctx = fc->fs_private; 541 struct p9_rdma_opts opts = ctx->rdma_opts; 542 int err; 543 struct p9_trans_rdma *rdma; 544 struct rdma_conn_param conn_param; 545 struct ib_qp_init_attr qp_attr; 546 547 if (addr == NULL) 548 return -EINVAL; 549 550 /* options are already parsed, in the fs context */ 551 opts = ctx->rdma_opts; 552 553 /* Create and initialize the RDMA transport structure */ 554 rdma = alloc_rdma(&opts); 555 if (!rdma) 556 return -ENOMEM; 557 558 /* Create the RDMA CM ID */ 559 rdma->cm_id = rdma_create_id(&init_net, p9_cm_event_handler, client, 560 RDMA_PS_TCP, IB_QPT_RC); 561 if (IS_ERR(rdma->cm_id)) 562 goto error; 563 564 /* Associate the client with the transport */ 565 client->trans = rdma; 566 567 /* Bind to a privileged port if we need to */ 568 if (opts.privport) { 569 err = p9_rdma_bind_privport(rdma); 570 if (err < 0) { 571 pr_err("%s (%d): problem binding to privport: %d\n", 572 __func__, task_pid_nr(current), -err); 573 goto error; 574 } 575 } 576 577 /* Resolve the server's address */ 578 rdma->addr.sin_family = AF_INET; 579 rdma->addr.sin_addr.s_addr = in_aton(addr); 580 rdma->addr.sin_port = htons(opts.port); 581 err = rdma_resolve_addr(rdma->cm_id, NULL, 582 (struct sockaddr *)&rdma->addr, 583 rdma->timeout); 584 if (err) 585 goto error; 586 err = wait_for_completion_interruptible(&rdma->cm_done); 587 if (err || (rdma->state != P9_RDMA_ADDR_RESOLVED)) 588 goto error; 589 590 /* Resolve the route to the server */ 591 err = rdma_resolve_route(rdma->cm_id, rdma->timeout); 592 if (err) 593 goto error; 594 err = wait_for_completion_interruptible(&rdma->cm_done); 595 if (err || (rdma->state != P9_RDMA_ROUTE_RESOLVED)) 596 goto error; 597 598 /* Create the Completion Queue */ 599 rdma->cq = ib_alloc_cq_any(rdma->cm_id->device, client, 600 opts.sq_depth + opts.rq_depth + 1, 601 IB_POLL_SOFTIRQ); 602 if (IS_ERR(rdma->cq)) 603 goto error; 604 605 /* Create the Protection Domain */ 606 rdma->pd = ib_alloc_pd(rdma->cm_id->device, 0); 607 if (IS_ERR(rdma->pd)) 608 goto error; 609 610 /* Create the Queue Pair */ 611 memset(&qp_attr, 0, sizeof qp_attr); 612 qp_attr.event_handler = qp_event_handler; 613 qp_attr.qp_context = client; 614 qp_attr.cap.max_send_wr = opts.sq_depth; 615 qp_attr.cap.max_recv_wr = opts.rq_depth; 616 qp_attr.cap.max_send_sge = P9_RDMA_SEND_SGE; 617 qp_attr.cap.max_recv_sge = P9_RDMA_RECV_SGE; 618 qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR; 619 qp_attr.qp_type = IB_QPT_RC; 620 qp_attr.send_cq = rdma->cq; 621 qp_attr.recv_cq = rdma->cq; 622 err = rdma_create_qp(rdma->cm_id, rdma->pd, &qp_attr); 623 if (err) 624 goto error; 625 rdma->qp = rdma->cm_id->qp; 626 627 /* Request a connection */ 628 memset(&conn_param, 0, sizeof(conn_param)); 629 conn_param.private_data = NULL; 630 conn_param.private_data_len = 0; 631 conn_param.responder_resources = P9_RDMA_IRD; 632 conn_param.initiator_depth = P9_RDMA_ORD; 633 err = rdma_connect(rdma->cm_id, &conn_param); 634 if (err) 635 goto error; 636 err = wait_for_completion_interruptible(&rdma->cm_done); 637 if (err || (rdma->state != P9_RDMA_CONNECTED)) 638 goto error; 639 640 client->status = Connected; 641 642 return 0; 643 644 error: 645 rdma_destroy_trans(rdma); 646 return -ENOTCONN; 647 } 648 649 static struct p9_trans_module p9_rdma_trans = { 650 .name = "rdma", 651 .maxsize = P9_RDMA_MAXSIZE, 652 .pooled_rbuffers = true, 653 .def = false, 654 .supports_vmalloc = false, 655 .owner = THIS_MODULE, 656 .create = rdma_create_trans, 657 .close = rdma_close, 658 .request = rdma_request, 659 .cancel = rdma_cancel, 660 .cancelled = rdma_cancelled, 661 .show_options = p9_rdma_show_options, 662 }; 663 664 /** 665 * p9_trans_rdma_init - Register the 9P RDMA transport driver 666 */ 667 static int __init p9_trans_rdma_init(void) 668 { 669 v9fs_register_trans(&p9_rdma_trans); 670 return 0; 671 } 672 673 static void __exit p9_trans_rdma_exit(void) 674 { 675 v9fs_unregister_trans(&p9_rdma_trans); 676 } 677 678 module_init(p9_trans_rdma_init); 679 module_exit(p9_trans_rdma_exit); 680 MODULE_ALIAS_9P("rdma"); 681 682 MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>"); 683 MODULE_DESCRIPTION("RDMA Transport for 9P"); 684 MODULE_LICENSE("Dual BSD/GPL"); 685