예제 #1
0
/**
 * 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);
}
예제 #2
0
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;
}
예제 #3
0
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);
}