1*457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/net/sunrpc/timer.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Estimate RPC request round trip time.
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Based on packet round-trip and variance estimator algorithms described
81da177e4SLinus Torvalds * in appendix A of "Congestion Avoidance and Control" by Van Jacobson
91da177e4SLinus Torvalds * and Michael J. Karels (ACM Computer Communication Review; Proceedings
101da177e4SLinus Torvalds * of the Sigcomm '88 Symposium in Stanford, CA, August, 1988).
111da177e4SLinus Torvalds *
121da177e4SLinus Torvalds * This RTT estimator is used only for RPC over datagram protocols.
131da177e4SLinus Torvalds *
141da177e4SLinus Torvalds * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
151da177e4SLinus Torvalds */
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds #include <asm/param.h>
181da177e4SLinus Torvalds
191da177e4SLinus Torvalds #include <linux/types.h>
201da177e4SLinus Torvalds #include <linux/unistd.h>
2112444809S\"Talpey, Thomas\ #include <linux/module.h>
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds #define RPC_RTO_MAX (60*HZ)
261da177e4SLinus Torvalds #define RPC_RTO_INIT (HZ/5)
271da177e4SLinus Torvalds #define RPC_RTO_MIN (HZ/10)
281da177e4SLinus Torvalds
29c05988cdSChuck Lever /**
30c05988cdSChuck Lever * rpc_init_rtt - Initialize an RPC RTT estimator context
31c05988cdSChuck Lever * @rt: context to initialize
32c05988cdSChuck Lever * @timeo: initial timeout value, in jiffies
33c05988cdSChuck Lever *
34c05988cdSChuck Lever */
rpc_init_rtt(struct rpc_rtt * rt,unsigned long timeo)35c05988cdSChuck Lever void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
361da177e4SLinus Torvalds {
371da177e4SLinus Torvalds unsigned long init = 0;
3895c96174SEric Dumazet unsigned int i;
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds rt->timeo = timeo;
411da177e4SLinus Torvalds
421da177e4SLinus Torvalds if (timeo > RPC_RTO_INIT)
431da177e4SLinus Torvalds init = (timeo - RPC_RTO_INIT) << 3;
441da177e4SLinus Torvalds for (i = 0; i < 5; i++) {
451da177e4SLinus Torvalds rt->srtt[i] = init;
461da177e4SLinus Torvalds rt->sdrtt[i] = RPC_RTO_INIT;
471da177e4SLinus Torvalds rt->ntimeouts[i] = 0;
481da177e4SLinus Torvalds }
491da177e4SLinus Torvalds }
5012444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(rpc_init_rtt);
511da177e4SLinus Torvalds
52c05988cdSChuck Lever /**
53c05988cdSChuck Lever * rpc_update_rtt - Update an RPC RTT estimator context
54c05988cdSChuck Lever * @rt: context to update
55c05988cdSChuck Lever * @timer: timer array index (request type)
56c05988cdSChuck Lever * @m: recent actual RTT, in jiffies
57c05988cdSChuck Lever *
581da177e4SLinus Torvalds * NB: When computing the smoothed RTT and standard deviation,
591da177e4SLinus Torvalds * be careful not to produce negative intermediate results.
601da177e4SLinus Torvalds */
rpc_update_rtt(struct rpc_rtt * rt,unsigned int timer,long m)6195c96174SEric Dumazet void rpc_update_rtt(struct rpc_rtt *rt, unsigned int timer, long m)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds long *srtt, *sdrtt;
641da177e4SLinus Torvalds
651da177e4SLinus Torvalds if (timer-- == 0)
661da177e4SLinus Torvalds return;
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds /* jiffies wrapped; ignore this one */
691da177e4SLinus Torvalds if (m < 0)
701da177e4SLinus Torvalds return;
711da177e4SLinus Torvalds
721da177e4SLinus Torvalds if (m == 0)
731da177e4SLinus Torvalds m = 1L;
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds srtt = (long *)&rt->srtt[timer];
761da177e4SLinus Torvalds m -= *srtt >> 3;
771da177e4SLinus Torvalds *srtt += m;
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds if (m < 0)
801da177e4SLinus Torvalds m = -m;
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds sdrtt = (long *)&rt->sdrtt[timer];
831da177e4SLinus Torvalds m -= *sdrtt >> 2;
841da177e4SLinus Torvalds *sdrtt += m;
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds /* Set lower bound on the variance */
871da177e4SLinus Torvalds if (*sdrtt < RPC_RTO_MIN)
881da177e4SLinus Torvalds *sdrtt = RPC_RTO_MIN;
891da177e4SLinus Torvalds }
9012444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(rpc_update_rtt);
911da177e4SLinus Torvalds
92c05988cdSChuck Lever /**
93c05988cdSChuck Lever * rpc_calc_rto - Provide an estimated timeout value
94c05988cdSChuck Lever * @rt: context to use for calculation
95c05988cdSChuck Lever * @timer: timer array index (request type)
96c05988cdSChuck Lever *
97c05988cdSChuck Lever * Estimate RTO for an NFS RPC sent via an unreliable datagram. Use
98c05988cdSChuck Lever * the mean and mean deviation of RTT for the appropriate type of RPC
99c05988cdSChuck Lever * for frequently issued RPCs, and a fixed default for the others.
100c05988cdSChuck Lever *
101c05988cdSChuck Lever * The justification for doing "other" this way is that these RPCs
102c05988cdSChuck Lever * happen so infrequently that timer estimation would probably be
103c05988cdSChuck Lever * stale. Also, since many of these RPCs are non-idempotent, a
104c05988cdSChuck Lever * conservative timeout is desired.
105c05988cdSChuck Lever *
1061da177e4SLinus Torvalds * getattr, lookup,
1071da177e4SLinus Torvalds * read, write, commit - A+4D
1081da177e4SLinus Torvalds * other - timeo
1091da177e4SLinus Torvalds */
rpc_calc_rto(struct rpc_rtt * rt,unsigned int timer)11095c96174SEric Dumazet unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned int timer)
1111da177e4SLinus Torvalds {
1121da177e4SLinus Torvalds unsigned long res;
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds if (timer-- == 0)
1151da177e4SLinus Torvalds return rt->timeo;
1161da177e4SLinus Torvalds
1171da177e4SLinus Torvalds res = ((rt->srtt[timer] + 7) >> 3) + rt->sdrtt[timer];
1181da177e4SLinus Torvalds if (res > RPC_RTO_MAX)
1191da177e4SLinus Torvalds res = RPC_RTO_MAX;
1201da177e4SLinus Torvalds
1211da177e4SLinus Torvalds return res;
1221da177e4SLinus Torvalds }
12312444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(rpc_calc_rto);
124