Commit 153f90a0 authored by David Howells's avatar David Howells
Browse files

rxrpc: Use ktimes for call timeout tracking and set the timer lazily



Track the call timeouts as ktimes rather than jiffies as the latter's
granularity is too high and only set the timer at the end of the event
handling function.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Eric Dumazet <edumazet@google.com>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
parent 12a66e77
Loading
Loading
Loading
Loading
+93 −81
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@
	EM(rxrpc_call_poke_complete,		"Compl")	\
	EM(rxrpc_call_poke_error,		"Error")	\
	EM(rxrpc_call_poke_idle,		"Idle")		\
	EM(rxrpc_call_poke_set_timeout,		"Set-timo")	\
	EM(rxrpc_call_poke_start,		"Start")	\
	EM(rxrpc_call_poke_timer,		"Timer")	\
	E_(rxrpc_call_poke_timer_now,		"Timer-now")
@@ -340,27 +341,16 @@
	E_(rxrpc_rtt_rx_requested_ack,		"RACK")

#define rxrpc_timer_traces \
	EM(rxrpc_timer_begin,			"Begin ") \
	EM(rxrpc_timer_exp_ack,			"ExpAck") \
	EM(rxrpc_timer_exp_hard,		"ExpHrd") \
	EM(rxrpc_timer_exp_idle,		"ExpIdl") \
	EM(rxrpc_timer_exp_keepalive,		"ExpKA ") \
	EM(rxrpc_timer_exp_lost_ack,		"ExpLoA") \
	EM(rxrpc_timer_exp_normal,		"ExpNml") \
	EM(rxrpc_timer_exp_ping,		"ExpPng") \
	EM(rxrpc_timer_exp_resend,		"ExpRsn") \
	EM(rxrpc_timer_init_for_reply,		"IniRpl") \
	EM(rxrpc_timer_init_for_send_reply,	"SndRpl") \
	EM(rxrpc_timer_restart,			"Restrt") \
	EM(rxrpc_timer_set_for_ack,		"SetAck") \
	EM(rxrpc_timer_set_for_hard,		"SetHrd") \
	EM(rxrpc_timer_set_for_idle,		"SetIdl") \
	EM(rxrpc_timer_set_for_keepalive,	"KeepAl") \
	EM(rxrpc_timer_set_for_lost_ack,	"SetLoA") \
	EM(rxrpc_timer_set_for_normal,		"SetNml") \
	EM(rxrpc_timer_set_for_ping,		"SetPng") \
	EM(rxrpc_timer_set_for_resend,		"SetRTx") \
	E_(rxrpc_timer_set_for_send,		"SetSnd")
	EM(rxrpc_timer_trace_delayed_ack,	"DelayAck ") \
	EM(rxrpc_timer_trace_expect_rx,		"ExpectRx ") \
	EM(rxrpc_timer_trace_hard,		"HardLimit") \
	EM(rxrpc_timer_trace_idle,		"IdleLimit") \
	EM(rxrpc_timer_trace_keepalive,		"KeepAlive") \
	EM(rxrpc_timer_trace_lost_ack,		"LostAck  ") \
	EM(rxrpc_timer_trace_ping,		"DelayPing") \
	EM(rxrpc_timer_trace_resend,		"Resend   ") \
	EM(rxrpc_timer_trace_resend_reset,	"ResendRst") \
	E_(rxrpc_timer_trace_resend_tx,		"ResendTx ")

#define rxrpc_propose_ack_traces \
	EM(rxrpc_propose_ack_client_tx_end,	"ClTxEnd") \
@@ -1314,90 +1304,112 @@ TRACE_EVENT(rxrpc_rtt_rx,
		      __entry->rto)
	    );

TRACE_EVENT(rxrpc_timer,
	    TP_PROTO(struct rxrpc_call *call, enum rxrpc_timer_trace why,
		     unsigned long now),
TRACE_EVENT(rxrpc_timer_set,
	    TP_PROTO(struct rxrpc_call *call, ktime_t delay,
		     enum rxrpc_timer_trace why),

	    TP_ARGS(call, why, now),
	    TP_ARGS(call, delay, why),

	    TP_STRUCT__entry(
		    __field(unsigned int,		call)
		    __field(enum rxrpc_timer_trace,	why)
		    __field(long,			now)
		    __field(long,			ack_at)
		    __field(long,			ack_lost_at)
		    __field(long,			resend_at)
		    __field(long,			ping_at)
		    __field(long,			expect_rx_by)
		    __field(long,			expect_req_by)
		    __field(long,			expect_term_by)
		    __field(long,			timer)
		    __field(ktime_t,			delay)
			     ),

	    TP_fast_assign(
		    __entry->call		= call->debug_id;
		    __entry->why		= why;
		    __entry->now		= now;
		    __entry->ack_at		= call->delay_ack_at;
		    __entry->ack_lost_at	= call->ack_lost_at;
		    __entry->resend_at		= call->resend_at;
		    __entry->expect_rx_by	= call->expect_rx_by;
		    __entry->expect_req_by	= call->expect_req_by;
		    __entry->expect_term_by	= call->expect_term_by;
		    __entry->timer		= call->timer.expires;
		    __entry->delay		= delay;
			   ),

	    TP_printk("c=%08x %s a=%ld la=%ld r=%ld xr=%ld xq=%ld xt=%ld t=%ld",
	    TP_printk("c=%08x %s to=%lld",
		      __entry->call,
		      __print_symbolic(__entry->why, rxrpc_timer_traces),
		      __entry->ack_at - __entry->now,
		      __entry->ack_lost_at - __entry->now,
		      __entry->resend_at - __entry->now,
		      __entry->expect_rx_by - __entry->now,
		      __entry->expect_req_by - __entry->now,
		      __entry->expect_term_by - __entry->now,
		      __entry->timer - __entry->now)
		      ktime_to_us(__entry->delay))
	    );

TRACE_EVENT(rxrpc_timer_expired,
	    TP_PROTO(struct rxrpc_call *call, unsigned long now),
TRACE_EVENT(rxrpc_timer_exp,
	    TP_PROTO(struct rxrpc_call *call, ktime_t delay,
		     enum rxrpc_timer_trace why),

	    TP_ARGS(call, now),
	    TP_ARGS(call, delay, why),

	    TP_STRUCT__entry(
		    __field(unsigned int,		call)
		    __field(long,		now)
		    __field(long,		ack_at)
		    __field(long,		ack_lost_at)
		    __field(long,		resend_at)
		    __field(long,		ping_at)
		    __field(long,		expect_rx_by)
		    __field(long,		expect_req_by)
		    __field(long,		expect_term_by)
		    __field(long,		timer)
		    __field(enum rxrpc_timer_trace,	why)
		    __field(ktime_t,			delay)
			     ),

	    TP_fast_assign(
		    __entry->call		= call->debug_id;
		    __entry->now		= now;
		    __entry->ack_at		= call->delay_ack_at;
		    __entry->ack_lost_at	= call->ack_lost_at;
		    __entry->resend_at		= call->resend_at;
		    __entry->expect_rx_by	= call->expect_rx_by;
		    __entry->expect_req_by	= call->expect_req_by;
		    __entry->expect_term_by	= call->expect_term_by;
		    __entry->timer		= call->timer.expires;
		    __entry->why		= why;
		    __entry->delay		= delay;
			   ),

	    TP_printk("c=%08x EXPIRED a=%ld la=%ld r=%ld xr=%ld xq=%ld xt=%ld t=%ld",
	    TP_printk("c=%08x %s to=%lld",
		      __entry->call,
		      __entry->ack_at - __entry->now,
		      __entry->ack_lost_at - __entry->now,
		      __entry->resend_at - __entry->now,
		      __entry->expect_rx_by - __entry->now,
		      __entry->expect_req_by - __entry->now,
		      __entry->expect_term_by - __entry->now,
		      __entry->timer - __entry->now)
		      __print_symbolic(__entry->why, rxrpc_timer_traces),
		      ktime_to_us(__entry->delay))
	    );

TRACE_EVENT(rxrpc_timer_can,
	    TP_PROTO(struct rxrpc_call *call, enum rxrpc_timer_trace why),

	    TP_ARGS(call, why),

	    TP_STRUCT__entry(
		    __field(unsigned int,		call)
		    __field(enum rxrpc_timer_trace,	why)
			     ),

	    TP_fast_assign(
		    __entry->call		= call->debug_id;
		    __entry->why		= why;
			   ),

	    TP_printk("c=%08x %s",
		      __entry->call,
		      __print_symbolic(__entry->why, rxrpc_timer_traces))
	    );

TRACE_EVENT(rxrpc_timer_restart,
	    TP_PROTO(struct rxrpc_call *call, ktime_t delay, unsigned long delayj),

	    TP_ARGS(call, delay, delayj),

	    TP_STRUCT__entry(
		    __field(unsigned int,		call)
		    __field(unsigned long,		delayj)
		    __field(ktime_t,			delay)
			     ),

	    TP_fast_assign(
		    __entry->call		= call->debug_id;
		    __entry->delayj		= delayj;
		    __entry->delay		= delay;
			   ),

	    TP_printk("c=%08x to=%lld j=%ld",
		      __entry->call,
		      ktime_to_us(__entry->delay),
		      __entry->delayj)
	    );

TRACE_EVENT(rxrpc_timer_expired,
	    TP_PROTO(struct rxrpc_call *call),

	    TP_ARGS(call),

	    TP_STRUCT__entry(
		    __field(unsigned int,	call)
			     ),

	    TP_fast_assign(
		    __entry->call		= call->debug_id;
			   ),

	    TP_printk("c=%08x EXPIRED",
		      __entry->call)
	    );

TRACE_EVENT(rxrpc_rx_lose,
@@ -1507,7 +1519,7 @@ TRACE_EVENT(rxrpc_drop_ack,

TRACE_EVENT(rxrpc_retransmit,
	    TP_PROTO(struct rxrpc_call *call, rxrpc_seq_t seq,
		     rxrpc_serial_t serial, s64 expiry),
		     rxrpc_serial_t serial, ktime_t expiry),

	    TP_ARGS(call, seq, serial, expiry),

@@ -1515,7 +1527,7 @@ TRACE_EVENT(rxrpc_retransmit,
		    __field(unsigned int,	call)
		    __field(rxrpc_seq_t,	seq)
		    __field(rxrpc_serial_t,	serial)
		    __field(s64,		expiry)
		    __field(ktime_t,		expiry)
			     ),

	    TP_fast_assign(
@@ -1529,7 +1541,7 @@ TRACE_EVENT(rxrpc_retransmit,
		      __entry->call,
		      __entry->seq,
		      __entry->serial,
		      __entry->expiry)
		      ktime_to_us(__entry->expiry))
	    );

TRACE_EVENT(rxrpc_congest,
+6 −6
Original line number Diff line number Diff line
@@ -487,7 +487,7 @@ EXPORT_SYMBOL(rxrpc_kernel_new_call_notification);
 * rxrpc_kernel_set_max_life - Set maximum lifespan on a call
 * @sock: The socket the call is on
 * @call: The call to configure
 * @hard_timeout: The maximum lifespan of the call in jiffies
 * @hard_timeout: The maximum lifespan of the call in ms
 *
 * Set the maximum lifespan of a call.  The call will end with ETIME or
 * ETIMEDOUT if it takes longer than this.
@@ -495,14 +495,14 @@ EXPORT_SYMBOL(rxrpc_kernel_new_call_notification);
void rxrpc_kernel_set_max_life(struct socket *sock, struct rxrpc_call *call,
			       unsigned long hard_timeout)
{
	unsigned long now;
	ktime_t delay = ms_to_ktime(hard_timeout), expect_term_by;

	mutex_lock(&call->user_mutex);

	now = jiffies;
	hard_timeout += now;
	WRITE_ONCE(call->expect_term_by, hard_timeout);
	rxrpc_reduce_call_timer(call, hard_timeout, now, rxrpc_timer_set_for_hard);
	expect_term_by = ktime_add(ktime_get_real(), delay);
	WRITE_ONCE(call->expect_term_by, expect_term_by);
	trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_hard);
	rxrpc_poke_call(call, rxrpc_call_poke_set_timeout);

	mutex_unlock(&call->user_mutex);
}
+15 −20
Original line number Diff line number Diff line
@@ -352,8 +352,8 @@ struct rxrpc_peer {
	u32			mdev_us;	/* medium deviation			*/
	u32			mdev_max_us;	/* maximal mdev for the last rtt period	*/
	u32			rttvar_us;	/* smoothed mdev_max			*/
	u32			rto_j;		/* Retransmission timeout in jiffies */
	u8			backoff;	/* Backoff timeout */
	u32			rto_us;		/* Retransmission timeout in usec */
	u8			backoff;	/* Backoff timeout (as shift) */

	u8			cong_ssthresh;	/* Congestion slow-start threshold */
};
@@ -620,17 +620,17 @@ struct rxrpc_call {
	const struct rxrpc_security *security;	/* applied security module */
	struct mutex		user_mutex;	/* User access mutex */
	struct sockaddr_rxrpc	dest_srx;	/* Destination address */
	unsigned long		delay_ack_at;	/* When DELAY ACK needs to happen */
	unsigned long		ack_lost_at;	/* When ACK is figured as lost */
	unsigned long		resend_at;	/* When next resend needs to happen */
	unsigned long		ping_at;	/* When next to send a ping */
	unsigned long		keepalive_at;	/* When next to send a keepalive ping */
	unsigned long		expect_rx_by;	/* When we expect to get a packet by */
	unsigned long		expect_req_by;	/* When we expect to get a request DATA packet by */
	unsigned long		expect_term_by;	/* When we expect call termination by */
	u32			next_rx_timo;	/* Timeout for next Rx packet (jif) */
	u32			next_req_timo;	/* Timeout for next Rx request packet (jif) */
	u32			hard_timo;	/* Maximum lifetime or 0 (jif) */
	ktime_t			delay_ack_at;	/* When DELAY ACK needs to happen */
	ktime_t			ack_lost_at;	/* When ACK is figured as lost */
	ktime_t			resend_at;	/* When next resend needs to happen */
	ktime_t			ping_at;	/* When next to send a ping */
	ktime_t			keepalive_at;	/* When next to send a keepalive ping */
	ktime_t			expect_rx_by;	/* When we expect to get a packet by */
	ktime_t			expect_req_by;	/* When we expect to get a request DATA packet by */
	ktime_t			expect_term_by;	/* When we expect call termination by */
	u32			next_rx_timo;	/* Timeout for next Rx packet (ms) */
	u32			next_req_timo;	/* Timeout for next Rx request packet (ms) */
	u32			hard_timo;	/* Maximum lifetime or 0 (s) */
	struct timer_list	timer;		/* Combined event timer */
	struct work_struct	destroyer;	/* In-process-context destroyer */
	rxrpc_notify_rx_t	notify_rx;	/* kernel service Rx notification function */
@@ -675,7 +675,7 @@ struct rxrpc_call {
	rxrpc_seq_t		tx_transmitted;	/* Highest packet transmitted */
	rxrpc_seq_t		tx_prepared;	/* Highest Tx slot prepared. */
	rxrpc_seq_t		tx_top;		/* Highest Tx slot allocated. */
	u16			tx_backoff;	/* Delay to insert due to Tx failure */
	u16			tx_backoff;	/* Delay to insert due to Tx failure (ms) */
	u8			tx_winsize;	/* Maximum size of Tx window */
#define RXRPC_TX_MAX_WINDOW	128
	ktime_t			tx_last_sent;	/* Last time a transmission occurred */
@@ -866,11 +866,6 @@ void rxrpc_propose_delay_ACK(struct rxrpc_call *, rxrpc_serial_t,
void rxrpc_shrink_call_tx_buffer(struct rxrpc_call *);
void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb);

void rxrpc_reduce_call_timer(struct rxrpc_call *call,
			     unsigned long expire_at,
			     unsigned long now,
			     enum rxrpc_timer_trace why);

bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb);

/*
@@ -1214,7 +1209,7 @@ static inline int rxrpc_abort_eproto(struct rxrpc_call *call,
 */
void rxrpc_peer_add_rtt(struct rxrpc_call *, enum rxrpc_rtt_rx_trace, int,
			rxrpc_serial_t, rxrpc_serial_t, ktime_t, ktime_t);
unsigned long rxrpc_get_rto_backoff(struct rxrpc_peer *, bool);
ktime_t rxrpc_get_rto_backoff(struct rxrpc_peer *peer, bool retrans);
void rxrpc_peer_init_rtt(struct rxrpc_peer *);

/*
+94 −95
Original line number Diff line number Diff line
@@ -23,14 +23,14 @@
void rxrpc_propose_ping(struct rxrpc_call *call, u32 serial,
			enum rxrpc_propose_ack_trace why)
{
	unsigned long now = jiffies;
	unsigned long ping_at = now + rxrpc_idle_ack_delay;
	ktime_t delay = ms_to_ktime(READ_ONCE(rxrpc_idle_ack_delay));
	ktime_t now = ktime_get_real();
	ktime_t ping_at = ktime_add(now, delay);

	if (time_before(ping_at, call->ping_at)) {
		call->ping_at = ping_at;
		rxrpc_reduce_call_timer(call, ping_at, now,
					rxrpc_timer_set_for_ping);
	trace_rxrpc_propose_ack(call, why, RXRPC_ACK_PING, serial);
	if (ktime_before(ping_at, call->ping_at)) {
		call->ping_at = ping_at;
		trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_ping);
	}
}

@@ -40,25 +40,18 @@ void rxrpc_propose_ping(struct rxrpc_call *call, u32 serial,
void rxrpc_propose_delay_ACK(struct rxrpc_call *call, rxrpc_serial_t serial,
			     enum rxrpc_propose_ack_trace why)
{
	unsigned long expiry = rxrpc_soft_ack_delay;
	unsigned long now = jiffies, ack_at;
	ktime_t now = ktime_get_real(), delay;

	if (rxrpc_soft_ack_delay < expiry)
		expiry = rxrpc_soft_ack_delay;
	if (call->peer->srtt_us != 0)
		ack_at = usecs_to_jiffies(call->peer->srtt_us >> 3);
	else
		ack_at = expiry;
	trace_rxrpc_propose_ack(call, why, RXRPC_ACK_DELAY, serial);

	ack_at += READ_ONCE(call->tx_backoff);
	ack_at += now;
	if (time_before(ack_at, call->delay_ack_at)) {
		call->delay_ack_at = ack_at;
		rxrpc_reduce_call_timer(call, ack_at, now,
					rxrpc_timer_set_for_ack);
	}
	if (call->peer->srtt_us)
		delay = (call->peer->srtt_us >> 3) * NSEC_PER_USEC;
	else
		delay = ms_to_ktime(READ_ONCE(rxrpc_soft_ack_delay));
	ktime_add_ms(delay, call->tx_backoff);

	trace_rxrpc_propose_ack(call, why, RXRPC_ACK_DELAY, serial);
	call->delay_ack_at = ktime_add(now, delay);
	trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_delayed_ack);
}

/*
@@ -77,9 +70,8 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb)
	struct rxrpc_ackpacket *ack = NULL;
	struct rxrpc_skb_priv *sp;
	struct rxrpc_txbuf *txb;
	unsigned long resend_at;
	rxrpc_seq_t transmitted = call->tx_transmitted;
	ktime_t now, max_age, oldest, ack_ts;
	ktime_t now, max_age, oldest, ack_ts, delay;
	bool unacked = false;
	unsigned int i;
	LIST_HEAD(retrans_queue);
@@ -87,7 +79,7 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb)
	_enter("{%d,%d}", call->acks_hard_ack, call->tx_top);

	now = ktime_get_real();
	max_age = ktime_sub_us(now, jiffies_to_usecs(call->peer->rto_j));
	max_age = ktime_sub_us(now, call->peer->rto_us);
	oldest = now;

	if (list_empty(&call->tx_buffer))
@@ -178,10 +170,8 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb)

no_further_resend:
no_resend:
	resend_at = nsecs_to_jiffies(ktime_to_ns(ktime_sub(now, oldest)));
	resend_at += jiffies + rxrpc_get_rto_backoff(call->peer,
						     !list_empty(&retrans_queue));
	call->resend_at = resend_at;
	delay = rxrpc_get_rto_backoff(call->peer, !list_empty(&retrans_queue));
	call->resend_at = ktime_add(oldest, delay);

	if (unacked)
		rxrpc_congestion_timeout(call);
@@ -191,8 +181,7 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb)
	 * retransmitting data.
	 */
	if (list_empty(&retrans_queue)) {
		rxrpc_reduce_call_timer(call, resend_at, jiffies,
					rxrpc_timer_set_for_resend);
		trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_resend_reset);
		ack_ts = ktime_sub(now, call->acks_latest_ts);
		if (ktime_to_us(ack_ts) < (call->peer->srtt_us >> 3))
			goto out;
@@ -218,13 +207,11 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb)
 */
static void rxrpc_begin_service_reply(struct rxrpc_call *call)
{
	unsigned long now = jiffies;

	rxrpc_set_call_state(call, RXRPC_CALL_SERVER_SEND_REPLY);
	call->delay_ack_at = now + MAX_JIFFY_OFFSET;
	if (call->ackr_reason == RXRPC_ACK_DELAY)
		call->ackr_reason = 0;
	trace_rxrpc_timer(call, rxrpc_timer_init_for_send_reply, now);
	call->delay_ack_at = KTIME_MAX;
	trace_rxrpc_timer_can(call, rxrpc_timer_trace_delayed_ack);
}

/*
@@ -333,8 +320,8 @@ static void rxrpc_send_initial_ping(struct rxrpc_call *call)
 */
bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
{
	unsigned long now, next, t;
	bool resend = false, expired = false;
	ktime_t now, t;
	bool resend = false;
	s32 abort_code;

	rxrpc_see_call(call, rxrpc_call_see_input);
@@ -362,66 +349,69 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
		rxrpc_input_call_packet(call, skb);

	/* If we see our async-event poke, check for timeout trippage. */
	now = jiffies;
	t = call->expect_rx_by;
	if (time_after_eq(now, t)) {
		trace_rxrpc_timer(call, rxrpc_timer_exp_normal, now);
		expired = true;
	now = ktime_get_real();
	t = ktime_sub(call->expect_rx_by, now);
	if (t <= 0) {
		trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_expect_rx);
		goto expired;
	}

	t = call->expect_req_by;
	if (__rxrpc_call_state(call) == RXRPC_CALL_SERVER_RECV_REQUEST &&
	    time_after_eq(now, t)) {
		trace_rxrpc_timer(call, rxrpc_timer_exp_idle, now);
		expired = true;
	t = ktime_sub(call->expect_req_by, now);
	if (t <= 0) {
		call->expect_req_by = KTIME_MAX;
		if (__rxrpc_call_state(call) == RXRPC_CALL_SERVER_RECV_REQUEST) {
			trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_idle);
			goto expired;
		}
	}

	t = READ_ONCE(call->expect_term_by);
	if (time_after_eq(now, t)) {
		trace_rxrpc_timer(call, rxrpc_timer_exp_hard, now);
		expired = true;
	t = ktime_sub(READ_ONCE(call->expect_term_by), now);
	if (t <= 0) {
		trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_hard);
		goto expired;
	}

	t = call->delay_ack_at;
	if (time_after_eq(now, t)) {
		trace_rxrpc_timer(call, rxrpc_timer_exp_ack, now);
		call->delay_ack_at = now + MAX_JIFFY_OFFSET;
	t = ktime_sub(call->delay_ack_at, now);
	if (t <= 0) {
		trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_delayed_ack);
		call->delay_ack_at = KTIME_MAX;
		rxrpc_send_ACK(call, RXRPC_ACK_DELAY, 0,
			       rxrpc_propose_ack_delayed_ack);
	}

	t = call->ack_lost_at;
	if (time_after_eq(now, t)) {
		trace_rxrpc_timer(call, rxrpc_timer_exp_lost_ack, now);
		call->ack_lost_at = now + MAX_JIFFY_OFFSET;
	t = ktime_sub(call->ack_lost_at, now);
	if (t <= 0) {
		trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_lost_ack);
		call->ack_lost_at = KTIME_MAX;
		set_bit(RXRPC_CALL_EV_ACK_LOST, &call->events);
	}

	t = call->keepalive_at;
	if (time_after_eq(now, t)) {
		trace_rxrpc_timer(call, rxrpc_timer_exp_keepalive, now);
		call->keepalive_at = now + MAX_JIFFY_OFFSET;
	t = ktime_sub(call->ping_at, now);
	if (t <= 0) {
		trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_ping);
		call->ping_at = KTIME_MAX;
		rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
			       rxrpc_propose_ack_ping_for_keepalive);
	}

	t = call->ping_at;
	if (time_after_eq(now, t)) {
		trace_rxrpc_timer(call, rxrpc_timer_exp_ping, now);
		call->ping_at = now + MAX_JIFFY_OFFSET;
		rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
			       rxrpc_propose_ack_ping_for_keepalive);
	}

	t = call->resend_at;
	if (time_after_eq(now, t)) {
		trace_rxrpc_timer(call, rxrpc_timer_exp_resend, now);
		call->resend_at = now + MAX_JIFFY_OFFSET;
	t = ktime_sub(call->resend_at, now);
	if (t <= 0) {
		trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_resend);
		call->resend_at = KTIME_MAX;
		resend = true;
	}

	rxrpc_transmit_some_data(call);

	now = ktime_get_real();
	t = ktime_sub(call->keepalive_at, now);
	if (t <= 0) {
		trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_keepalive);
		call->keepalive_at = KTIME_MAX;
		rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
			       rxrpc_propose_ack_ping_for_keepalive);
	}

	if (skb) {
		struct rxrpc_skb_priv *sp = rxrpc_skb(skb);

@@ -433,19 +423,6 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
		rxrpc_send_initial_ping(call);

	/* Process events */
	if (expired) {
		if (test_bit(RXRPC_CALL_RX_HEARD, &call->flags) &&
		    (int)call->conn->hi_serial - (int)call->rx_serial > 0) {
			trace_rxrpc_call_reset(call);
			rxrpc_abort_call(call, 0, RX_CALL_DEAD, -ECONNRESET,
					 rxrpc_abort_call_reset);
		} else {
			rxrpc_abort_call(call, 0, RX_CALL_TIMEOUT, -ETIME,
					 rxrpc_abort_call_timeout);
		}
		goto out;
	}

	if (test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events))
		rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
			       rxrpc_propose_ack_ping_for_lost_ack);
@@ -474,23 +451,33 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)

	/* Make sure the timer is restarted */
	if (!__rxrpc_call_is_complete(call)) {
		next = call->expect_rx_by;
		ktime_t next = READ_ONCE(call->expect_term_by), delay;

#define set(T) { t = READ_ONCE(T); if (time_before(t, next)) next = t; }
#define set(T) { ktime_t _t = (T); if (ktime_before(_t, next)) next = _t; }

		set(call->expect_req_by);
		set(call->expect_term_by);
		set(call->expect_rx_by);
		set(call->delay_ack_at);
		set(call->ack_lost_at);
		set(call->resend_at);
		set(call->keepalive_at);
		set(call->ping_at);

		now = jiffies;
		if (time_after_eq(now, next))
		now = ktime_get_real();
		delay = ktime_sub(next, now);
		if (delay <= 0) {
			rxrpc_poke_call(call, rxrpc_call_poke_timer_now);
		} else {
			unsigned long nowj = jiffies, delayj, nextj;

		rxrpc_reduce_call_timer(call, next, now, rxrpc_timer_restart);
			delayj = max(nsecs_to_jiffies(delay), 1);
			nextj = nowj + delayj;
			if (time_before(nextj, call->timer.expires) ||
			    !timer_pending(&call->timer)) {
				trace_rxrpc_timer_restart(call, delay, delayj);
				timer_reduce(&call->timer, nextj);
			}
		}
	}

out:
@@ -505,4 +492,16 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
		rxrpc_shrink_call_tx_buffer(call);
	_leave("");
	return true;

expired:
	if (test_bit(RXRPC_CALL_RX_HEARD, &call->flags) &&
	    (int)call->conn->hi_serial - (int)call->rx_serial > 0) {
		trace_rxrpc_call_reset(call);
		rxrpc_abort_call(call, 0, RX_CALL_DEAD, -ECONNRESET,
				 rxrpc_abort_call_reset);
	} else {
		rxrpc_abort_call(call, 0, RX_CALL_TIMEOUT, -ETIME,
				 rxrpc_abort_call_timeout);
	}
	goto out;
}
+25 −31
Original line number Diff line number Diff line
@@ -70,20 +70,11 @@ static void rxrpc_call_timer_expired(struct timer_list *t)
	_enter("%d", call->debug_id);

	if (!__rxrpc_call_is_complete(call)) {
		trace_rxrpc_timer_expired(call, jiffies);
		trace_rxrpc_timer_expired(call);
		rxrpc_poke_call(call, rxrpc_call_poke_timer);
	}
}

void rxrpc_reduce_call_timer(struct rxrpc_call *call,
			     unsigned long expire_at,
			     unsigned long now,
			     enum rxrpc_timer_trace why)
{
	trace_rxrpc_timer(call, why, now);
	timer_reduce(&call->timer, expire_at);
}

static struct lock_class_key rxrpc_call_user_mutex_lock_class_key;

static void rxrpc_destroy_call(struct work_struct *);
@@ -169,6 +160,14 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,
	call->next_req_timo	= 1 * HZ;
	call->ackr_window	= 1;
	call->ackr_wtop		= 1;
	call->delay_ack_at	= KTIME_MAX;
	call->ack_lost_at	= KTIME_MAX;
	call->resend_at		= KTIME_MAX;
	call->ping_at		= KTIME_MAX;
	call->keepalive_at	= KTIME_MAX;
	call->expect_rx_by	= KTIME_MAX;
	call->expect_req_by	= KTIME_MAX;
	call->expect_term_by	= KTIME_MAX;

	memset(&call->sock_node, 0xed, sizeof(call->sock_node));

@@ -226,11 +225,11 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,
		__set_bit(RXRPC_CALL_EXCLUSIVE, &call->flags);

	if (p->timeouts.normal)
		call->next_rx_timo = min(msecs_to_jiffies(p->timeouts.normal), 1UL);
		call->next_rx_timo = min(p->timeouts.normal, 1);
	if (p->timeouts.idle)
		call->next_req_timo = min(msecs_to_jiffies(p->timeouts.idle), 1UL);
		call->next_req_timo = min(p->timeouts.idle, 1);
	if (p->timeouts.hard)
		call->hard_timo = p->timeouts.hard * HZ;
		call->hard_timo = p->timeouts.hard;

	ret = rxrpc_init_client_call_security(call);
	if (ret < 0) {
@@ -253,18 +252,13 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,
 */
void rxrpc_start_call_timer(struct rxrpc_call *call)
{
	unsigned long now = jiffies;
	unsigned long j = now + MAX_JIFFY_OFFSET;

	call->delay_ack_at = j;
	call->ack_lost_at = j;
	call->resend_at = j;
	call->ping_at = j;
	call->keepalive_at = j;
	call->expect_rx_by = j;
	call->expect_req_by = j;
	call->expect_term_by = j + call->hard_timo;
	call->timer.expires = now;
	if (call->hard_timo) {
		ktime_t delay = ms_to_ktime(call->hard_timo * 1000);

		call->expect_term_by = ktime_add(ktime_get_real(), delay);
		trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_hard);
	}
	call->timer.expires = jiffies;
}

/*
Loading