diff options
author | David S. Miller <davem@davemloft.net> | 2014-03-08 01:08:59 +0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-08 01:08:59 +0400 |
commit | 389400428953bb002b173fa07d16d7a6f120843f (patch) | |
tree | 06aa3fd674a970fdbfc63866a2cd9b295e21a61c /net/rxrpc/ar-input.c | |
parent | 4caeccb4de76440e433a15009636e77d003eb3d6 (diff) | |
parent | 7727640cc3c4d03b6a3cb5bf26d48c72e31403ca (diff) | |
download | linux-389400428953bb002b173fa07d16d7a6f120843f.tar.xz |
Merge tag 'rxrpc-devel-20140304' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
David Howells says:
====================
net-next: AF_RXRPC fixes and development
Here are some AF_RXRPC fixes:
(1) Fix to remove incorrect checksum calculation made during recvmsg(). It's
unnecessary to try to do this there since we check the checksum before
reading the RxRPC header from the packet.
(2) Fix to prevent the sending of an ABORT packet in response to another
ABORT packet and inducing a storm.
(3) Fix UDP MTU calculation from parsing ICMP_FRAG_NEEDED packets where we
don't handle the ICMP packet not specifying an MTU size.
And development patches:
(4) Add sysctls for configuring RxRPC parameters, specifically various delays
pertaining to ACK generation, the time before we resend a packet for
which we don't receive an ACK, the maximum time a call is permitted to
live and the amount of time transport, connection and dead call
information is cached.
(5) Improve ACK packet production by adjusting the handling of ACK_REQUESTED
packets, ignoring the MORE_PACKETS flag, delaying the production of
otherwise immediate ACK_IDLE packets and delaying all ACK_IDLE production
(barring the call termination) to half a second.
(6) Add more sysctl parameters to expose the Rx window size, the maximum
packet size that we're willing to receive and the number of jumbo rxrpc
packets we're willing to handle in a single UDP packet.
(7) Request ACKs on alternate DATA packets so that the other side doesn't
wait till we fill up the Tx window.
(8) Use a RCU hash table to look up the rxrpc_call for an incoming packet
rather than stepping through a hierarchy involving several spinlocks.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rxrpc/ar-input.c')
-rw-r--r-- | net/rxrpc/ar-input.c | 190 |
1 files changed, 80 insertions, 110 deletions
diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c index 529572f18d1f..73742647c135 100644 --- a/net/rxrpc/ar-input.c +++ b/net/rxrpc/ar-input.c @@ -25,8 +25,6 @@ #include <net/net_namespace.h> #include "ar-internal.h" -unsigned long rxrpc_ack_timeout = 1; - const char *rxrpc_pkts[] = { "?00", "DATA", "ACK", "BUSY", "ABORT", "ACKALL", "CHALL", "RESP", "DEBUG", @@ -349,8 +347,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb) * it */ if (sp->hdr.flags & RXRPC_REQUEST_ACK) { _proto("ACK Requested on %%%u", serial); - rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial, - !(sp->hdr.flags & RXRPC_MORE_PACKETS)); + rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial, false); } switch (sp->hdr.type) { @@ -526,36 +523,38 @@ protocol_error: * post an incoming packet to the appropriate call/socket to deal with * - must get rid of the sk_buff, either by freeing it or by queuing it */ -static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn, +static void rxrpc_post_packet_to_call(struct rxrpc_call *call, struct sk_buff *skb) { struct rxrpc_skb_priv *sp; - struct rxrpc_call *call; - struct rb_node *p; - __be32 call_id; - - _enter("%p,%p", conn, skb); - read_lock_bh(&conn->lock); + _enter("%p,%p", call, skb); sp = rxrpc_skb(skb); - /* look at extant calls by channel number first */ - call = conn->channels[ntohl(sp->hdr.cid) & RXRPC_CHANNELMASK]; - if (!call || call->call_id != sp->hdr.callNumber) - goto call_not_extant; - _debug("extant call [%d]", call->state); - ASSERTCMP(call->conn, ==, conn); read_lock(&call->state_lock); switch (call->state) { case RXRPC_CALL_LOCALLY_ABORTED: - if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events)) + if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events)) { rxrpc_queue_call(call); + goto free_unlock; + } case RXRPC_CALL_REMOTELY_ABORTED: case RXRPC_CALL_NETWORK_ERROR: case RXRPC_CALL_DEAD: + goto dead_call; + case RXRPC_CALL_COMPLETE: + case RXRPC_CALL_CLIENT_FINAL_ACK: + /* complete server call */ + if (call->conn->in_clientflag) + goto dead_call; + /* resend last packet of a completed call */ + _debug("final ack again"); + rxrpc_get_call(call); + set_bit(RXRPC_CALL_ACK_FINAL, &call->events); + rxrpc_queue_call(call); goto free_unlock; default: break; @@ -563,7 +562,6 @@ static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn, read_unlock(&call->state_lock); rxrpc_get_call(call); - read_unlock_bh(&conn->lock); if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA && sp->hdr.flags & RXRPC_JUMBO_PACKET) @@ -574,78 +572,16 @@ static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn, rxrpc_put_call(call); goto done; -call_not_extant: - /* search the completed calls in case what we're dealing with is - * there */ - _debug("call not extant"); - - call_id = sp->hdr.callNumber; - p = conn->calls.rb_node; - while (p) { - call = rb_entry(p, struct rxrpc_call, conn_node); - - if (call_id < call->call_id) - p = p->rb_left; - else if (call_id > call->call_id) - p = p->rb_right; - else - goto found_completed_call; - } - dead_call: - /* it's a either a really old call that we no longer remember or its a - * new incoming call */ - read_unlock_bh(&conn->lock); - - if (sp->hdr.flags & RXRPC_CLIENT_INITIATED && - sp->hdr.seq == cpu_to_be32(1)) { - _debug("incoming call"); - skb_queue_tail(&conn->trans->local->accept_queue, skb); - rxrpc_queue_work(&conn->trans->local->acceptor); - goto done; - } - - _debug("dead call"); - skb->priority = RX_CALL_DEAD; - rxrpc_reject_packet(conn->trans->local, skb); - goto done; - - /* resend last packet of a completed call - * - client calls may have been aborted or ACK'd - * - server calls may have been aborted - */ -found_completed_call: - _debug("completed call"); - - if (atomic_read(&call->usage) == 0) - goto dead_call; - - /* synchronise any state changes */ - read_lock(&call->state_lock); - ASSERTIFCMP(call->state != RXRPC_CALL_CLIENT_FINAL_ACK, - call->state, >=, RXRPC_CALL_COMPLETE); - - if (call->state == RXRPC_CALL_LOCALLY_ABORTED || - call->state == RXRPC_CALL_REMOTELY_ABORTED || - call->state == RXRPC_CALL_DEAD) { - read_unlock(&call->state_lock); - goto dead_call; - } - - if (call->conn->in_clientflag) { - read_unlock(&call->state_lock); - goto dead_call; /* complete server call */ + if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) { + skb->priority = RX_CALL_DEAD; + rxrpc_reject_packet(call->conn->trans->local, skb); + goto unlock; } - - _debug("final ack again"); - rxrpc_get_call(call); - set_bit(RXRPC_CALL_ACK_FINAL, &call->events); - rxrpc_queue_call(call); - free_unlock: - read_unlock(&call->state_lock); - read_unlock_bh(&conn->lock); rxrpc_free_skb(skb); +unlock: + read_unlock(&call->state_lock); done: _leave(""); } @@ -664,17 +600,42 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn, rxrpc_queue_conn(conn); } +static struct rxrpc_connection *rxrpc_conn_from_local(struct rxrpc_local *local, + struct sk_buff *skb, + struct rxrpc_skb_priv *sp) +{ + struct rxrpc_peer *peer; + struct rxrpc_transport *trans; + struct rxrpc_connection *conn; + + peer = rxrpc_find_peer(local, ip_hdr(skb)->saddr, + udp_hdr(skb)->source); + if (IS_ERR(peer)) + goto cant_find_conn; + + trans = rxrpc_find_transport(local, peer); + rxrpc_put_peer(peer); + if (!trans) + goto cant_find_conn; + + conn = rxrpc_find_connection(trans, &sp->hdr); + rxrpc_put_transport(trans); + if (!conn) + goto cant_find_conn; + + return conn; +cant_find_conn: + return NULL; +} + /* * handle data received on the local endpoint * - may be called in interrupt context */ void rxrpc_data_ready(struct sock *sk, int count) { - struct rxrpc_connection *conn; - struct rxrpc_transport *trans; struct rxrpc_skb_priv *sp; struct rxrpc_local *local; - struct rxrpc_peer *peer; struct sk_buff *skb; int ret; @@ -749,27 +710,34 @@ void rxrpc_data_ready(struct sock *sk, int count) (sp->hdr.callNumber == 0 || sp->hdr.seq == 0)) goto bad_message; - peer = rxrpc_find_peer(local, ip_hdr(skb)->saddr, udp_hdr(skb)->source); - if (IS_ERR(peer)) - goto cant_route_call; + if (sp->hdr.callNumber == 0) { + /* This is a connection-level packet. These should be + * fairly rare, so the extra overhead of looking them up the + * old-fashioned way doesn't really hurt */ + struct rxrpc_connection *conn; - trans = rxrpc_find_transport(local, peer); - rxrpc_put_peer(peer); - if (!trans) - goto cant_route_call; + conn = rxrpc_conn_from_local(local, skb, sp); + if (!conn) + goto cant_route_call; - conn = rxrpc_find_connection(trans, &sp->hdr); - rxrpc_put_transport(trans); - if (!conn) - goto cant_route_call; - - _debug("CONN %p {%d}", conn, conn->debug_id); - - if (sp->hdr.callNumber == 0) + _debug("CONN %p {%d}", conn, conn->debug_id); rxrpc_post_packet_to_conn(conn, skb); - else - rxrpc_post_packet_to_call(conn, skb); - rxrpc_put_connection(conn); + rxrpc_put_connection(conn); + } else { + struct rxrpc_call *call; + u8 in_clientflag = 0; + + if (sp->hdr.flags & RXRPC_CLIENT_INITIATED) + in_clientflag = RXRPC_CLIENT_INITIATED; + call = rxrpc_find_call_hash(in_clientflag, sp->hdr.cid, + sp->hdr.callNumber, sp->hdr.epoch, + sp->hdr.serviceId, local, AF_INET, + (u8 *)&ip_hdr(skb)->saddr); + if (call) + rxrpc_post_packet_to_call(call, skb); + else + goto cant_route_call; + } rxrpc_put_local(local); return; @@ -790,8 +758,10 @@ cant_route_call: skb->priority = RX_CALL_DEAD; } - _debug("reject"); - rxrpc_reject_packet(local, skb); + if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) { + _debug("reject type %d",sp->hdr.type); + rxrpc_reject_packet(local, skb); + } rxrpc_put_local(local); _leave(" [no call]"); return; |