diff options
Diffstat (limited to 'net/rds')
| -rw-r--r-- | net/rds/af_rds.c | 99 | ||||
| -rw-r--r-- | net/rds/connection.c | 13 | ||||
| -rw-r--r-- | net/rds/ib_cm.c | 25 | ||||
| -rw-r--r-- | net/rds/ib_send.c | 2 | ||||
| -rw-r--r-- | net/rds/info.c | 78 | ||||
| -rw-r--r-- | net/rds/info.h | 3 | ||||
| -rw-r--r-- | net/rds/send.c | 4 | ||||
| -rw-r--r-- | net/rds/tcp.c | 63 | ||||
| -rw-r--r-- | net/rds/tcp_listen.c | 4 | ||||
| -rw-r--r-- | net/rds/tcp_recv.c | 2 |
10 files changed, 200 insertions, 93 deletions
diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index 76f625986a7f..d5defe9172e3 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -37,13 +37,13 @@ #include <linux/in.h> #include <linux/ipv6.h> #include <linux/poll.h> +#include <linux/uio.h> #include <net/sock.h> #include "rds.h" /* this is just used for stats gathering :/ */ static DEFINE_SPINLOCK(rds_sock_lock); -static unsigned long rds_sock_count; static LIST_HEAD(rds_sock_list); DECLARE_WAIT_QUEUE_HEAD(rds_poll_waitq); @@ -82,7 +82,6 @@ static int rds_release(struct socket *sock) spin_lock_bh(&rds_sock_lock); list_del_init(&rs->rs_item); - rds_sock_count--; spin_unlock_bh(&rds_sock_lock); rds_trans_put(rs->rs_transport); @@ -219,7 +218,7 @@ static __poll_t rds_poll(struct file *file, struct socket *sock, poll_wait(file, sk_sleep(sk), wait); - if (rs->rs_seen_congestion) + if (READ_ONCE(rs->rs_seen_congestion)) poll_wait(file, &rds_poll_waitq, wait); read_lock_irqsave(&rs->rs_recv_lock, flags); @@ -247,7 +246,7 @@ static __poll_t rds_poll(struct file *file, struct socket *sock, /* clear state any time we wake a seen-congested socket */ if (mask) - rs->rs_seen_congestion = 0; + WRITE_ONCE(rs->rs_seen_congestion, 0); return mask; } @@ -487,35 +486,36 @@ out: } static int rds_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) + sockopt_t *opt) { struct rds_sock *rs = rds_sk_to_rs(sock->sk); int ret = -ENOPROTOOPT, len; int trans; + int val; if (level != SOL_RDS) goto out; - if (get_user(len, optlen)) { - ret = -EFAULT; - goto out; - } + len = opt->optlen; switch (optname) { case RDS_INFO_FIRST ... RDS_INFO_LAST: - ret = rds_info_getsockopt(sock, optname, optval, - optlen); + ret = rds_info_getsockopt(sock, optname, opt); break; case RDS_RECVERR: - if (len < sizeof(int)) + if (len < sizeof(int)) { ret = -EINVAL; - else - if (put_user(rs->rs_recverr, (int __user *) optval) || - put_user(sizeof(int), optlen)) + break; + } + val = rs->rs_recverr; + if (copy_to_iter(&val, sizeof(int), &opt->iter_out) != + sizeof(int)) { ret = -EFAULT; - else + } else { + opt->optlen = sizeof(int); ret = 0; + } break; case SO_RDS_TRANSPORT: if (len < sizeof(int)) { @@ -524,11 +524,13 @@ static int rds_getsockopt(struct socket *sock, int level, int optname, } trans = (rs->rs_transport ? rs->rs_transport->t_type : RDS_TRANS_NONE); /* unbound */ - if (put_user(trans, (int __user *)optval) || - put_user(sizeof(int), optlen)) + if (copy_to_iter(&trans, sizeof(int), &opt->iter_out) != + sizeof(int)) { ret = -EFAULT; - else + } else { + opt->optlen = sizeof(int); ret = 0; + } break; default: break; @@ -655,7 +657,7 @@ static const struct proto_ops rds_proto_ops = { .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = rds_setsockopt, - .getsockopt = rds_getsockopt, + .getsockopt_iter = rds_getsockopt, .sendmsg = rds_sendmsg, .recvmsg = rds_recvmsg, .mmap = sock_no_mmap, @@ -694,7 +696,6 @@ static int __rds_create(struct socket *sock, struct sock *sk, int protocol) spin_lock_bh(&rds_sock_lock); list_add_tail(&rs->rs_item, &rds_sock_list); - rds_sock_count++; spin_unlock_bh(&rds_sock_lock); return 0; @@ -735,6 +736,7 @@ static void rds_sock_inc_info(struct socket *sock, unsigned int len, struct rds_info_iterator *iter, struct rds_info_lengths *lens) { + struct net *net = sock_net(sock->sk); struct rds_sock *rs; struct rds_incoming *inc; unsigned int total = 0; @@ -744,6 +746,9 @@ static void rds_sock_inc_info(struct socket *sock, unsigned int len, spin_lock_bh(&rds_sock_lock); list_for_each_entry(rs, &rds_sock_list, rs_item) { + /* Only show sockets in the caller's netns. */ + if (!net_eq(sock_net(rds_rs_to_sk(rs)), net)) + continue; /* This option only supports IPv4 sockets. */ if (!ipv6_addr_v4mapped(&rs->rs_bound_addr)) continue; @@ -774,6 +779,7 @@ static void rds6_sock_inc_info(struct socket *sock, unsigned int len, struct rds_info_iterator *iter, struct rds_info_lengths *lens) { + struct net *net = sock_net(sock->sk); struct rds_incoming *inc; unsigned int total = 0; struct rds_sock *rs; @@ -783,6 +789,9 @@ static void rds6_sock_inc_info(struct socket *sock, unsigned int len, spin_lock_bh(&rds_sock_lock); list_for_each_entry(rs, &rds_sock_list, rs_item) { + /* Only show sockets in the caller's netns. */ + if (!net_eq(sock_net(rds_rs_to_sk(rs)), net)) + continue; read_lock(&rs->rs_recv_lock); list_for_each_entry(inc, &rs->rs_recv_queue, i_item) { @@ -806,7 +815,9 @@ static void rds_sock_info(struct socket *sock, unsigned int len, struct rds_info_iterator *iter, struct rds_info_lengths *lens) { + struct net *net = sock_net(sock->sk); struct rds_info_socket sinfo; + unsigned int copied = 0; unsigned int cnt = 0; struct rds_sock *rs; @@ -814,12 +825,24 @@ static void rds_sock_info(struct socket *sock, unsigned int len, spin_lock_bh(&rds_sock_lock); - if (len < rds_sock_count) { - cnt = rds_sock_count; - goto out; + /* First pass: count entries visible in the caller's netns. */ + list_for_each_entry(rs, &rds_sock_list, rs_item) { + if (!net_eq(sock_net(rds_rs_to_sk(rs)), net)) + continue; + if (!ipv6_addr_v4mapped(&rs->rs_bound_addr)) + continue; + cnt++; } + if (len < cnt) + goto out; + list_for_each_entry(rs, &rds_sock_list, rs_item) { + if (copied >= cnt) + break; + /* Only show sockets in the caller's netns. */ + if (!net_eq(sock_net(rds_rs_to_sk(rs)), net)) + continue; /* This option only supports IPv4 sockets. */ if (!ipv6_addr_v4mapped(&rs->rs_bound_addr)) continue; @@ -832,8 +855,13 @@ static void rds_sock_info(struct socket *sock, unsigned int len, sinfo.inum = sock_i_ino(rds_rs_to_sk(rs)); rds_info_copy(iter, &sinfo, sizeof(sinfo)); - cnt++; + copied++; } + /* A concurrent rds_bind() can change rs_bound_addr between the + * two passes without holding rds_sock_lock, so copied may be + * less than cnt. Report what was actually copied. + */ + cnt = copied; out: lens->nr = cnt; @@ -847,17 +875,32 @@ static void rds6_sock_info(struct socket *sock, unsigned int len, struct rds_info_iterator *iter, struct rds_info_lengths *lens) { + struct net *net = sock_net(sock->sk); struct rds6_info_socket sinfo6; + unsigned int copied = 0; + unsigned int cnt = 0; struct rds_sock *rs; len /= sizeof(struct rds6_info_socket); spin_lock_bh(&rds_sock_lock); - if (len < rds_sock_count) + /* First pass: count entries visible in the caller's netns. */ + list_for_each_entry(rs, &rds_sock_list, rs_item) { + if (!net_eq(sock_net(rds_rs_to_sk(rs)), net)) + continue; + cnt++; + } + + if (len < cnt) goto out; list_for_each_entry(rs, &rds_sock_list, rs_item) { + if (copied >= cnt) + break; + /* Only show sockets in the caller's netns. */ + if (!net_eq(sock_net(rds_rs_to_sk(rs)), net)) + continue; sinfo6.sndbuf = rds_sk_sndbuf(rs); sinfo6.rcvbuf = rds_sk_rcvbuf(rs); sinfo6.bound_addr = rs->rs_bound_addr; @@ -867,10 +910,12 @@ static void rds6_sock_info(struct socket *sock, unsigned int len, sinfo6.inum = sock_i_ino(rds_rs_to_sk(rs)); rds_info_copy(iter, &sinfo6, sizeof(sinfo6)); + copied++; } + cnt = copied; out: - lens->nr = rds_sock_count; + lens->nr = cnt; lens->each = sizeof(struct rds6_info_socket); spin_unlock_bh(&rds_sock_lock); diff --git a/net/rds/connection.c b/net/rds/connection.c index c10b7ed06c49..7c8ab8e973e1 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -568,6 +568,7 @@ static void rds_conn_message_info_cmn(struct socket *sock, unsigned int len, struct rds_info_lengths *lens, int want_send, bool isv6) { + struct net *net = sock_net(sock->sk); struct hlist_head *head; struct list_head *list; struct rds_connection *conn; @@ -590,6 +591,9 @@ static void rds_conn_message_info_cmn(struct socket *sock, unsigned int len, struct rds_conn_path *cp; int npaths; + /* Only show connections in the caller's netns. */ + if (!net_eq(rds_conn_net(conn), net)) + continue; if (!isv6 && conn->c_isv6) continue; @@ -688,6 +692,7 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, u64 *buffer, size_t item_len) { + struct net *net = sock_net(sock->sk); struct hlist_head *head; struct rds_connection *conn; size_t i; @@ -700,6 +705,9 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash); i++, head++) { hlist_for_each_entry_rcu(conn, head, c_hash_node) { + /* Only show connections in the caller's netns. */ + if (!net_eq(rds_conn_net(conn), net)) + continue; /* Zero the per-item buffer before handing it to the * visitor so any field the visitor does not write - @@ -733,6 +741,7 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len, u64 *buffer, size_t item_len) { + struct net *net = sock_net(sock->sk); struct hlist_head *head; struct rds_connection *conn; size_t i; @@ -747,6 +756,10 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len, hlist_for_each_entry_rcu(conn, head, c_hash_node) { struct rds_conn_path *cp; + /* Only show connections in the caller's netns. */ + if (!net_eq(rds_conn_net(conn), net)) + continue; + /* XXX We only copy the information from the first * path for now. The problem is that if there are * more than one underlying paths, we cannot report diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 4001de0c4959..5667f0173b47 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -1039,6 +1039,19 @@ out: return ret; } +static unsigned long rds_ib_conn_path_shutdown_check_wait(struct rds_conn_path *cp) +{ + struct rds_connection *conn = cp->cp_conn; + struct rds_ib_connection *ic = conn->c_transport_data; + + return (!ic->i_cm_id || + (rds_ib_ring_empty(&ic->i_recv_ring) && + (atomic_read(&ic->i_signaled_sends) == 0) && + (atomic_read(&ic->i_fastreg_inuse_count)) == 0 && + (atomic_read(&ic->i_fastreg_wrs) == RDS_IB_DEFAULT_FR_WR))) ? 0 + : msecs_to_jiffies(1000); +} + /* * This is so careful about only cleaning up resources that were built up * so that it can be called at any point during startup. In fact it @@ -1079,11 +1092,13 @@ void rds_ib_conn_path_shutdown(struct rds_conn_path *cp) * sends to complete we're ensured that there will be no * more tx processing. */ - wait_event(rds_ib_ring_empty_wait, - rds_ib_ring_empty(&ic->i_recv_ring) && - (atomic_read(&ic->i_signaled_sends) == 0) && - (atomic_read(&ic->i_fastreg_inuse_count) == 0) && - (atomic_read(&ic->i_fastreg_wrs) == RDS_IB_DEFAULT_FR_WR)); + while (!wait_event_timeout(rds_ib_ring_empty_wait, + rds_ib_conn_path_shutdown_check_wait(cp) == 0, + msecs_to_jiffies(1000))) { + tasklet_schedule(&ic->i_send_tasklet); + tasklet_schedule(&ic->i_recv_tasklet); + } + tasklet_kill(&ic->i_send_tasklet); tasklet_kill(&ic->i_recv_tasklet); diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c index fcd04c29f543..d6be95542119 100644 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c @@ -170,6 +170,8 @@ static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic, break; case IB_WR_ATOMIC_FETCH_AND_ADD: case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: + case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: if (send->s_op) { rm = container_of(send->s_op, struct rds_message, atomic); rds_ib_send_unmap_atomic(ic, send->s_op, wc_status); diff --git a/net/rds/info.c b/net/rds/info.c index f1b29994934a..21b32eb16559 100644 --- a/net/rds/info.c +++ b/net/rds/info.c @@ -35,6 +35,7 @@ #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/export.h> +#include <linux/uio.h> #include "rds.h" @@ -144,60 +145,68 @@ void rds_info_copy(struct rds_info_iterator *iter, void *data, EXPORT_SYMBOL_GPL(rds_info_copy); /* - * @optval points to the userspace buffer that the information snapshot - * will be copied into. - * - * @optlen on input is the size of the buffer in userspace. @optlen - * on output is the size of the requested snapshot in bytes. + * @opt->iter_out describes the buffer that the information snapshot will be + * copied into, and @opt->optlen is the size of that buffer on input. On + * output @opt->optlen is set to the size of the requested snapshot in bytes. * * This function returns -errno if there is a failure, particularly -ENOSPC - * if the given userspace buffer was not large enough to fit the snapshot. - * On success it returns the positive number of bytes of each array element - * in the snapshot. + * if the given buffer was not large enough to fit the snapshot. On success + * it returns the positive number of bytes of each array element in the + * snapshot. */ -int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, - int __user *optlen) +int rds_info_getsockopt(struct socket *sock, int optname, sockopt_t *opt) { struct rds_info_iterator iter; struct rds_info_lengths lens; unsigned long nr_pages = 0; - unsigned long start; rds_info_func func; struct page **pages = NULL; + size_t offset0 = 0; + int npages = 0; int ret; int len; int total; - if (get_user(len, optlen)) { - ret = -EFAULT; - goto out; - } + len = opt->optlen; /* check for all kinds of wrapping and the like */ - start = (unsigned long)optval; - if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 || start + len < start) { + if (len < 0 || len > INT_MAX - PAGE_SIZE + 1) { ret = -EINVAL; goto out; } + /* The info producers write into the pages with kmap_atomic() while + * holding a spinlock, so they need a genuine page-backed user buffer. + */ + if (!user_backed_iter(&opt->iter_out)) { + ret = -EOPNOTSUPP; + goto out; + } + /* a 0 len call is just trying to probe its length */ if (len == 0) goto call_func; - nr_pages = (PAGE_ALIGN(start + len) - (start & PAGE_MASK)) - >> PAGE_SHIFT; - - pages = kmalloc_objs(struct page *, nr_pages); + /* + * Preallocate the page array and pass it in so that + * iov_iter_extract_pages() fills it in place rather than allocating + * one for us. Handing it a non-NULL array keeps ownership of the + * array with us on every return path, instead of depending on the + * iterator code to allocate and hand it back. + */ + npages = iov_iter_npages(&opt->iter_out, INT_MAX); + pages = kvmalloc_array(npages, sizeof(*pages), GFP_KERNEL); if (!pages) { ret = -ENOMEM; goto out; } - ret = pin_user_pages_fast(start, nr_pages, FOLL_WRITE, pages); - if (ret != nr_pages) { - if (ret > 0) - nr_pages = ret; - else - nr_pages = 0; + + ret = iov_iter_extract_pages(&opt->iter_out, &pages, len, npages, + 0, &offset0); + if (ret < 0) + goto out; + nr_pages = DIV_ROUND_UP(offset0 + ret, PAGE_SIZE); + if (ret != len) { ret = -EAGAIN; /* XXX ? */ goto out; } @@ -213,7 +222,7 @@ call_func: iter.pages = pages; iter.addr = NULL; - iter.offset = start & (PAGE_SIZE - 1); + iter.offset = offset0; func(sock, len, &iter, &lens); BUG_ON(lens.each == 0); @@ -230,13 +239,16 @@ call_func: ret = lens.each; } - if (put_user(len, optlen)) - ret = -EFAULT; + opt->optlen = len; out: - if (pages) - unpin_user_pages(pages, nr_pages); - kfree(pages); + /* + * iov_iter_extract_pages() pins only user-backed (ubuf) iters; + * iov_iter_extract_will_pin() reports whether an unpin is owed here. + */ + if (pages && iov_iter_extract_will_pin(&opt->iter_out)) + unpin_user_pages_dirty_lock(pages, nr_pages, true); + kvfree(pages); return ret; } diff --git a/net/rds/info.h b/net/rds/info.h index a069b51c4679..1aab62ab6d00 100644 --- a/net/rds/info.h +++ b/net/rds/info.h @@ -21,8 +21,7 @@ typedef void (*rds_info_func)(struct socket *sock, unsigned int len, void rds_info_register_func(int optname, rds_info_func func); void rds_info_deregister_func(int optname, rds_info_func func); -int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, - int __user *optlen); +int rds_info_getsockopt(struct socket *sock, int optname, sockopt_t *opt); void rds_info_copy(struct rds_info_iterator *iter, void *data, unsigned long bytes); void rds_info_iter_unmap(struct rds_info_iterator *iter); diff --git a/net/rds/send.c b/net/rds/send.c index d8b14ff9d366..68be1bf0e0ad 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -967,6 +967,8 @@ static int rds_rm_size(struct msghdr *msg, int num_sgs, switch (cmsg->cmsg_type) { case RDS_CMSG_RDMA_ARGS: + if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_rdma_args))) + return -EINVAL; if (vct->indx >= vct->len) { vct->len += vct->incr; tmp_iov = @@ -1388,7 +1390,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) ret = rds_cong_wait(conn->c_fcong, dport, nonblock, rs); if (ret) { - rs->rs_seen_congestion = 1; + WRITE_ONCE(rs->rs_seen_congestion, 1); goto out; } while (!rds_send_queue_rm(rs, conn, cpath, rm, rs->rs_bound_port, diff --git a/net/rds/tcp.c b/net/rds/tcp.c index 5830b31a1f37..a1de114d5e2e 100644 --- a/net/rds/tcp.c +++ b/net/rds/tcp.c @@ -46,14 +46,6 @@ static DEFINE_SPINLOCK(rds_tcp_tc_list_lock); static LIST_HEAD(rds_tcp_tc_list); -/* rds_tcp_tc_count counts only IPv4 connections. - * rds6_tcp_tc_count counts both IPv4 and IPv6 connections. - */ -static unsigned int rds_tcp_tc_count; -#if IS_ENABLED(CONFIG_IPV6) -static unsigned int rds6_tcp_tc_count; -#endif - /* Track rds_tcp_connection structs so they can be cleaned up */ static DEFINE_SPINLOCK(rds_tcp_conn_lock); static LIST_HEAD(rds_tcp_conn_list); @@ -110,11 +102,6 @@ void rds_tcp_restore_callbacks(struct socket *sock, /* done under the callback_lock to serialize with write_space */ spin_lock(&rds_tcp_tc_list_lock); list_del_init(&tc->t_list_item); -#if IS_ENABLED(CONFIG_IPV6) - rds6_tcp_tc_count--; -#endif - if (!tc->t_cpath->cp_conn->c_isv6) - rds_tcp_tc_count--; spin_unlock(&rds_tcp_tc_list_lock); tc->t_sock = NULL; @@ -206,11 +193,6 @@ void rds_tcp_set_callbacks(struct socket *sock, struct rds_conn_path *cp) spin_lock(&rds_tcp_tc_list_lock); tc->t_sock = sock; list_add_tail(&tc->t_list_item, &rds_tcp_tc_list); -#if IS_ENABLED(CONFIG_IPV6) - rds6_tcp_tc_count++; -#endif - if (!tc->t_cpath->cp_conn->c_isv6) - rds_tcp_tc_count++; spin_unlock(&rds_tcp_tc_list_lock); /* accepted sockets need our listen data ready undone */ @@ -238,20 +220,37 @@ static void rds_tcp_tc_info(struct socket *rds_sock, unsigned int len, struct rds_info_iterator *iter, struct rds_info_lengths *lens) { + struct net *net = sock_net(rds_sock->sk); struct rds_info_tcp_socket tsinfo; struct rds_tcp_connection *tc; + unsigned int copied = 0; + unsigned int cnt = 0; unsigned long flags; spin_lock_irqsave(&rds_tcp_tc_list_lock, flags); - if (len / sizeof(tsinfo) < rds_tcp_tc_count) + /* First pass: count entries visible in the caller's netns. */ + list_for_each_entry(tc, &rds_tcp_tc_list, t_list_item) { + if (tc->t_cpath->cp_conn->c_isv6) + continue; + if (!net_eq(rds_conn_net(tc->t_cpath->cp_conn), net)) + continue; + cnt++; + } + + if (len / sizeof(tsinfo) < cnt) goto out; list_for_each_entry(tc, &rds_tcp_tc_list, t_list_item) { struct inet_sock *inet = inet_sk(tc->t_sock->sk); + if (copied >= cnt) + break; if (tc->t_cpath->cp_conn->c_isv6) continue; + /* Only show connections in the caller's netns. */ + if (!net_eq(rds_conn_net(tc->t_cpath->cp_conn), net)) + continue; tsinfo.local_addr = inet->inet_saddr; tsinfo.local_port = inet->inet_sport; @@ -266,10 +265,12 @@ static void rds_tcp_tc_info(struct socket *rds_sock, unsigned int len, tsinfo.tos = tc->t_cpath->cp_conn->c_tos; rds_info_copy(iter, &tsinfo, sizeof(tsinfo)); + copied++; } + cnt = copied; out: - lens->nr = rds_tcp_tc_count; + lens->nr = cnt; lens->each = sizeof(tsinfo); spin_unlock_irqrestore(&rds_tcp_tc_list_lock, flags); @@ -284,19 +285,35 @@ static void rds6_tcp_tc_info(struct socket *sock, unsigned int len, struct rds_info_iterator *iter, struct rds_info_lengths *lens) { + struct net *net = sock_net(sock->sk); struct rds6_info_tcp_socket tsinfo6; struct rds_tcp_connection *tc; + unsigned int copied = 0; + unsigned int cnt = 0; unsigned long flags; spin_lock_irqsave(&rds_tcp_tc_list_lock, flags); - if (len / sizeof(tsinfo6) < rds6_tcp_tc_count) + /* First pass: count entries visible in the caller's netns. */ + list_for_each_entry(tc, &rds_tcp_tc_list, t_list_item) { + if (!net_eq(rds_conn_net(tc->t_cpath->cp_conn), net)) + continue; + cnt++; + } + + if (len / sizeof(tsinfo6) < cnt) goto out; list_for_each_entry(tc, &rds_tcp_tc_list, t_list_item) { struct sock *sk = tc->t_sock->sk; struct inet_sock *inet = inet_sk(sk); + if (copied >= cnt) + break; + /* Only show connections in the caller's netns. */ + if (!net_eq(rds_conn_net(tc->t_cpath->cp_conn), net)) + continue; + tsinfo6.local_addr = sk->sk_v6_rcv_saddr; tsinfo6.local_port = inet->inet_sport; tsinfo6.peer_addr = sk->sk_v6_daddr; @@ -309,10 +326,12 @@ static void rds6_tcp_tc_info(struct socket *sock, unsigned int len, tsinfo6.last_seen_una = tc->t_last_seen_una; rds_info_copy(iter, &tsinfo6, sizeof(tsinfo6)); + copied++; } + cnt = copied; out: - lens->nr = rds6_tcp_tc_count; + lens->nr = cnt; lens->each = sizeof(tsinfo6); spin_unlock_irqrestore(&rds_tcp_tc_list_lock, flags); diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c index 08a506aa7ce7..a3db9b057084 100644 --- a/net/rds/tcp_listen.c +++ b/net/rds/tcp_listen.c @@ -69,7 +69,7 @@ rds_tcp_get_peer_sport(struct socket *sock) /* rds_tcp_accept_one_path(): if accepting on cp_index > 0, make sure the * client's ipaddr < server's ipaddr. Otherwise, close the accepted - * socket and force a reconneect from smaller -> larger ip addr. The reason + * socket and force a reconnect from smaller -> larger ip addr. The reason * we special case cp_index 0 is to allow the rds probe ping itself to itself * get through efficiently. */ @@ -143,7 +143,7 @@ void rds_tcp_conn_slots_available(struct rds_connection *conn, bool fan_out) * * Doing so is necessary to address the case where an * incoming connection on "rds_tcp_listen_sock" is ready - * to be acccepted prior to a free slot being available: + * to be accepted prior to a free slot being available: * the -ENOBUFS case in "rds_tcp_accept_one". */ rds_tcp_accept_work(rtn); diff --git a/net/rds/tcp_recv.c b/net/rds/tcp_recv.c index 49f96ee0c40f..ffe843ca219c 100644 --- a/net/rds/tcp_recv.c +++ b/net/rds/tcp_recv.c @@ -275,7 +275,7 @@ static int rds_tcp_read_sock(struct rds_conn_path *cp, gfp_t gfp) desc.count = 1; /* give more than one skb per call */ tcp_read_sock(sock->sk, &desc, rds_tcp_data_recv); - rdsdebug("tcp_read_sock for tc %p gfp 0x%x returned %d\n", tc, gfp, + rdsdebug("tcp_read_sock for tc %p gfp %pGg returned %d\n", tc, &gfp, desc.error); if (skb_queue_empty_lockless(&sock->sk->sk_receive_queue) && |
