/** * xs_udp_data_ready - "data ready" callback for UDP sockets * @sk: socket with data to read * @len: how much data to read * */ static void xs_udp_data_ready(struct sock *sk, int len) { struct rpc_task *task; struct rpc_xprt *xprt; struct rpc_rqst *rovr; struct sk_buff *skb; int err, repsize, copied; u32 _xid, *xp; read_lock(&sk->sk_callback_lock); dprintk("RPC: xs_udp_data_ready...\n"); if (!(xprt = xprt_from_sock(sk))) goto out; if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) goto out; if (xprt->shutdown) goto dropit; repsize = skb->len - sizeof(struct udphdr); if (repsize < 4) { dprintk("RPC: impossible RPC reply size %d!\n", repsize); goto dropit; } /* Copy the XID from the skb... */ xp = skb_header_pointer(skb, sizeof(struct udphdr), sizeof(_xid), &_xid); if (xp == NULL) goto dropit; /* Look up and lock the request corresponding to the given XID */ spin_lock(&xprt->transport_lock); rovr = xprt_lookup_rqst(xprt, *xp); if (!rovr) goto out_unlock; task = rovr->rq_task; if ((copied = rovr->rq_private_buf.buflen) > repsize) copied = repsize; /* Suck it into the iovec, verify checksum if not done by hw. */ if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb)) goto out_unlock; /* Something worked... */ dst_confirm(skb->dst); xprt_adjust_cwnd(task, copied); xprt_update_rtt(task); xprt_complete_rqst(task, copied); out_unlock: spin_unlock(&xprt->transport_lock); dropit: skb_free_datagram(sk, skb); out: read_unlock(&sk->sk_callback_lock); }
int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt, struct rpcrdma_msg *rmsgp, struct xdr_buf *rcvbuf) { struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); struct kvec *dst, *src = &rcvbuf->head[0]; struct rpc_rqst *req; unsigned long cwnd; u32 credits; size_t len; __be32 xid; __be32 *p; int ret; p = (__be32 *)src->iov_base; len = src->iov_len; xid = rmsgp->rm_xid; #ifdef SVCRDMA_BACKCHANNEL_DEBUG pr_info("%s: xid=%08x, length=%zu\n", __func__, be32_to_cpu(xid), len); pr_info("%s: RPC/RDMA: %*ph\n", __func__, (int)RPCRDMA_HDRLEN_MIN, rmsgp); pr_info("%s: RPC: %*ph\n", __func__, (int)len, p); #endif ret = -EAGAIN; if (src->iov_len < 24) goto out_shortreply; spin_lock_bh(&xprt->transport_lock); req = xprt_lookup_rqst(xprt, xid); if (!req) goto out_notfound; dst = &req->rq_private_buf.head[0]; memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf)); if (dst->iov_len < len) goto out_unlock; memcpy(dst->iov_base, p, len); credits = be32_to_cpu(rmsgp->rm_credit); if (credits == 0) credits = 1; /* don't deadlock */ else if (credits > r_xprt->rx_buf.rb_bc_max_requests) credits = r_xprt->rx_buf.rb_bc_max_requests; cwnd = xprt->cwnd; xprt->cwnd = credits << RPC_CWNDSHIFT; if (xprt->cwnd > cwnd) xprt_release_rqst_cong(req->rq_task); ret = 0; xprt_complete_rqst(req->rq_task, rcvbuf->len); rcvbuf->len = 0; out_unlock: spin_unlock_bh(&xprt->transport_lock); out: return ret; out_shortreply: dprintk("svcrdma: short bc reply: xprt=%p, len=%zu\n", xprt, src->iov_len); goto out; out_notfound: dprintk("svcrdma: unrecognized bc reply: xprt=%p, xid=%08x\n", xprt, be32_to_cpu(xid)); goto out_unlock; }
static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) { struct rpc_rqst *req; struct xdr_buf *rcvbuf; size_t len; ssize_t r; /* Find and lock the request corresponding to this xid */ spin_lock(&xprt->transport_lock); req = xprt_lookup_rqst(xprt, xprt->tcp_xid); if (!req) { xprt->tcp_flags &= ~XPRT_COPY_DATA; dprintk("RPC: XID %08x request not found!\n", ntohl(xprt->tcp_xid)); spin_unlock(&xprt->transport_lock); return; } rcvbuf = &req->rq_private_buf; len = desc->count; if (len > xprt->tcp_reclen - xprt->tcp_offset) { skb_reader_t my_desc; len = xprt->tcp_reclen - xprt->tcp_offset; memcpy(&my_desc, desc, sizeof(my_desc)); my_desc.count = len; r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, &my_desc, xs_tcp_copy_data); desc->count -= r; desc->offset += r; } else r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, desc, xs_tcp_copy_data); if (r > 0) { xprt->tcp_copied += r; xprt->tcp_offset += r; } if (r != len) { /* Error when copying to the receive buffer, * usually because we weren't able to allocate * additional buffer pages. All we can do now * is turn off XPRT_COPY_DATA, so the request * will not receive any additional updates, * and time out. * Any remaining data from this record will * be discarded. */ xprt->tcp_flags &= ~XPRT_COPY_DATA; dprintk("RPC: XID %08x truncated request\n", ntohl(xprt->tcp_xid)); dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); goto out; } dprintk("RPC: XID %08x read %Zd bytes\n", ntohl(xprt->tcp_xid), r); dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); if (xprt->tcp_copied == req->rq_private_buf.buflen) xprt->tcp_flags &= ~XPRT_COPY_DATA; else if (xprt->tcp_offset == xprt->tcp_reclen) { if (xprt->tcp_flags & XPRT_LAST_FRAG) xprt->tcp_flags &= ~XPRT_COPY_DATA; } out: if (!(xprt->tcp_flags & XPRT_COPY_DATA)) xprt_complete_rqst(req->rq_task, xprt->tcp_copied); spin_unlock(&xprt->transport_lock); xs_tcp_check_recm(xprt); }