Skip to content

Commit

Permalink
Merge tag 'rxrpc-fixes-20180928' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: Fixes

Here are some miscellaneous fixes for AF_RXRPC:

 (1) Remove a duplicate variable initialisation.

 (2) Fix one of the checks made when we decide to set up a new incoming
     service call in which a flag is being checked in the wrong field of
     the packet header.  This check is abstracted out into helper
     functions.

 (3) Fix RTT gathering.  The code has been trying to make use of socket
     timestamps, but wasn't actually enabling them.  The code has also been
     recording a transmit time for the outgoing packet for which we're
     going to measure the RTT after sending the message - but we can get
     the incoming packet before we get to that and record a negative RTT.

 (4) Fix the emission of BUSY packets (we are emitting ABORTs instead).

 (5) Improve error checking on incoming packets.

 (6) Try to fix a bug in new service call handling whereby a BUG we should
     never be able to reach somehow got triggered.  Do this by moving much
     of the checking as early as possible and not repeating it later
     (depends on (5) above).

 (7) Fix the sockopts set on a UDP6 socket to include the ones set on a
     UDP4 socket so that we receive UDP4 errors and packet-too-large
     notifications too.

 (8) Fix the distribution of errors so that we do it at the point of
     receiving an error in the UDP callback rather than deferring it
     thereby cutting short any transmissions that would otherwise occur in
     the window.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Sep 29, 2018
2 parents f13d1b4 + f334430 commit f810dce
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 205 deletions.
4 changes: 1 addition & 3 deletions include/trace/events/rxrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ enum rxrpc_peer_trace {
rxrpc_peer_new,
rxrpc_peer_processing,
rxrpc_peer_put,
rxrpc_peer_queued_error,
};

enum rxrpc_conn_trace {
Expand Down Expand Up @@ -257,8 +256,7 @@ enum rxrpc_tx_point {
EM(rxrpc_peer_got, "GOT") \
EM(rxrpc_peer_new, "NEW") \
EM(rxrpc_peer_processing, "PRO") \
EM(rxrpc_peer_put, "PUT") \
E_(rxrpc_peer_queued_error, "QER")
E_(rxrpc_peer_put, "PUT")

#define rxrpc_conn_traces \
EM(rxrpc_conn_got, "GOT") \
Expand Down
36 changes: 19 additions & 17 deletions net/rxrpc/ar-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,12 @@ struct rxrpc_crypt {
struct rxrpc_connection;

/*
* Mark applied to socket buffers.
* Mark applied to socket buffers in skb->mark. skb->priority is used
* to pass supplementary information.
*/
enum rxrpc_skb_mark {
RXRPC_SKB_MARK_DATA, /* data message */
RXRPC_SKB_MARK_FINAL_ACK, /* final ACK received message */
RXRPC_SKB_MARK_BUSY, /* server busy message */
RXRPC_SKB_MARK_REMOTE_ABORT, /* remote abort message */
RXRPC_SKB_MARK_LOCAL_ABORT, /* local abort message */
RXRPC_SKB_MARK_NET_ERROR, /* network error message */
RXRPC_SKB_MARK_LOCAL_ERROR, /* local error message */
RXRPC_SKB_MARK_NEW_CALL, /* local error message */
RXRPC_SKB_MARK_REJECT_BUSY, /* Reject with BUSY */
RXRPC_SKB_MARK_REJECT_ABORT, /* Reject with ABORT (code in skb->priority) */
};

/*
Expand Down Expand Up @@ -293,7 +288,6 @@ struct rxrpc_peer {
struct hlist_node hash_link;
struct rxrpc_local *local;
struct hlist_head error_targets; /* targets for net error distribution */
struct work_struct error_distributor;
struct rb_root service_conns; /* Service connections */
struct list_head keepalive_link; /* Link in net->peer_keepalive[] */
time64_t last_tx_at; /* Last time packet sent here */
Expand All @@ -304,8 +298,6 @@ struct rxrpc_peer {
unsigned int maxdata; /* data size (MTU - hdrsize) */
unsigned short hdrsize; /* header size (IP + UDP + RxRPC) */
int debug_id; /* debug ID for printks */
int error_report; /* Net (+0) or local (+1000000) to distribute */
#define RXRPC_LOCAL_ERROR_OFFSET 1000000
struct sockaddr_rxrpc srx; /* remote address */

/* calculated RTT cache */
Expand Down Expand Up @@ -463,6 +455,16 @@ struct rxrpc_connection {
u8 out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */
};

static inline bool rxrpc_to_server(const struct rxrpc_skb_priv *sp)
{
return sp->hdr.flags & RXRPC_CLIENT_INITIATED;
}

static inline bool rxrpc_to_client(const struct rxrpc_skb_priv *sp)
{
return !rxrpc_to_server(sp);
}

/*
* Flags in call->flags.
*/
Expand Down Expand Up @@ -717,6 +719,8 @@ extern struct workqueue_struct *rxrpc_workqueue;
int rxrpc_service_prealloc(struct rxrpc_sock *, gfp_t);
void rxrpc_discard_prealloc(struct rxrpc_sock *);
struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *,
struct rxrpc_sock *,
struct rxrpc_peer *,
struct rxrpc_connection *,
struct sk_buff *);
void rxrpc_accept_incoming_calls(struct rxrpc_local *);
Expand Down Expand Up @@ -908,7 +912,8 @@ extern unsigned int rxrpc_closed_conn_expiry;

struct rxrpc_connection *rxrpc_alloc_connection(gfp_t);
struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *,
struct sk_buff *);
struct sk_buff *,
struct rxrpc_peer **);
void __rxrpc_disconnect_call(struct rxrpc_connection *, struct rxrpc_call *);
void rxrpc_disconnect_call(struct rxrpc_call *);
void rxrpc_kill_connection(struct rxrpc_connection *);
Expand Down Expand Up @@ -1031,7 +1036,6 @@ void rxrpc_send_keepalive(struct rxrpc_peer *);
* peer_event.c
*/
void rxrpc_error_report(struct sock *);
void rxrpc_peer_error_distributor(struct work_struct *);
void rxrpc_peer_add_rtt(struct rxrpc_call *, enum rxrpc_rtt_rx_trace,
rxrpc_serial_t, rxrpc_serial_t, ktime_t, ktime_t);
void rxrpc_peer_keepalive_worker(struct work_struct *);
Expand All @@ -1044,13 +1048,11 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *,
struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *,
struct sockaddr_rxrpc *, gfp_t);
struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *, gfp_t);
struct rxrpc_peer *rxrpc_lookup_incoming_peer(struct rxrpc_local *,
struct rxrpc_peer *);
void rxrpc_new_incoming_peer(struct rxrpc_local *, struct rxrpc_peer *);
void rxrpc_destroy_all_peers(struct rxrpc_net *);
struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *);
struct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *);
void rxrpc_put_peer(struct rxrpc_peer *);
void __rxrpc_queue_peer_error(struct rxrpc_peer *);

/*
* proc.c
Expand Down
45 changes: 14 additions & 31 deletions net/rxrpc/call_accept.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,11 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
*/
static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
struct rxrpc_local *local,
struct rxrpc_peer *peer,
struct rxrpc_connection *conn,
struct sk_buff *skb)
{
struct rxrpc_backlog *b = rx->backlog;
struct rxrpc_peer *peer, *xpeer;
struct rxrpc_call *call;
unsigned short call_head, conn_head, peer_head;
unsigned short call_tail, conn_tail, peer_tail;
Expand All @@ -276,21 +276,18 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
return NULL;

if (!conn) {
/* No connection. We're going to need a peer to start off
* with. If one doesn't yet exist, use a spare from the
* preallocation set. We dump the address into the spare in
* anticipation - and to save on stack space.
*/
xpeer = b->peer_backlog[peer_tail];
if (rxrpc_extract_addr_from_skb(local, &xpeer->srx, skb) < 0)
return NULL;

peer = rxrpc_lookup_incoming_peer(local, xpeer);
if (peer == xpeer) {
if (peer && !rxrpc_get_peer_maybe(peer))
peer = NULL;
if (!peer) {
peer = b->peer_backlog[peer_tail];
if (rxrpc_extract_addr_from_skb(local, &peer->srx, skb) < 0)
return NULL;
b->peer_backlog[peer_tail] = NULL;
smp_store_release(&b->peer_backlog_tail,
(peer_tail + 1) &
(RXRPC_BACKLOG_MAX - 1));

rxrpc_new_incoming_peer(local, peer);
}

/* Now allocate and set up the connection */
Expand Down Expand Up @@ -335,45 +332,31 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
* The call is returned with the user access mutex held.
*/
struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
struct rxrpc_sock *rx,
struct rxrpc_peer *peer,
struct rxrpc_connection *conn,
struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct rxrpc_sock *rx;
struct rxrpc_call *call;
u16 service_id = sp->hdr.serviceId;

_enter("");

/* Get the socket providing the service */
rx = rcu_dereference(local->service);
if (rx && (service_id == rx->srx.srx_service ||
service_id == rx->second_service))
goto found_service;

trace_rxrpc_abort(0, "INV", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
RX_INVALID_OPERATION, EOPNOTSUPP);
skb->mark = RXRPC_SKB_MARK_LOCAL_ABORT;
skb->priority = RX_INVALID_OPERATION;
_leave(" = NULL [service]");
return NULL;

found_service:
spin_lock(&rx->incoming_lock);
if (rx->sk.sk_state == RXRPC_SERVER_LISTEN_DISABLED ||
rx->sk.sk_state == RXRPC_CLOSE) {
trace_rxrpc_abort(0, "CLS", sp->hdr.cid, sp->hdr.callNumber,
sp->hdr.seq, RX_INVALID_OPERATION, ESHUTDOWN);
skb->mark = RXRPC_SKB_MARK_LOCAL_ABORT;
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
skb->priority = RX_INVALID_OPERATION;
_leave(" = NULL [close]");
call = NULL;
goto out;
}

call = rxrpc_alloc_incoming_call(rx, local, conn, skb);
call = rxrpc_alloc_incoming_call(rx, local, peer, conn, skb);
if (!call) {
skb->mark = RXRPC_SKB_MARK_BUSY;
skb->mark = RXRPC_SKB_MARK_REJECT_BUSY;
_leave(" = NULL [busy]");
call = NULL;
goto out;
Expand Down
2 changes: 1 addition & 1 deletion net/rxrpc/call_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx,
rcu_assign_pointer(conn->channels[chan].call, call);

spin_lock(&conn->params.peer->lock);
hlist_add_head(&call->error_link, &conn->params.peer->error_targets);
hlist_add_head_rcu(&call->error_link, &conn->params.peer->error_targets);
spin_unlock(&conn->params.peer->lock);

_net("CALL incoming %d on CONN %d", call->debug_id, call->conn->debug_id);
Expand Down
4 changes: 2 additions & 2 deletions net/rxrpc/conn_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -710,8 +710,8 @@ int rxrpc_connect_call(struct rxrpc_call *call,
}

spin_lock_bh(&call->conn->params.peer->lock);
hlist_add_head(&call->error_link,
&call->conn->params.peer->error_targets);
hlist_add_head_rcu(&call->error_link,
&call->conn->params.peer->error_targets);
spin_unlock_bh(&call->conn->params.peer->lock);

out:
Expand Down
14 changes: 8 additions & 6 deletions net/rxrpc/conn_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,14 @@ struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
* If successful, a pointer to the connection is returned, but no ref is taken.
* NULL is returned if there is no match.
*
* When searching for a service call, if we find a peer but no connection, we
* return that through *_peer in case we need to create a new service call.
*
* The caller must be holding the RCU read lock.
*/
struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local,
struct sk_buff *skb)
struct sk_buff *skb,
struct rxrpc_peer **_peer)
{
struct rxrpc_connection *conn;
struct rxrpc_conn_proto k;
Expand All @@ -85,9 +89,6 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local,
if (rxrpc_extract_addr_from_skb(local, &srx, skb) < 0)
goto not_found;

k.epoch = sp->hdr.epoch;
k.cid = sp->hdr.cid & RXRPC_CIDMASK;

/* We may have to handle mixing IPv4 and IPv6 */
if (srx.transport.family != local->srx.transport.family) {
pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n",
Expand All @@ -99,14 +100,15 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local,
k.epoch = sp->hdr.epoch;
k.cid = sp->hdr.cid & RXRPC_CIDMASK;

if (sp->hdr.flags & RXRPC_CLIENT_INITIATED) {
if (rxrpc_to_server(sp)) {
/* We need to look up service connections by the full protocol
* parameter set. We look up the peer first as an intermediate
* step and then the connection from the peer's tree.
*/
peer = rxrpc_lookup_peer_rcu(local, &srx);
if (!peer)
goto not_found;
*_peer = peer;
conn = rxrpc_find_service_conn_rcu(peer, skb);
if (!conn || atomic_read(&conn->usage) == 0)
goto not_found;
Expand Down Expand Up @@ -214,7 +216,7 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
call->peer->cong_cwnd = call->cong_cwnd;

spin_lock_bh(&conn->params.peer->lock);
hlist_del_init(&call->error_link);
hlist_del_rcu(&call->error_link);
spin_unlock_bh(&conn->params.peer->lock);

if (rxrpc_is_client_call(call))
Expand Down
Loading

0 comments on commit f810dce

Please sign in to comment.