diff options
Diffstat (limited to 'net/rds')
-rw-r--r-- | net/rds/loop.c | 4 | ||||
-rw-r--r-- | net/rds/message.c | 7 | ||||
-rw-r--r-- | net/rds/rdma.c | 128 | ||||
-rw-r--r-- | net/rds/send.c | 4 | ||||
-rw-r--r-- | net/rds/tcp.c | 6 |
5 files changed, 106 insertions, 43 deletions
diff --git a/net/rds/loop.c b/net/rds/loop.c index c390156b426f..aeec1d483b17 100644 --- a/net/rds/loop.c +++ b/net/rds/loop.c | |||
@@ -134,8 +134,12 @@ static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp) | |||
134 | static void rds_loop_conn_free(void *arg) | 134 | static void rds_loop_conn_free(void *arg) |
135 | { | 135 | { |
136 | struct rds_loop_connection *lc = arg; | 136 | struct rds_loop_connection *lc = arg; |
137 | unsigned long flags; | ||
138 | |||
137 | rdsdebug("lc %p\n", lc); | 139 | rdsdebug("lc %p\n", lc); |
140 | spin_lock_irqsave(&loop_conns_lock, flags); | ||
138 | list_del(&lc->loop_node); | 141 | list_del(&lc->loop_node); |
142 | spin_unlock_irqrestore(&loop_conns_lock, flags); | ||
139 | kfree(lc); | 143 | kfree(lc); |
140 | } | 144 | } |
141 | 145 | ||
diff --git a/net/rds/message.c b/net/rds/message.c index a84545dae370..1fd3d29023d7 100644 --- a/net/rds/message.c +++ b/net/rds/message.c | |||
@@ -224,6 +224,9 @@ struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents) | |||
224 | WARN_ON(rm->m_used_sgs + nents > rm->m_total_sgs); | 224 | WARN_ON(rm->m_used_sgs + nents > rm->m_total_sgs); |
225 | WARN_ON(!nents); | 225 | WARN_ON(!nents); |
226 | 226 | ||
227 | if (rm->m_used_sgs + nents > rm->m_total_sgs) | ||
228 | return NULL; | ||
229 | |||
227 | sg_ret = &sg_first[rm->m_used_sgs]; | 230 | sg_ret = &sg_first[rm->m_used_sgs]; |
228 | sg_init_table(sg_ret, nents); | 231 | sg_init_table(sg_ret, nents); |
229 | rm->m_used_sgs += nents; | 232 | rm->m_used_sgs += nents; |
@@ -246,6 +249,10 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in | |||
246 | rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len); | 249 | rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len); |
247 | rm->data.op_nents = ceil(total_len, PAGE_SIZE); | 250 | rm->data.op_nents = ceil(total_len, PAGE_SIZE); |
248 | rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs); | 251 | rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs); |
252 | if (!rm->data.op_sg) { | ||
253 | rds_message_put(rm); | ||
254 | return ERR_PTR(-ENOMEM); | ||
255 | } | ||
249 | 256 | ||
250 | for (i = 0; i < rm->data.op_nents; ++i) { | 257 | for (i = 0; i < rm->data.op_nents; ++i) { |
251 | sg_set_page(&rm->data.op_sg[i], | 258 | sg_set_page(&rm->data.op_sg[i], |
diff --git a/net/rds/rdma.c b/net/rds/rdma.c index 1a41debca1ce..4e37c1cbe8b2 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c | |||
@@ -479,13 +479,38 @@ void rds_atomic_free_op(struct rm_atomic_op *ao) | |||
479 | 479 | ||
480 | 480 | ||
481 | /* | 481 | /* |
482 | * Count the number of pages needed to describe an incoming iovec. | 482 | * Count the number of pages needed to describe an incoming iovec array. |
483 | */ | 483 | */ |
484 | static int rds_rdma_pages(struct rds_rdma_args *args) | 484 | static int rds_rdma_pages(struct rds_iovec iov[], int nr_iovecs) |
485 | { | ||
486 | int tot_pages = 0; | ||
487 | unsigned int nr_pages; | ||
488 | unsigned int i; | ||
489 | |||
490 | /* figure out the number of pages in the vector */ | ||
491 | for (i = 0; i < nr_iovecs; i++) { | ||
492 | nr_pages = rds_pages_in_vec(&iov[i]); | ||
493 | if (nr_pages == 0) | ||
494 | return -EINVAL; | ||
495 | |||
496 | tot_pages += nr_pages; | ||
497 | |||
498 | /* | ||
499 | * nr_pages for one entry is limited to (UINT_MAX>>PAGE_SHIFT)+1, | ||
500 | * so tot_pages cannot overflow without first going negative. | ||
501 | */ | ||
502 | if (tot_pages < 0) | ||
503 | return -EINVAL; | ||
504 | } | ||
505 | |||
506 | return tot_pages; | ||
507 | } | ||
508 | |||
509 | int rds_rdma_extra_size(struct rds_rdma_args *args) | ||
485 | { | 510 | { |
486 | struct rds_iovec vec; | 511 | struct rds_iovec vec; |
487 | struct rds_iovec __user *local_vec; | 512 | struct rds_iovec __user *local_vec; |
488 | unsigned int tot_pages = 0; | 513 | int tot_pages = 0; |
489 | unsigned int nr_pages; | 514 | unsigned int nr_pages; |
490 | unsigned int i; | 515 | unsigned int i; |
491 | 516 | ||
@@ -502,14 +527,16 @@ static int rds_rdma_pages(struct rds_rdma_args *args) | |||
502 | return -EINVAL; | 527 | return -EINVAL; |
503 | 528 | ||
504 | tot_pages += nr_pages; | 529 | tot_pages += nr_pages; |
505 | } | ||
506 | 530 | ||
507 | return tot_pages; | 531 | /* |
508 | } | 532 | * nr_pages for one entry is limited to (UINT_MAX>>PAGE_SHIFT)+1, |
533 | * so tot_pages cannot overflow without first going negative. | ||
534 | */ | ||
535 | if (tot_pages < 0) | ||
536 | return -EINVAL; | ||
537 | } | ||
509 | 538 | ||
510 | int rds_rdma_extra_size(struct rds_rdma_args *args) | 539 | return tot_pages * sizeof(struct scatterlist); |
511 | { | ||
512 | return rds_rdma_pages(args) * sizeof(struct scatterlist); | ||
513 | } | 540 | } |
514 | 541 | ||
515 | /* | 542 | /* |
@@ -520,13 +547,12 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, | |||
520 | struct cmsghdr *cmsg) | 547 | struct cmsghdr *cmsg) |
521 | { | 548 | { |
522 | struct rds_rdma_args *args; | 549 | struct rds_rdma_args *args; |
523 | struct rds_iovec vec; | ||
524 | struct rm_rdma_op *op = &rm->rdma; | 550 | struct rm_rdma_op *op = &rm->rdma; |
525 | int nr_pages; | 551 | int nr_pages; |
526 | unsigned int nr_bytes; | 552 | unsigned int nr_bytes; |
527 | struct page **pages = NULL; | 553 | struct page **pages = NULL; |
528 | struct rds_iovec __user *local_vec; | 554 | struct rds_iovec iovstack[UIO_FASTIOV], *iovs = iovstack; |
529 | unsigned int nr; | 555 | int iov_size; |
530 | unsigned int i, j; | 556 | unsigned int i, j; |
531 | int ret = 0; | 557 | int ret = 0; |
532 | 558 | ||
@@ -541,14 +567,31 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, | |||
541 | goto out; | 567 | goto out; |
542 | } | 568 | } |
543 | 569 | ||
544 | if (args->nr_local > (u64)UINT_MAX) { | 570 | if (args->nr_local > UIO_MAXIOV) { |
545 | ret = -EMSGSIZE; | 571 | ret = -EMSGSIZE; |
546 | goto out; | 572 | goto out; |
547 | } | 573 | } |
548 | 574 | ||
549 | nr_pages = rds_rdma_pages(args); | 575 | /* Check whether to allocate the iovec area */ |
550 | if (nr_pages < 0) | 576 | iov_size = args->nr_local * sizeof(struct rds_iovec); |
577 | if (args->nr_local > UIO_FASTIOV) { | ||
578 | iovs = sock_kmalloc(rds_rs_to_sk(rs), iov_size, GFP_KERNEL); | ||
579 | if (!iovs) { | ||
580 | ret = -ENOMEM; | ||
581 | goto out; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | if (copy_from_user(iovs, (struct rds_iovec __user *)(unsigned long) args->local_vec_addr, iov_size)) { | ||
586 | ret = -EFAULT; | ||
587 | goto out; | ||
588 | } | ||
589 | |||
590 | nr_pages = rds_rdma_pages(iovs, args->nr_local); | ||
591 | if (nr_pages < 0) { | ||
592 | ret = -EINVAL; | ||
551 | goto out; | 593 | goto out; |
594 | } | ||
552 | 595 | ||
553 | pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL); | 596 | pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL); |
554 | if (!pages) { | 597 | if (!pages) { |
@@ -564,6 +607,10 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, | |||
564 | op->op_recverr = rs->rs_recverr; | 607 | op->op_recverr = rs->rs_recverr; |
565 | WARN_ON(!nr_pages); | 608 | WARN_ON(!nr_pages); |
566 | op->op_sg = rds_message_alloc_sgs(rm, nr_pages); | 609 | op->op_sg = rds_message_alloc_sgs(rm, nr_pages); |
610 | if (!op->op_sg) { | ||
611 | ret = -ENOMEM; | ||
612 | goto out; | ||
613 | } | ||
567 | 614 | ||
568 | if (op->op_notify || op->op_recverr) { | 615 | if (op->op_notify || op->op_recverr) { |
569 | /* We allocate an uninitialized notifier here, because | 616 | /* We allocate an uninitialized notifier here, because |
@@ -597,50 +644,40 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, | |||
597 | (unsigned long long)args->remote_vec.addr, | 644 | (unsigned long long)args->remote_vec.addr, |
598 | op->op_rkey); | 645 | op->op_rkey); |
599 | 646 | ||
600 | local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr; | ||
601 | |||
602 | for (i = 0; i < args->nr_local; i++) { | 647 | for (i = 0; i < args->nr_local; i++) { |
603 | if (copy_from_user(&vec, &local_vec[i], | 648 | struct rds_iovec *iov = &iovs[i]; |
604 | sizeof(struct rds_iovec))) { | 649 | /* don't need to check, rds_rdma_pages() verified nr will be +nonzero */ |
605 | ret = -EFAULT; | 650 | unsigned int nr = rds_pages_in_vec(iov); |
606 | goto out; | ||
607 | } | ||
608 | |||
609 | nr = rds_pages_in_vec(&vec); | ||
610 | if (nr == 0) { | ||
611 | ret = -EINVAL; | ||
612 | goto out; | ||
613 | } | ||
614 | 651 | ||
615 | rs->rs_user_addr = vec.addr; | 652 | rs->rs_user_addr = iov->addr; |
616 | rs->rs_user_bytes = vec.bytes; | 653 | rs->rs_user_bytes = iov->bytes; |
617 | 654 | ||
618 | /* If it's a WRITE operation, we want to pin the pages for reading. | 655 | /* If it's a WRITE operation, we want to pin the pages for reading. |
619 | * If it's a READ operation, we need to pin the pages for writing. | 656 | * If it's a READ operation, we need to pin the pages for writing. |
620 | */ | 657 | */ |
621 | ret = rds_pin_pages(vec.addr, nr, pages, !op->op_write); | 658 | ret = rds_pin_pages(iov->addr, nr, pages, !op->op_write); |
622 | if (ret < 0) | 659 | if (ret < 0) |
623 | goto out; | 660 | goto out; |
624 | 661 | ||
625 | rdsdebug("RDS: nr_bytes %u nr %u vec.bytes %llu vec.addr %llx\n", | 662 | rdsdebug("RDS: nr_bytes %u nr %u iov->bytes %llu iov->addr %llx\n", |
626 | nr_bytes, nr, vec.bytes, vec.addr); | 663 | nr_bytes, nr, iov->bytes, iov->addr); |
627 | 664 | ||
628 | nr_bytes += vec.bytes; | 665 | nr_bytes += iov->bytes; |
629 | 666 | ||
630 | for (j = 0; j < nr; j++) { | 667 | for (j = 0; j < nr; j++) { |
631 | unsigned int offset = vec.addr & ~PAGE_MASK; | 668 | unsigned int offset = iov->addr & ~PAGE_MASK; |
632 | struct scatterlist *sg; | 669 | struct scatterlist *sg; |
633 | 670 | ||
634 | sg = &op->op_sg[op->op_nents + j]; | 671 | sg = &op->op_sg[op->op_nents + j]; |
635 | sg_set_page(sg, pages[j], | 672 | sg_set_page(sg, pages[j], |
636 | min_t(unsigned int, vec.bytes, PAGE_SIZE - offset), | 673 | min_t(unsigned int, iov->bytes, PAGE_SIZE - offset), |
637 | offset); | 674 | offset); |
638 | 675 | ||
639 | rdsdebug("RDS: sg->offset %x sg->len %x vec.addr %llx vec.bytes %llu\n", | 676 | rdsdebug("RDS: sg->offset %x sg->len %x iov->addr %llx iov->bytes %llu\n", |
640 | sg->offset, sg->length, vec.addr, vec.bytes); | 677 | sg->offset, sg->length, iov->addr, iov->bytes); |
641 | 678 | ||
642 | vec.addr += sg->length; | 679 | iov->addr += sg->length; |
643 | vec.bytes -= sg->length; | 680 | iov->bytes -= sg->length; |
644 | } | 681 | } |
645 | 682 | ||
646 | op->op_nents += nr; | 683 | op->op_nents += nr; |
@@ -655,13 +692,14 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, | |||
655 | } | 692 | } |
656 | op->op_bytes = nr_bytes; | 693 | op->op_bytes = nr_bytes; |
657 | 694 | ||
658 | ret = 0; | ||
659 | out: | 695 | out: |
696 | if (iovs != iovstack) | ||
697 | sock_kfree_s(rds_rs_to_sk(rs), iovs, iov_size); | ||
660 | kfree(pages); | 698 | kfree(pages); |
661 | if (ret) | 699 | if (ret) |
662 | rds_rdma_free_op(op); | 700 | rds_rdma_free_op(op); |
663 | 701 | else | |
664 | rds_stats_inc(s_send_rdma); | 702 | rds_stats_inc(s_send_rdma); |
665 | 703 | ||
666 | return ret; | 704 | return ret; |
667 | } | 705 | } |
@@ -773,6 +811,10 @@ int rds_cmsg_atomic(struct rds_sock *rs, struct rds_message *rm, | |||
773 | rm->atomic.op_active = 1; | 811 | rm->atomic.op_active = 1; |
774 | rm->atomic.op_recverr = rs->rs_recverr; | 812 | rm->atomic.op_recverr = rs->rs_recverr; |
775 | rm->atomic.op_sg = rds_message_alloc_sgs(rm, 1); | 813 | rm->atomic.op_sg = rds_message_alloc_sgs(rm, 1); |
814 | if (!rm->atomic.op_sg) { | ||
815 | ret = -ENOMEM; | ||
816 | goto err; | ||
817 | } | ||
776 | 818 | ||
777 | /* verify 8 byte-aligned */ | 819 | /* verify 8 byte-aligned */ |
778 | if (args->local_addr & 0x7) { | 820 | if (args->local_addr & 0x7) { |
diff --git a/net/rds/send.c b/net/rds/send.c index 0bc9db17a87d..35b9c2e9caf1 100644 --- a/net/rds/send.c +++ b/net/rds/send.c | |||
@@ -973,6 +973,10 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, | |||
973 | /* Attach data to the rm */ | 973 | /* Attach data to the rm */ |
974 | if (payload_len) { | 974 | if (payload_len) { |
975 | rm->data.op_sg = rds_message_alloc_sgs(rm, ceil(payload_len, PAGE_SIZE)); | 975 | rm->data.op_sg = rds_message_alloc_sgs(rm, ceil(payload_len, PAGE_SIZE)); |
976 | if (!rm->data.op_sg) { | ||
977 | ret = -ENOMEM; | ||
978 | goto out; | ||
979 | } | ||
976 | ret = rds_message_copy_from_user(rm, msg->msg_iov, payload_len); | 980 | ret = rds_message_copy_from_user(rm, msg->msg_iov, payload_len); |
977 | if (ret) | 981 | if (ret) |
978 | goto out; | 982 | goto out; |
diff --git a/net/rds/tcp.c b/net/rds/tcp.c index 08a8c6cf2d10..8e0a32001c90 100644 --- a/net/rds/tcp.c +++ b/net/rds/tcp.c | |||
@@ -221,7 +221,13 @@ static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp) | |||
221 | static void rds_tcp_conn_free(void *arg) | 221 | static void rds_tcp_conn_free(void *arg) |
222 | { | 222 | { |
223 | struct rds_tcp_connection *tc = arg; | 223 | struct rds_tcp_connection *tc = arg; |
224 | unsigned long flags; | ||
224 | rdsdebug("freeing tc %p\n", tc); | 225 | rdsdebug("freeing tc %p\n", tc); |
226 | |||
227 | spin_lock_irqsave(&rds_tcp_conn_lock, flags); | ||
228 | list_del(&tc->t_tcp_node); | ||
229 | spin_unlock_irqrestore(&rds_tcp_conn_lock, flags); | ||
230 | |||
225 | kmem_cache_free(rds_tcp_conn_slab, tc); | 231 | kmem_cache_free(rds_tcp_conn_slab, tc); |
226 | } | 232 | } |
227 | 233 | ||