Esempio n. 1
0
/**
 * xs_udp_connect_worker - set up a UDP socket
 * @args: RPC transport to connect
 *
 * Invoked by a work queue tasklet.
 */
static void xs_udp_connect_worker(void *args)
{
    struct rpc_xprt *xprt = (struct rpc_xprt *) args;
    struct socket *sock = xprt->sock;
    int err, status = -EIO;

    if (xprt->shutdown || xprt->addr.sin_port == 0)
        goto out;

    dprintk("RPC:      xs_udp_connect_worker for xprt %p\n", xprt);

    /* Start by resetting any existing state */
    xs_close(xprt);

    if ((err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
        dprintk("RPC:      can't create UDP transport socket (%d).\n", -err);
        goto out;
    }
    xs_reclassify_socket(sock);

    if (xs_bind(xprt, sock)) {
        sock_release(sock);
        goto out;
    }

    if (!xprt->inet) {
        struct sock *sk = sock->sk;

        write_lock_bh(&sk->sk_callback_lock);

        sk->sk_user_data = xprt;
        xprt->old_data_ready = sk->sk_data_ready;
        xprt->old_state_change = sk->sk_state_change;
        xprt->old_write_space = sk->sk_write_space;
        sk->sk_data_ready = xs_udp_data_ready;
        sk->sk_write_space = xs_udp_write_space;
        sk->sk_no_check = UDP_CSUM_NORCV;
        sk->sk_allocation = GFP_ATOMIC;

        xprt_set_connected(xprt);

        /* Reset to new socket */
        xprt->sock = sock;
        xprt->inet = sk;

        write_unlock_bh(&sk->sk_callback_lock);
    }
    xs_udp_do_set_buffer_size(xprt);
    status = 0;
out:
    xprt_wake_pending_tasks(xprt, status);
    xprt_clear_connecting(xprt);
}
Esempio n. 2
0
/**
 * xprt_rdma_connect_worker - establish connection in the background
 * @work: worker thread context
 *
 * Requester holds the xprt's send lock to prevent activity on this
 * transport while a fresh connection is being established. RPC tasks
 * sleep on the xprt's pending queue waiting for connect to complete.
 */
static void
xprt_rdma_connect_worker(struct work_struct *work)
{
	struct rpcrdma_xprt *r_xprt = container_of(work, struct rpcrdma_xprt,
						   rx_connect_worker.work);
	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
	int rc;

	rc = rpcrdma_ep_connect(&r_xprt->rx_ep, &r_xprt->rx_ia);
	xprt_clear_connecting(xprt);
	if (r_xprt->rx_ep.rep_connected > 0) {
		if (!xprt_test_and_set_connected(xprt)) {
			xprt->stat.connect_count++;
			xprt->stat.connect_time += (long)jiffies -
						   xprt->stat.connect_start;
			xprt_wake_pending_tasks(xprt, -EAGAIN);
		}
	} else {
		if (xprt_test_and_clear_connected(xprt))
			xprt_wake_pending_tasks(xprt, rc);
	}
}
Esempio n. 3
0
static void
xprt_rdma_connect_worker(struct work_struct *work)
{
	struct rpcrdma_xprt *r_xprt = container_of(work, struct rpcrdma_xprt,
						   rx_connect_worker.work);
	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
	int rc = 0;

	xprt_clear_connected(xprt);

	dprintk("RPC:       %s: %sconnect\n", __func__,
			r_xprt->rx_ep.rep_connected != 0 ? "re" : "");
	rc = rpcrdma_ep_connect(&r_xprt->rx_ep, &r_xprt->rx_ia);
	if (rc)
		xprt_wake_pending_tasks(xprt, rc);

	dprintk("RPC:       %s: exit\n", __func__);
	xprt_clear_connecting(xprt);
}
Esempio n. 4
0
static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, unsigned int offset, size_t len)
{
    struct rpc_xprt *xprt = rd_desc->arg.data;
    skb_reader_t desc = {
        .skb	= skb,
        .offset	= offset,
        .count	= len,
        .csum	= 0
    };

    dprintk("RPC:      xs_tcp_data_recv started\n");
    do {
        /* Read in a new fragment marker if necessary */
        /* Can we ever really expect to get completely empty fragments? */
        if (xprt->tcp_flags & XPRT_COPY_RECM) {
            xs_tcp_read_fraghdr(xprt, &desc);
            continue;
        }
        /* Read in the xid if necessary */
        if (xprt->tcp_flags & XPRT_COPY_XID) {
            xs_tcp_read_xid(xprt, &desc);
            continue;
        }
        /* Read in the request data */
        if (xprt->tcp_flags & XPRT_COPY_DATA) {
            xs_tcp_read_request(xprt, &desc);
            continue;
        }
        /* Skip over any trailing bytes on short reads */
        xs_tcp_read_discard(xprt, &desc);
    } while (desc.count);
    dprintk("RPC:      xs_tcp_data_recv done\n");
    return len - desc.count;
}

/**
 * xs_tcp_data_ready - "data ready" callback for TCP sockets
 * @sk: socket with data to read
 * @bytes: how much data to read
 *
 */
static void xs_tcp_data_ready(struct sock *sk, int bytes)
{
    struct rpc_xprt *xprt;
    read_descriptor_t rd_desc;

    read_lock(&sk->sk_callback_lock);
    dprintk("RPC:      xs_tcp_data_ready...\n");
    if (!(xprt = xprt_from_sock(sk)))
        goto out;
    if (xprt->shutdown)
        goto out;

    /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */
    rd_desc.arg.data = xprt;
    rd_desc.count = 65536;
    tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv);
out:
    read_unlock(&sk->sk_callback_lock);
}

/**
 * xs_tcp_state_change - callback to handle TCP socket state changes
 * @sk: socket whose state has changed
 *
 */
static void xs_tcp_state_change(struct sock *sk)
{
    struct rpc_xprt *xprt;

    read_lock(&sk->sk_callback_lock);
    if (!(xprt = xprt_from_sock(sk)))
        goto out;
    dprintk("RPC:      xs_tcp_state_change client %p...\n", xprt);
    dprintk("RPC:      state %x conn %d dead %d zapped %d\n",
            sk->sk_state, xprt_connected(xprt),
            sock_flag(sk, SOCK_DEAD),
            sock_flag(sk, SOCK_ZAPPED));

    switch (sk->sk_state) {
    case TCP_ESTABLISHED:
        spin_lock_bh(&xprt->transport_lock);
        if (!xprt_test_and_set_connected(xprt)) {
            /* Reset TCP record info */
            xprt->tcp_offset = 0;
            xprt->tcp_reclen = 0;
            xprt->tcp_copied = 0;

            if (xprt->tcp_flags & XPRT_SRCADDR_PRESENT)
                xprt->tcp_flags = XPRT_SRCADDR_PRESENT |
                                  XPRT_COPY_RECM |
                                  XPRT_COPY_XID;
            else
                xprt->tcp_flags = XPRT_COPY_RECM |
                                  XPRT_COPY_XID;

            xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
            xprt_wake_pending_tasks(xprt, 0);
        }
        spin_unlock_bh(&xprt->transport_lock);
        break;
    case TCP_SYN_SENT:
    case TCP_SYN_RECV:
        break;
    case TCP_CLOSE_WAIT:
        /* Try to schedule an autoclose RPC calls */
        set_bit(XPRT_CLOSE_WAIT, &xprt->state);
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
            queue_work(rpciod_workqueue, &xprt->task_cleanup);
    default:
        xprt_disconnect(xprt);
    }
out:
    read_unlock(&sk->sk_callback_lock);
}

/**
 * xs_udp_write_space - callback invoked when socket buffer space
 *                             becomes available
 * @sk: socket whose state has changed
 *
 * Called when more output buffer space is available for this socket.
 * We try not to wake our writers until they can make "significant"
 * progress, otherwise we'll waste resources thrashing kernel_sendmsg
 * with a bunch of small requests.
 */
static void xs_udp_write_space(struct sock *sk)
{
    read_lock(&sk->sk_callback_lock);

    /* from net/core/sock.c:sock_def_write_space */
    if (sock_writeable(sk)) {
        struct socket *sock;
        struct rpc_xprt *xprt;

        if (unlikely(!(sock = sk->sk_socket)))
            goto out;
        if (unlikely(!(xprt = xprt_from_sock(sk))))
            goto out;
        if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)))
            goto out;

        xprt_write_space(xprt);
    }

out:
    read_unlock(&sk->sk_callback_lock);
}
Esempio n. 5
0
/**
 * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint
 * @args: RPC transport to connect
 *
 * Invoked by a work queue tasklet.
 */
static void xs_tcp_connect_worker(void *args)
{
    struct rpc_xprt *xprt = (struct rpc_xprt *)args;
    struct socket *sock = xprt->sock;
    int err, status = -EIO;

    if (xprt->shutdown || xprt->addr.sin_port == 0)
        goto out;

    dprintk("RPC:      xs_tcp_connect_worker for xprt %p\n", xprt);

    if (!xprt->sock) {
        /* start from scratch */
        if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
            dprintk("RPC:      can't create TCP transport socket (%d).\n", -err);
            goto out;
        }
        xs_reclassify_socket(sock);

        if (xs_bind(xprt, sock)) {
            sock_release(sock);
            goto out;
        }
    } else
        /* "close" the socket, preserving the local port */
        xs_tcp_reuse_connection(xprt);

    if (!xprt->inet) {
        struct sock *sk = sock->sk;

        write_lock_bh(&sk->sk_callback_lock);

        sk->sk_user_data = xprt;
        xprt->old_data_ready = sk->sk_data_ready;
        xprt->old_state_change = sk->sk_state_change;
        xprt->old_write_space = sk->sk_write_space;
        sk->sk_data_ready = xs_tcp_data_ready;
        sk->sk_state_change = xs_tcp_state_change;
        sk->sk_write_space = xs_tcp_write_space;
        sk->sk_allocation = GFP_ATOMIC;

        /* socket options */
        sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
        sock_reset_flag(sk, SOCK_LINGER);
        tcp_sk(sk)->linger2 = 0;
        tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;

        xprt_clear_connected(xprt);

        /* Reset to new socket */
        xprt->sock = sock;
        xprt->inet = sk;

        write_unlock_bh(&sk->sk_callback_lock);
    }

    /* Tell the socket layer to start connecting... */
    xprt->stat.connect_count++;
    xprt->stat.connect_start = jiffies;
    status = kernel_connect(sock, (struct sockaddr *) &xprt->addr,
                            sizeof(xprt->addr), O_NONBLOCK);
    dprintk("RPC: %p  connect status %d connected %d sock state %d\n",
            xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
    if (status < 0) {
        switch (status) {
        case -EINPROGRESS:
        case -EALREADY:
            goto out_clear;
        case -ECONNREFUSED:
        case -ECONNRESET:
            /* retry with existing socket, after a delay */
            break;
        case -ENETUNREACH:
            status = -ENOTCONN;
            break;
        default:
            /* get rid of existing socket, and retry */
            xs_close(xprt);
            break;
        }
    }
out:
    xprt_wake_pending_tasks(xprt, status);
out_clear:
    xprt_clear_connecting(xprt);
}