diff options
Diffstat (limited to 'net/rxrpc/conn_object.c')
-rw-r--r-- | net/rxrpc/conn_object.c | 247 |
1 files changed, 1 insertions, 246 deletions
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index ce83f3e44da2..ab5c8c2960e4 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c @@ -34,7 +34,7 @@ static DECLARE_DELAYED_WORK(rxrpc_connection_reap, rxrpc_connection_reaper); /* * allocate a new connection */ -static struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp) +struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp) { struct rxrpc_connection *conn; @@ -61,251 +61,6 @@ static struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp) } /* - * Allocate a client connection. The caller must take care to clear any - * padding bytes in *cp. - */ -static struct rxrpc_connection * -rxrpc_alloc_client_connection(struct rxrpc_conn_parameters *cp, gfp_t gfp) -{ - struct rxrpc_connection *conn; - int ret; - - _enter(""); - - conn = rxrpc_alloc_connection(gfp); - if (!conn) { - _leave(" = -ENOMEM"); - return ERR_PTR(-ENOMEM); - } - - conn->params = *cp; - conn->proto.local = cp->local; - conn->proto.epoch = rxrpc_epoch; - conn->proto.cid = 0; - conn->proto.in_clientflag = 0; - conn->proto.family = cp->peer->srx.transport.family; - conn->out_clientflag = RXRPC_CLIENT_INITIATED; - conn->state = RXRPC_CONN_CLIENT; - - switch (conn->proto.family) { - case AF_INET: - conn->proto.addr_size = sizeof(conn->proto.ipv4_addr); - conn->proto.ipv4_addr = cp->peer->srx.transport.sin.sin_addr; - conn->proto.port = cp->peer->srx.transport.sin.sin_port; - break; - } - - ret = rxrpc_get_client_connection_id(conn, gfp); - if (ret < 0) - goto error_0; - - ret = rxrpc_init_client_conn_security(conn); - if (ret < 0) - goto error_1; - - ret = conn->security->prime_packet_security(conn); - if (ret < 0) - goto error_2; - - write_lock(&rxrpc_connection_lock); - list_add_tail(&conn->link, &rxrpc_connections); - write_unlock(&rxrpc_connection_lock); - - /* We steal the caller's peer ref. */ - cp->peer = NULL; - rxrpc_get_local(conn->params.local); - key_get(conn->params.key); - - _leave(" = %p", conn); - return conn; - -error_2: - conn->security->clear(conn); -error_1: - rxrpc_put_client_connection_id(conn); -error_0: - kfree(conn); - _leave(" = %d", ret); - return ERR_PTR(ret); -} - -/* - * find a connection for a call - * - called in process context with IRQs enabled - */ -int rxrpc_connect_call(struct rxrpc_call *call, - struct rxrpc_conn_parameters *cp, - struct sockaddr_rxrpc *srx, - gfp_t gfp) -{ - struct rxrpc_connection *conn, *candidate = NULL; - struct rxrpc_local *local = cp->local; - struct rb_node *p, **pp, *parent; - long diff; - int chan; - - DECLARE_WAITQUEUE(myself, current); - - _enter("{%d,%lx},", call->debug_id, call->user_call_ID); - - cp->peer = rxrpc_lookup_peer(cp->local, srx, gfp); - if (!cp->peer) - return -ENOMEM; - - if (!cp->exclusive) { - /* Search for a existing client connection unless this is going - * to be a connection that's used exclusively for a single call. - */ - _debug("search 1"); - spin_lock(&local->client_conns_lock); - p = local->client_conns.rb_node; - while (p) { - conn = rb_entry(p, struct rxrpc_connection, client_node); - -#define cmp(X) ((long)conn->params.X - (long)cp->X) - diff = (cmp(peer) ?: - cmp(key) ?: - cmp(security_level)); - if (diff < 0) - p = p->rb_left; - else if (diff > 0) - p = p->rb_right; - else - goto found_extant_conn; - } - spin_unlock(&local->client_conns_lock); - } - - /* We didn't find a connection or we want an exclusive one. */ - _debug("get new conn"); - candidate = rxrpc_alloc_client_connection(cp, gfp); - if (!candidate) { - _leave(" = -ENOMEM"); - return -ENOMEM; - } - - if (cp->exclusive) { - /* Assign the call on an exclusive connection to channel 0 and - * don't add the connection to the endpoint's shareable conn - * lookup tree. - */ - _debug("exclusive chan 0"); - conn = candidate; - atomic_set(&conn->avail_chans, RXRPC_MAXCALLS - 1); - spin_lock(&conn->channel_lock); - chan = 0; - goto found_channel; - } - - /* We need to redo the search before attempting to add a new connection - * lest we race with someone else adding a conflicting instance. - */ - _debug("search 2"); - spin_lock(&local->client_conns_lock); - - pp = &local->client_conns.rb_node; - parent = NULL; - while (*pp) { - parent = *pp; - conn = rb_entry(parent, struct rxrpc_connection, client_node); - - diff = (cmp(peer) ?: - cmp(key) ?: - cmp(security_level)); - if (diff < 0) - pp = &(*pp)->rb_left; - else if (diff > 0) - pp = &(*pp)->rb_right; - else - goto found_extant_conn; - } - - /* The second search also failed; simply add the new connection with - * the new call in channel 0. Note that we need to take the channel - * lock before dropping the client conn lock. - */ - _debug("new conn"); - conn = candidate; - candidate = NULL; - - rb_link_node(&conn->client_node, parent, pp); - rb_insert_color(&conn->client_node, &local->client_conns); - - atomic_set(&conn->avail_chans, RXRPC_MAXCALLS - 1); - spin_lock(&conn->channel_lock); - spin_unlock(&local->client_conns_lock); - chan = 0; - -found_channel: - _debug("found chan"); - call->conn = conn; - call->channel = chan; - call->epoch = conn->proto.epoch; - call->cid = conn->proto.cid | chan; - call->call_id = ++conn->channels[chan].call_counter; - conn->channels[chan].call_id = call->call_id; - rcu_assign_pointer(conn->channels[chan].call, call); - - _net("CONNECT call %d on conn %d", call->debug_id, conn->debug_id); - - spin_unlock(&conn->channel_lock); - rxrpc_put_peer(cp->peer); - cp->peer = NULL; - _leave(" = %p {u=%d}", conn, atomic_read(&conn->usage)); - return 0; - - /* We found a suitable connection already in existence. Discard any - * candidate we may have allocated, and try to get a channel on this - * one. - */ -found_extant_conn: - _debug("found conn"); - rxrpc_get_connection(conn); - spin_unlock(&local->client_conns_lock); - - rxrpc_put_connection(candidate); - - if (!atomic_add_unless(&conn->avail_chans, -1, 0)) { - if (!gfpflags_allow_blocking(gfp)) { - rxrpc_put_connection(conn); - _leave(" = -EAGAIN"); - return -EAGAIN; - } - - add_wait_queue(&conn->channel_wq, &myself); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (atomic_add_unless(&conn->avail_chans, -1, 0)) - break; - if (signal_pending(current)) - goto interrupted; - schedule(); - } - remove_wait_queue(&conn->channel_wq, &myself); - __set_current_state(TASK_RUNNING); - } - - /* The connection allegedly now has a free channel and we can now - * attach the call to it. - */ - spin_lock(&conn->channel_lock); - - for (chan = 0; chan < RXRPC_MAXCALLS; chan++) - if (!conn->channels[chan].call) - goto found_channel; - BUG(); - -interrupted: - remove_wait_queue(&conn->channel_wq, &myself); - __set_current_state(TASK_RUNNING); - rxrpc_put_connection(conn); - rxrpc_put_peer(cp->peer); - cp->peer = NULL; - _leave(" = -ERESTARTSYS"); - return -ERESTARTSYS; -} - -/* * get a record of an incoming connection */ struct rxrpc_connection *rxrpc_incoming_connection(struct rxrpc_local *local, |