Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2e80c02 authored by David S. Miller's avatar David S. Miller
Browse files


David Howells says:

====================
rxrpc: Fixes and more traces

Here are some patches that add some more tracepoints to AF_RXRPC and fix
some issues therein:

 (1) Fix the use of VERSION packets to keep firewall routes open.

 (2) Fix the incorrect current time usage in a tracepoint.

 (3) Fix Tx ring annotation corruption.

 (4) Fix accidental conversion of call-level abort into connection-level
     abort.

 (5) Fix calculation of resend time.

 (6) Remove a couple of unused variables.

 (7) Fix a bunch of checker warnings and an error.  Note that not all
     warnings can be quashed as checker doesn't seem to correctly handle
     seqlocks.

 (8) Fix a potential race between call destruction and socket/net
     destruction.

 (9) Add a tracepoint to track rxrpc_local refcounting.

(10) Fix an apparent leak of rxrpc_local objects.

(11) Add a tracepoint to track rxrpc_peer refcounting.

(12) Fix a leak of rxrpc_peer objects.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3be9b5fd 17226f12
Loading
Loading
Loading
Loading
+85 −0
Original line number Diff line number Diff line
@@ -42,6 +42,22 @@ enum rxrpc_skb_trace {
	rxrpc_skb_tx_seen,
};

enum rxrpc_local_trace {
	rxrpc_local_got,
	rxrpc_local_new,
	rxrpc_local_processing,
	rxrpc_local_put,
	rxrpc_local_queued,
};

enum rxrpc_peer_trace {
	rxrpc_peer_got,
	rxrpc_peer_new,
	rxrpc_peer_processing,
	rxrpc_peer_put,
	rxrpc_peer_queued_error,
};

enum rxrpc_conn_trace {
	rxrpc_conn_got,
	rxrpc_conn_new_client,
@@ -215,6 +231,20 @@ enum rxrpc_congest_change {
	EM(rxrpc_skb_tx_rotated,		"Tx ROT") \
	E_(rxrpc_skb_tx_seen,			"Tx SEE")

#define rxrpc_local_traces \
	EM(rxrpc_local_got,			"GOT") \
	EM(rxrpc_local_new,			"NEW") \
	EM(rxrpc_local_processing,		"PRO") \
	EM(rxrpc_local_put,			"PUT") \
	E_(rxrpc_local_queued,			"QUE")

#define rxrpc_peer_traces \
	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")

#define rxrpc_conn_traces \
	EM(rxrpc_conn_got,			"GOT") \
	EM(rxrpc_conn_new_client,		"NWc") \
@@ -416,6 +446,7 @@ enum rxrpc_congest_change {
#define E_(a, b) TRACE_DEFINE_ENUM(a);

rxrpc_skb_traces;
rxrpc_local_traces;
rxrpc_conn_traces;
rxrpc_client_traces;
rxrpc_call_traces;
@@ -439,6 +470,60 @@ rxrpc_congest_changes;
#define EM(a, b)	{ a, b },
#define E_(a, b)	{ a, b }

TRACE_EVENT(rxrpc_local,
	    TP_PROTO(struct rxrpc_local *local, enum rxrpc_local_trace op,
		     int usage, const void *where),

	    TP_ARGS(local, op, usage, where),

	    TP_STRUCT__entry(
		    __field(unsigned int,	local		)
		    __field(int,		op		)
		    __field(int,		usage		)
		    __field(const void *,	where		)
			     ),

	    TP_fast_assign(
		    __entry->local = local->debug_id;
		    __entry->op = op;
		    __entry->usage = usage;
		    __entry->where = where;
			   ),

	    TP_printk("L=%08x %s u=%d sp=%pSR",
		      __entry->local,
		      __print_symbolic(__entry->op, rxrpc_local_traces),
		      __entry->usage,
		      __entry->where)
	    );

TRACE_EVENT(rxrpc_peer,
	    TP_PROTO(struct rxrpc_peer *peer, enum rxrpc_peer_trace op,
		     int usage, const void *where),

	    TP_ARGS(peer, op, usage, where),

	    TP_STRUCT__entry(
		    __field(unsigned int,	peer		)
		    __field(int,		op		)
		    __field(int,		usage		)
		    __field(const void *,	where		)
			     ),

	    TP_fast_assign(
		    __entry->peer = peer->debug_id;
		    __entry->op = op;
		    __entry->usage = usage;
		    __entry->where = where;
			   ),

	    TP_printk("P=%08x %s u=%d sp=%pSR",
		      __entry->peer,
		      __print_symbolic(__entry->op, rxrpc_peer_traces),
		      __entry->usage,
		      __entry->where)
	    );

TRACE_EVENT(rxrpc_conn,
	    TP_PROTO(struct rxrpc_connection *conn, enum rxrpc_conn_trace op,
		     int usage, const void *where),
+6 −0
Original line number Diff line number Diff line
@@ -324,6 +324,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
		mutex_unlock(&call->user_mutex);
	}

	rxrpc_put_peer(cp.peer);
	_leave(" = %p", call);
	return call;
}
@@ -447,6 +448,7 @@ int rxrpc_kernel_retry_call(struct socket *sock, struct rxrpc_call *call,
		ret = rxrpc_retry_client_call(rx, call, &cp, srx, GFP_KERNEL);

	mutex_unlock(&call->user_mutex);
	rxrpc_put_peer(cp.peer);
	_leave(" = %d", ret);
	return ret;
}
@@ -762,6 +764,7 @@ static __poll_t rxrpc_poll(struct file *file, struct socket *sock,
static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
			int kern)
{
	struct rxrpc_net *rxnet;
	struct rxrpc_sock *rx;
	struct sock *sk;

@@ -801,6 +804,9 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
	rwlock_init(&rx->call_lock);
	memset(&rx->srx, 0, sizeof(rx->srx));

	rxnet = rxrpc_net(sock_net(&rx->sk));
	timer_reduce(&rxnet->peer_keepalive_timer, jiffies + 1);

	_leave(" = 0 [%p]", rx);
	return 0;
}
+25 −43
Original line number Diff line number Diff line
@@ -75,7 +75,9 @@ struct rxrpc_net {
	u32			epoch;		/* Local epoch for detecting local-end reset */
	struct list_head	calls;		/* List of calls active in this namespace */
	rwlock_t		call_lock;	/* Lock for ->calls */
	atomic_t		nr_calls;	/* Count of allocated calls */

	atomic_t		nr_conns;
	struct list_head	conn_proc_list;	/* List of conns in this namespace for proc */
	struct list_head	service_conns;	/* Service conns in this namespace */
	rwlock_t		conn_lock;	/* Lock for ->conn_proc_list, ->service_conns */
@@ -97,8 +99,16 @@ struct rxrpc_net {
	struct list_head	local_endpoints;
	struct mutex		local_mutex;	/* Lock for ->local_endpoints */

	spinlock_t		peer_hash_lock;	/* Lock for ->peer_hash */
	DECLARE_HASHTABLE	(peer_hash, 10);
	spinlock_t		peer_hash_lock;	/* Lock for ->peer_hash */

#define RXRPC_KEEPALIVE_TIME 20 /* NAT keepalive time in seconds */
	u8			peer_keepalive_cursor;
	ktime_t			peer_keepalive_base;
	struct hlist_head	peer_keepalive[RXRPC_KEEPALIVE_TIME + 1];
	struct hlist_head	peer_keepalive_new;
	struct timer_list	peer_keepalive_timer;
	struct work_struct	peer_keepalive_work;
};

/*
@@ -285,6 +295,8 @@ struct rxrpc_peer {
	struct hlist_head	error_targets;	/* targets for net error distribution */
	struct work_struct	error_distributor;
	struct rb_root		service_conns;	/* Service connections */
	struct hlist_node	keepalive_link;	/* Link in net->peer_keepalive[] */
	time64_t		last_tx_at;	/* Last time packet sent here */
	seqlock_t		service_conn_lock;
	spinlock_t		lock;		/* access lock */
	unsigned int		if_mtu;		/* interface MTU for this peer */
@@ -518,6 +530,7 @@ struct rxrpc_call {
	struct rxrpc_connection	*conn;		/* connection carrying call */
	struct rxrpc_peer	*peer;		/* Peer record for remote address */
	struct rxrpc_sock __rcu	*socket;	/* socket responsible */
	struct rxrpc_net	*rxnet;		/* Network namespace to which call belongs */
	struct mutex		user_mutex;	/* User access mutex */
	unsigned long		ack_at;		/* When deferred ACK needs to happen */
	unsigned long		ack_lost_at;	/* When ACK is figured as lost */
@@ -969,31 +982,12 @@ extern void rxrpc_process_local_events(struct rxrpc_local *);
 * local_object.c
 */
struct rxrpc_local *rxrpc_lookup_local(struct net *, const struct sockaddr_rxrpc *);
void __rxrpc_put_local(struct rxrpc_local *);
struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *);
struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *);
void rxrpc_put_local(struct rxrpc_local *);
void rxrpc_queue_local(struct rxrpc_local *);
void rxrpc_destroy_all_locals(struct rxrpc_net *);

static inline void rxrpc_get_local(struct rxrpc_local *local)
{
	atomic_inc(&local->usage);
}

static inline
struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local)
{
	return atomic_inc_not_zero(&local->usage) ? local : NULL;
}

static inline void rxrpc_put_local(struct rxrpc_local *local)
{
	if (local && atomic_dec_and_test(&local->usage))
		__rxrpc_put_local(local);
}

static inline void rxrpc_queue_local(struct rxrpc_local *local)
{
	rxrpc_queue_work(&local->processor);
}

/*
 * misc.c
 */
@@ -1026,6 +1020,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *, bool, rxrpc_serial_t *);
int rxrpc_send_abort_packet(struct rxrpc_call *);
int rxrpc_send_data_packet(struct rxrpc_call *, struct sk_buff *, bool);
void rxrpc_reject_packets(struct rxrpc_local *);
void rxrpc_send_keepalive(struct rxrpc_peer *);

/*
 * peer_event.c
@@ -1034,6 +1029,7 @@ 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 *);

/*
 * peer_object.c
@@ -1045,25 +1041,11 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *,
struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *, gfp_t);
struct rxrpc_peer *rxrpc_lookup_incoming_peer(struct rxrpc_local *,
					      struct rxrpc_peer *);

static inline struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *peer)
{
	atomic_inc(&peer->usage);
	return peer;
}

static inline
struct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *peer)
{
	return atomic_inc_not_zero(&peer->usage) ? peer : NULL;
}

extern void __rxrpc_put_peer(struct rxrpc_peer *peer);
static inline void rxrpc_put_peer(struct rxrpc_peer *peer)
{
	if (peer && atomic_dec_and_test(&peer->usage))
		__rxrpc_put_peer(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
+6 −3
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,

	write_unlock(&rx->call_lock);

	rxnet = call->rxnet;
	write_lock(&rxnet->call_lock);
	list_add_tail(&call->link, &rxnet->calls);
	write_unlock(&rxnet->call_lock);
@@ -218,6 +219,8 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
		list_del(&conn->proc_link);
		write_unlock(&rxnet->conn_lock);
		kfree(conn);
		if (atomic_dec_and_test(&rxnet->nr_conns))
			wake_up_atomic_t(&rxnet->nr_conns);
		tail = (tail + 1) & (size - 1);
	}

@@ -225,7 +228,7 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
	tail = b->call_backlog_tail;
	while (CIRC_CNT(head, tail, size) > 0) {
		struct rxrpc_call *call = b->call_backlog[tail];
		call->socket = rx;
		rcu_assign_pointer(call->socket, rx);
		if (rx->discard_new_call) {
			_debug("discard %lx", call->user_call_ID);
			rx->discard_new_call(call, call->user_call_ID);
@@ -295,8 +298,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
		b->conn_backlog[conn_tail] = NULL;
		smp_store_release(&b->conn_backlog_tail,
				  (conn_tail + 1) & (RXRPC_BACKLOG_MAX - 1));
		rxrpc_get_local(local);
		conn->params.local = local;
		conn->params.local = rxrpc_get_local(local);
		conn->params.peer = peer;
		rxrpc_see_connection(conn);
		rxrpc_new_incoming_connection(rx, conn, skb);
@@ -456,6 +458,7 @@ struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *rx,
				     unsigned long user_call_ID,
				     rxrpc_notify_rx_t notify_rx)
	__releases(&rx->sk.sk_lock.slock)
	__acquires(call->user_mutex)
{
	struct rxrpc_call *call;
	struct rb_node *parent, **pp;
+2 −2
Original line number Diff line number Diff line
@@ -226,7 +226,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
				       ktime_to_ns(ktime_sub(skb->tstamp, max_age)));
	}

	resend_at = nsecs_to_jiffies(ktime_to_ns(ktime_sub(oldest, now)));
	resend_at = nsecs_to_jiffies(ktime_to_ns(ktime_sub(now, oldest)));
	resend_at += jiffies + rxrpc_resend_timeout;
	WRITE_ONCE(call->resend_at, resend_at);

@@ -238,7 +238,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
	 * retransmitting data.
	 */
	if (!retrans) {
		rxrpc_reduce_call_timer(call, resend_at, now,
		rxrpc_reduce_call_timer(call, resend_at, now_j,
					rxrpc_timer_set_for_resend);
		spin_unlock_bh(&call->lock);
		ack_ts = ktime_sub(now, call->acks_latest_ts);
Loading