aboutsummaryrefslogtreecommitdiffstats
path: root/net/rds
diff options
context:
space:
mode:
Diffstat (limited to 'net/rds')
-rw-r--r--net/rds/loop.c4
-rw-r--r--net/rds/message.c7
-rw-r--r--net/rds/rdma.c128
-rw-r--r--net/rds/send.c4
-rw-r--r--net/rds/tcp.c6
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)
134static void rds_loop_conn_free(void *arg) 134static 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 */
484static int rds_rdma_pages(struct rds_rdma_args *args) 484static 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
509int 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
510int 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;
659out: 695out:
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)
221static void rds_tcp_conn_free(void *arg) 221static 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