18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/net/sunrpc/timer.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Estimate RPC request round trip time.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Based on packet round-trip and variance estimator algorithms described
88c2ecf20Sopenharmony_ci * in appendix A of "Congestion Avoidance and Control" by Van Jacobson
98c2ecf20Sopenharmony_ci * and Michael J. Karels (ACM Computer Communication Review; Proceedings
108c2ecf20Sopenharmony_ci * of the Sigcomm '88 Symposium in Stanford, CA, August, 1988).
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * This RTT estimator is used only for RPC over datagram protocols.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <asm/param.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/types.h>
208c2ecf20Sopenharmony_ci#include <linux/unistd.h>
218c2ecf20Sopenharmony_ci#include <linux/module.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define RPC_RTO_MAX (60*HZ)
268c2ecf20Sopenharmony_ci#define RPC_RTO_INIT (HZ/5)
278c2ecf20Sopenharmony_ci#define RPC_RTO_MIN (HZ/10)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/**
308c2ecf20Sopenharmony_ci * rpc_init_rtt - Initialize an RPC RTT estimator context
318c2ecf20Sopenharmony_ci * @rt: context to initialize
328c2ecf20Sopenharmony_ci * @timeo: initial timeout value, in jiffies
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_civoid rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	unsigned long init = 0;
388c2ecf20Sopenharmony_ci	unsigned int i;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	rt->timeo = timeo;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	if (timeo > RPC_RTO_INIT)
438c2ecf20Sopenharmony_ci		init = (timeo - RPC_RTO_INIT) << 3;
448c2ecf20Sopenharmony_ci	for (i = 0; i < 5; i++) {
458c2ecf20Sopenharmony_ci		rt->srtt[i] = init;
468c2ecf20Sopenharmony_ci		rt->sdrtt[i] = RPC_RTO_INIT;
478c2ecf20Sopenharmony_ci		rt->ntimeouts[i] = 0;
488c2ecf20Sopenharmony_ci	}
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_init_rtt);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/**
538c2ecf20Sopenharmony_ci * rpc_update_rtt - Update an RPC RTT estimator context
548c2ecf20Sopenharmony_ci * @rt: context to update
558c2ecf20Sopenharmony_ci * @timer: timer array index (request type)
568c2ecf20Sopenharmony_ci * @m: recent actual RTT, in jiffies
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci * NB: When computing the smoothed RTT and standard deviation,
598c2ecf20Sopenharmony_ci *     be careful not to produce negative intermediate results.
608c2ecf20Sopenharmony_ci */
618c2ecf20Sopenharmony_civoid rpc_update_rtt(struct rpc_rtt *rt, unsigned int timer, long m)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	long *srtt, *sdrtt;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (timer-- == 0)
668c2ecf20Sopenharmony_ci		return;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	/* jiffies wrapped; ignore this one */
698c2ecf20Sopenharmony_ci	if (m < 0)
708c2ecf20Sopenharmony_ci		return;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (m == 0)
738c2ecf20Sopenharmony_ci		m = 1L;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	srtt = (long *)&rt->srtt[timer];
768c2ecf20Sopenharmony_ci	m -= *srtt >> 3;
778c2ecf20Sopenharmony_ci	*srtt += m;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (m < 0)
808c2ecf20Sopenharmony_ci		m = -m;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	sdrtt = (long *)&rt->sdrtt[timer];
838c2ecf20Sopenharmony_ci	m -= *sdrtt >> 2;
848c2ecf20Sopenharmony_ci	*sdrtt += m;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/* Set lower bound on the variance */
878c2ecf20Sopenharmony_ci	if (*sdrtt < RPC_RTO_MIN)
888c2ecf20Sopenharmony_ci		*sdrtt = RPC_RTO_MIN;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_update_rtt);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/**
938c2ecf20Sopenharmony_ci * rpc_calc_rto - Provide an estimated timeout value
948c2ecf20Sopenharmony_ci * @rt: context to use for calculation
958c2ecf20Sopenharmony_ci * @timer: timer array index (request type)
968c2ecf20Sopenharmony_ci *
978c2ecf20Sopenharmony_ci * Estimate RTO for an NFS RPC sent via an unreliable datagram.  Use
988c2ecf20Sopenharmony_ci * the mean and mean deviation of RTT for the appropriate type of RPC
998c2ecf20Sopenharmony_ci * for frequently issued RPCs, and a fixed default for the others.
1008c2ecf20Sopenharmony_ci *
1018c2ecf20Sopenharmony_ci * The justification for doing "other" this way is that these RPCs
1028c2ecf20Sopenharmony_ci * happen so infrequently that timer estimation would probably be
1038c2ecf20Sopenharmony_ci * stale.  Also, since many of these RPCs are non-idempotent, a
1048c2ecf20Sopenharmony_ci * conservative timeout is desired.
1058c2ecf20Sopenharmony_ci *
1068c2ecf20Sopenharmony_ci * getattr, lookup,
1078c2ecf20Sopenharmony_ci * read, write, commit     - A+4D
1088c2ecf20Sopenharmony_ci * other                   - timeo
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_ciunsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned int timer)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	unsigned long res;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (timer-- == 0)
1158c2ecf20Sopenharmony_ci		return rt->timeo;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	res = ((rt->srtt[timer] + 7) >> 3) + rt->sdrtt[timer];
1188c2ecf20Sopenharmony_ci	if (res > RPC_RTO_MAX)
1198c2ecf20Sopenharmony_ci		res = RPC_RTO_MAX;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return res;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_calc_rto);
124