1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/net/sunrpc/timer.c |
4 | * |
5 | * Estimate RPC request round trip time. |
6 | * |
7 | * Based on packet round-trip and variance estimator algorithms described |
8 | * in appendix A of "Congestion Avoidance and Control" by Van Jacobson |
9 | * and Michael J. Karels (ACM Computer Communication Review; Proceedings |
10 | * of the Sigcomm '88 Symposium in Stanford, CA, August, 1988). |
11 | * |
12 | * This RTT estimator is used only for RPC over datagram protocols. |
13 | * |
14 | * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no> |
15 | */ |
16 | |
17 | #include <asm/param.h> |
18 | |
19 | #include <linux/types.h> |
20 | #include <linux/unistd.h> |
21 | #include <linux/module.h> |
22 | |
23 | #include <linux/sunrpc/clnt.h> |
24 | |
25 | #define RPC_RTO_MAX (60*HZ) |
26 | #define RPC_RTO_INIT (HZ/5) |
27 | #define RPC_RTO_MIN (HZ/10) |
28 | |
29 | /** |
30 | * rpc_init_rtt - Initialize an RPC RTT estimator context |
31 | * @rt: context to initialize |
32 | * @timeo: initial timeout value, in jiffies |
33 | * |
34 | */ |
35 | void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo) |
36 | { |
37 | unsigned long init = 0; |
38 | unsigned int i; |
39 | |
40 | rt->timeo = timeo; |
41 | |
42 | if (timeo > RPC_RTO_INIT) |
43 | init = (timeo - RPC_RTO_INIT) << 3; |
44 | for (i = 0; i < 5; i++) { |
45 | rt->srtt[i] = init; |
46 | rt->sdrtt[i] = RPC_RTO_INIT; |
47 | rt->ntimeouts[i] = 0; |
48 | } |
49 | } |
50 | EXPORT_SYMBOL_GPL(rpc_init_rtt); |
51 | |
52 | /** |
53 | * rpc_update_rtt - Update an RPC RTT estimator context |
54 | * @rt: context to update |
55 | * @timer: timer array index (request type) |
56 | * @m: recent actual RTT, in jiffies |
57 | * |
58 | * NB: When computing the smoothed RTT and standard deviation, |
59 | * be careful not to produce negative intermediate results. |
60 | */ |
61 | void rpc_update_rtt(struct rpc_rtt *rt, unsigned int timer, long m) |
62 | { |
63 | long *srtt, *sdrtt; |
64 | |
65 | if (timer-- == 0) |
66 | return; |
67 | |
68 | /* jiffies wrapped; ignore this one */ |
69 | if (m < 0) |
70 | return; |
71 | |
72 | if (m == 0) |
73 | m = 1L; |
74 | |
75 | srtt = (long *)&rt->srtt[timer]; |
76 | m -= *srtt >> 3; |
77 | *srtt += m; |
78 | |
79 | if (m < 0) |
80 | m = -m; |
81 | |
82 | sdrtt = (long *)&rt->sdrtt[timer]; |
83 | m -= *sdrtt >> 2; |
84 | *sdrtt += m; |
85 | |
86 | /* Set lower bound on the variance */ |
87 | if (*sdrtt < RPC_RTO_MIN) |
88 | *sdrtt = RPC_RTO_MIN; |
89 | } |
90 | EXPORT_SYMBOL_GPL(rpc_update_rtt); |
91 | |
92 | /** |
93 | * rpc_calc_rto - Provide an estimated timeout value |
94 | * @rt: context to use for calculation |
95 | * @timer: timer array index (request type) |
96 | * |
97 | * Estimate RTO for an NFS RPC sent via an unreliable datagram. Use |
98 | * the mean and mean deviation of RTT for the appropriate type of RPC |
99 | * for frequently issued RPCs, and a fixed default for the others. |
100 | * |
101 | * The justification for doing "other" this way is that these RPCs |
102 | * happen so infrequently that timer estimation would probably be |
103 | * stale. Also, since many of these RPCs are non-idempotent, a |
104 | * conservative timeout is desired. |
105 | * |
106 | * getattr, lookup, |
107 | * read, write, commit - A+4D |
108 | * other - timeo |
109 | */ |
110 | unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned int timer) |
111 | { |
112 | unsigned long res; |
113 | |
114 | if (timer-- == 0) |
115 | return rt->timeo; |
116 | |
117 | res = ((rt->srtt[timer] + 7) >> 3) + rt->sdrtt[timer]; |
118 | if (res > RPC_RTO_MAX) |
119 | res = RPC_RTO_MAX; |
120 | |
121 | return res; |
122 | } |
123 | EXPORT_SYMBOL_GPL(rpc_calc_rto); |
124 | |