Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Ursula Braun-Krahl | 985 | 38.96% | 13 | 30.95% |
Stefan Raspl | 973 | 38.49% | 5 | 11.90% |
Wen Gu | 406 | 16.06% | 1 | 2.38% |
Guvenc Gulce | 46 | 1.82% | 2 | 4.76% |
Karsten Graul | 37 | 1.46% | 1 | 2.38% |
Hans Wippel | 28 | 1.11% | 4 | 9.52% |
Tony Lu | 10 | 0.40% | 2 | 4.76% |
Linus Torvalds (pre-git) | 10 | 0.40% | 3 | 7.14% |
Eric Dumazet | 6 | 0.24% | 1 | 2.38% |
Peilin Ye | 5 | 0.20% | 1 | 2.38% |
Linus Torvalds | 4 | 0.16% | 1 | 2.38% |
Ingo Molnar | 3 | 0.12% | 1 | 2.38% |
Satoru Moriya | 3 | 0.12% | 1 | 2.38% |
Jakub Kiciński | 3 | 0.12% | 1 | 2.38% |
Arnaldo Carvalho de Melo | 3 | 0.12% | 1 | 2.38% |
Denys Vlasenko | 2 | 0.08% | 1 | 2.38% |
Guangguan Wang | 2 | 0.08% | 1 | 2.38% |
Greg Kroah-Hartman | 1 | 0.04% | 1 | 2.38% |
James Morris | 1 | 0.04% | 1 | 2.38% |
Total | 2528 | 42 |
// SPDX-License-Identifier: GPL-2.0 /* * Shared Memory Communications over RDMA (SMC-R) and RoCE * * Manage RMBE * copy new RMBE data into user space * * Copyright IBM Corp. 2016 * * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com> */ #include <linux/net.h> #include <linux/rcupdate.h> #include <linux/sched/signal.h> #include <linux/splice.h> #include <net/sock.h> #include <trace/events/sock.h> #include "smc.h" #include "smc_core.h" #include "smc_cdc.h" #include "smc_tx.h" /* smc_tx_consumer_update() */ #include "smc_rx.h" #include "smc_stats.h" #include "smc_tracepoint.h" /* callback implementation to wakeup consumers blocked with smc_rx_wait(). * indirectly called by smc_cdc_msg_recv_action(). */ static void smc_rx_wake_up(struct sock *sk) { struct socket_wq *wq; trace_sk_data_ready(sk); /* derived from sock_def_readable() */ /* called already in smc_listen_work() */ rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, EPOLLIN | EPOLLPRI | EPOLLRDNORM | EPOLLRDBAND); sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); if ((sk->sk_shutdown == SHUTDOWN_MASK) || (sk->sk_state == SMC_CLOSED)) sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP); rcu_read_unlock(); } /* Update consumer cursor * @conn connection to update * @cons consumer cursor * @len number of Bytes consumed * Returns: * 1 if we should end our receive, 0 otherwise */ static int smc_rx_update_consumer(struct smc_sock *smc, union smc_host_cursor cons, size_t len) { struct smc_connection *conn = &smc->conn; struct sock *sk = &smc->sk; bool force = false; int diff, rc = 0; smc_curs_add(conn->rmb_desc->len, &cons, len); /* did we process urgent data? */ if (conn->urg_state == SMC_URG_VALID || conn->urg_rx_skip_pend) { diff = smc_curs_comp(conn->rmb_desc->len, &cons, &conn->urg_curs); if (sock_flag(sk, SOCK_URGINLINE)) { if (diff == 0) { force = true; rc = 1; conn->urg_state = SMC_URG_READ; } } else { if (diff == 1) { /* skip urgent byte */ force = true; smc_curs_add(conn->rmb_desc->len, &cons, 1); conn->urg_rx_skip_pend = false; } else if (diff < -1) /* we read past urgent byte */ conn->urg_state = SMC_URG_READ; } } smc_curs_copy(&conn->local_tx_ctrl.cons, &cons, conn); /* send consumer cursor update if required */ /* similar to advertising new TCP rcv_wnd if required */ smc_tx_consumer_update(conn, force); return rc; } static void smc_rx_update_cons(struct smc_sock *smc, size_t len) { struct smc_connection *conn = &smc->conn; union smc_host_cursor cons; smc_curs_copy(&cons, &conn->local_tx_ctrl.cons, conn); smc_rx_update_consumer(smc, cons, len); } struct smc_spd_priv { struct smc_sock *smc; size_t len; }; static void smc_rx_pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { struct smc_spd_priv *priv = (struct smc_spd_priv *)buf->private; struct smc_sock *smc = priv->smc; struct smc_connection *conn; struct sock *sk = &smc->sk; if (sk->sk_state == SMC_CLOSED || sk->sk_state == SMC_PEERFINCLOSEWAIT || sk->sk_state == SMC_APPFINCLOSEWAIT) goto out; conn = &smc->conn; lock_sock(sk); smc_rx_update_cons(smc, priv->len); release_sock(sk); if (atomic_sub_and_test(priv->len, &conn->splice_pending)) smc_rx_wake_up(sk); out: kfree(priv); put_page(buf->page); sock_put(sk); } static const struct pipe_buf_operations smc_pipe_ops = { .release = smc_rx_pipe_buf_release, .get = generic_pipe_buf_get }; static void smc_rx_spd_release(struct splice_pipe_desc *spd, unsigned int i) { put_page(spd->pages[i]); } static int smc_rx_splice(struct pipe_inode_info *pipe, char *src, size_t len, struct smc_sock *smc) { struct smc_link_group *lgr = smc->conn.lgr; int offset = offset_in_page(src); struct partial_page *partial; struct splice_pipe_desc spd; struct smc_spd_priv **priv; struct page **pages; int bytes, nr_pages; int i; nr_pages = !lgr->is_smcd && smc->conn.rmb_desc->is_vm ? PAGE_ALIGN(len + offset) / PAGE_SIZE : 1; pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL); if (!pages) goto out; partial = kcalloc(nr_pages, sizeof(*partial), GFP_KERNEL); if (!partial) goto out_page; priv = kcalloc(nr_pages, sizeof(*priv), GFP_KERNEL); if (!priv) goto out_part; for (i = 0; i < nr_pages; i++) { priv[i] = kzalloc(sizeof(**priv), GFP_KERNEL); if (!priv[i]) goto out_priv; } if (lgr->is_smcd || (!lgr->is_smcd && !smc->conn.rmb_desc->is_vm)) { /* smcd or smcr that uses physically contiguous RMBs */ priv[0]->len = len; priv[0]->smc = smc; partial[0].offset = src - (char *)smc->conn.rmb_desc->cpu_addr; partial[0].len = len; partial[0].private = (unsigned long)priv[0]; pages[0] = smc->conn.rmb_desc->pages; } else { int size, left = len; void *buf = src; /* smcr that uses virtually contiguous RMBs*/ for (i = 0; i < nr_pages; i++) { size = min_t(int, PAGE_SIZE - offset, left); priv[i]->len = size; priv[i]->smc = smc; pages[i] = vmalloc_to_page(buf); partial[i].offset = offset; partial[i].len = size; partial[i].private = (unsigned long)priv[i]; buf += size / sizeof(*buf); left -= size; offset = 0; } } spd.nr_pages_max = nr_pages; spd.nr_pages = nr_pages; spd.pages = pages; spd.partial = partial; spd.ops = &smc_pipe_ops; spd.spd_release = smc_rx_spd_release; bytes = splice_to_pipe(pipe, &spd); if (bytes > 0) { sock_hold(&smc->sk); if (!lgr->is_smcd && smc->conn.rmb_desc->is_vm) { for (i = 0; i < PAGE_ALIGN(bytes + offset) / PAGE_SIZE; i++) get_page(pages[i]); } else { get_page(smc->conn.rmb_desc->pages); } atomic_add(bytes, &smc->conn.splice_pending); } kfree(priv); kfree(partial); kfree(pages); return bytes; out_priv: for (i = (i - 1); i >= 0; i--) kfree(priv[i]); kfree(priv); out_part: kfree(partial); out_page: kfree(pages); out: return -ENOMEM; } static int smc_rx_data_available_and_no_splice_pend(struct smc_connection *conn) { return atomic_read(&conn->bytes_to_rcv) && !atomic_read(&conn->splice_pending); } /* blocks rcvbuf consumer until >=len bytes available or timeout or interrupted * @smc smc socket * @timeo pointer to max seconds to wait, pointer to value 0 for no timeout * @fcrit add'l criterion to evaluate as function pointer * Returns: * 1 if at least 1 byte available in rcvbuf or if socket error/shutdown. * 0 otherwise (nothing in rcvbuf nor timeout, e.g. interrupted). */ int smc_rx_wait(struct smc_sock *smc, long *timeo, int (*fcrit)(struct smc_connection *conn)) { DEFINE_WAIT_FUNC(wait, woken_wake_function); struct smc_connection *conn = &smc->conn; struct smc_cdc_conn_state_flags *cflags = &conn->local_tx_ctrl.conn_state_flags; struct sock *sk = &smc->sk; int rc; if (fcrit(conn)) return 1; sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); add_wait_queue(sk_sleep(sk), &wait); rc = sk_wait_event(sk, timeo, READ_ONCE(sk->sk_err) || cflags->peer_conn_abort || READ_ONCE(sk->sk_shutdown) & RCV_SHUTDOWN || conn->killed || fcrit(conn), &wait); remove_wait_queue(sk_sleep(sk), &wait); sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); return rc; } static int smc_rx_recv_urg(struct smc_sock *smc, struct msghdr *msg, int len, int flags) { struct smc_connection *conn = &smc->conn; union smc_host_cursor cons; struct sock *sk = &smc->sk; int rc = 0; if (sock_flag(sk, SOCK_URGINLINE) || !(conn->urg_state == SMC_URG_VALID) || conn->urg_state == SMC_URG_READ) return -EINVAL; SMC_STAT_INC(smc, urg_data_cnt); if (conn->urg_state == SMC_URG_VALID) { if (!(flags & MSG_PEEK)) smc->conn.urg_state = SMC_URG_READ; msg->msg_flags |= MSG_OOB; if (len > 0) { if (!(flags & MSG_TRUNC)) rc = memcpy_to_msg(msg, &conn->urg_rx_byte, 1); len = 1; smc_curs_copy(&cons, &conn->local_tx_ctrl.cons, conn); if (smc_curs_diff(conn->rmb_desc->len, &cons, &conn->urg_curs) > 1) conn->urg_rx_skip_pend = true; /* Urgent Byte was already accounted for, but trigger * skipping the urgent byte in non-inline case */ if (!(flags & MSG_PEEK)) smc_rx_update_consumer(smc, cons, 0); } else { msg->msg_flags |= MSG_TRUNC; } return rc ? -EFAULT : len; } if (sk->sk_state == SMC_CLOSED || sk->sk_shutdown & RCV_SHUTDOWN) return 0; return -EAGAIN; } static bool smc_rx_recvmsg_data_available(struct smc_sock *smc) { struct smc_connection *conn = &smc->conn; if (smc_rx_data_available(conn)) return true; else if (conn->urg_state == SMC_URG_VALID) /* we received a single urgent Byte - skip */ smc_rx_update_cons(smc, 0); return false; } /* smc_rx_recvmsg - receive data from RMBE * @msg: copy data to receive buffer * @pipe: copy data to pipe if set - indicates splice() call * * rcvbuf consumer: main API called by socket layer. * Called under sk lock. */ int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg, struct pipe_inode_info *pipe, size_t len, int flags) { size_t copylen, read_done = 0, read_remaining = len; size_t chunk_len, chunk_off, chunk_len_sum; struct smc_connection *conn = &smc->conn; int (*func)(struct smc_connection *conn); union smc_host_cursor cons; int readable, chunk; char *rcvbuf_base; struct sock *sk; int splbytes; long timeo; int target; /* Read at least these many bytes */ int rc; if (unlikely(flags & MSG_ERRQUEUE)) return -EINVAL; /* future work for sk.sk_family == AF_SMC */ sk = &smc->sk; if (sk->sk_state == SMC_LISTEN) return -ENOTCONN; if (flags & MSG_OOB) return smc_rx_recv_urg(smc, msg, len, flags); timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); readable = atomic_read(&conn->bytes_to_rcv); if (readable >= conn->rmb_desc->len) SMC_STAT_RMB_RX_FULL(smc, !conn->lnk); if (len < readable) SMC_STAT_RMB_RX_SIZE_SMALL(smc, !conn->lnk); /* we currently use 1 RMBE per RMB, so RMBE == RMB base addr */ rcvbuf_base = conn->rx_off + conn->rmb_desc->cpu_addr; do { /* while (read_remaining) */ if (read_done >= target || (pipe && read_done)) break; if (conn->killed) break; if (smc_rx_recvmsg_data_available(smc)) goto copy; if (sk->sk_shutdown & RCV_SHUTDOWN) { /* smc_cdc_msg_recv_action() could have run after * above smc_rx_recvmsg_data_available() */ if (smc_rx_recvmsg_data_available(smc)) goto copy; break; } if (read_done) { if (sk->sk_err || sk->sk_state == SMC_CLOSED || !timeo || signal_pending(current)) break; } else { if (sk->sk_err) { read_done = sock_error(sk); break; } if (sk->sk_state == SMC_CLOSED) { if (!sock_flag(sk, SOCK_DONE)) { /* This occurs when user tries to read * from never connected socket. */ read_done = -ENOTCONN; break; } break; } if (!timeo) return -EAGAIN; if (signal_pending(current)) { read_done = sock_intr_errno(timeo); break; } } if (!smc_rx_data_available(conn)) { smc_rx_wait(smc, &timeo, smc_rx_data_available); continue; } copy: /* initialize variables for 1st iteration of subsequent loop */ /* could be just 1 byte, even after waiting on data above */ readable = atomic_read(&conn->bytes_to_rcv); splbytes = atomic_read(&conn->splice_pending); if (!readable || (msg && splbytes)) { if (splbytes) func = smc_rx_data_available_and_no_splice_pend; else func = smc_rx_data_available; smc_rx_wait(smc, &timeo, func); continue; } smc_curs_copy(&cons, &conn->local_tx_ctrl.cons, conn); /* subsequent splice() calls pick up where previous left */ if (splbytes) smc_curs_add(conn->rmb_desc->len, &cons, splbytes); if (conn->urg_state == SMC_URG_VALID && sock_flag(&smc->sk, SOCK_URGINLINE) && readable > 1) readable--; /* always stop at urgent Byte */ /* not more than what user space asked for */ copylen = min_t(size_t, read_remaining, readable); /* determine chunks where to read from rcvbuf */ /* either unwrapped case, or 1st chunk of wrapped case */ chunk_len = min_t(size_t, copylen, conn->rmb_desc->len - cons.count); chunk_len_sum = chunk_len; chunk_off = cons.count; smc_rmb_sync_sg_for_cpu(conn); for (chunk = 0; chunk < 2; chunk++) { if (!(flags & MSG_TRUNC)) { if (msg) { rc = memcpy_to_msg(msg, rcvbuf_base + chunk_off, chunk_len); } else { rc = smc_rx_splice(pipe, rcvbuf_base + chunk_off, chunk_len, smc); } if (rc < 0) { if (!read_done) read_done = -EFAULT; goto out; } } read_remaining -= chunk_len; read_done += chunk_len; if (chunk_len_sum == copylen) break; /* either on 1st or 2nd iteration */ /* prepare next (== 2nd) iteration */ chunk_len = copylen - chunk_len; /* remainder */ chunk_len_sum += chunk_len; chunk_off = 0; /* modulo offset in recv ring buffer */ } /* update cursors */ if (!(flags & MSG_PEEK)) { /* increased in recv tasklet smc_cdc_msg_rcv() */ smp_mb__before_atomic(); atomic_sub(copylen, &conn->bytes_to_rcv); /* guarantee 0 <= bytes_to_rcv <= rmb_desc->len */ smp_mb__after_atomic(); if (msg && smc_rx_update_consumer(smc, cons, copylen)) goto out; } trace_smc_rx_recvmsg(smc, copylen); } while (read_remaining); out: return read_done; } /* Initialize receive properties on connection establishment. NB: not __init! */ void smc_rx_init(struct smc_sock *smc) { smc->sk.sk_data_ready = smc_rx_wake_up; atomic_set(&smc->conn.splice_pending, 0); smc->conn.urg_state = SMC_URG_READ; }
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1