Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/net/sunrpc/timer.c
0004  *
0005  * Estimate RPC request round trip time.
0006  *
0007  * Based on packet round-trip and variance estimator algorithms described
0008  * in appendix A of "Congestion Avoidance and Control" by Van Jacobson
0009  * and Michael J. Karels (ACM Computer Communication Review; Proceedings
0010  * of the Sigcomm '88 Symposium in Stanford, CA, August, 1988).
0011  *
0012  * This RTT estimator is used only for RPC over datagram protocols.
0013  *
0014  * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
0015  */
0016 
0017 #include <asm/param.h>
0018 
0019 #include <linux/types.h>
0020 #include <linux/unistd.h>
0021 #include <linux/module.h>
0022 
0023 #include <linux/sunrpc/clnt.h>
0024 
0025 #define RPC_RTO_MAX (60*HZ)
0026 #define RPC_RTO_INIT (HZ/5)
0027 #define RPC_RTO_MIN (HZ/10)
0028 
0029 /**
0030  * rpc_init_rtt - Initialize an RPC RTT estimator context
0031  * @rt: context to initialize
0032  * @timeo: initial timeout value, in jiffies
0033  *
0034  */
0035 void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
0036 {
0037     unsigned long init = 0;
0038     unsigned int i;
0039 
0040     rt->timeo = timeo;
0041 
0042     if (timeo > RPC_RTO_INIT)
0043         init = (timeo - RPC_RTO_INIT) << 3;
0044     for (i = 0; i < 5; i++) {
0045         rt->srtt[i] = init;
0046         rt->sdrtt[i] = RPC_RTO_INIT;
0047         rt->ntimeouts[i] = 0;
0048     }
0049 }
0050 EXPORT_SYMBOL_GPL(rpc_init_rtt);
0051 
0052 /**
0053  * rpc_update_rtt - Update an RPC RTT estimator context
0054  * @rt: context to update
0055  * @timer: timer array index (request type)
0056  * @m: recent actual RTT, in jiffies
0057  *
0058  * NB: When computing the smoothed RTT and standard deviation,
0059  *     be careful not to produce negative intermediate results.
0060  */
0061 void rpc_update_rtt(struct rpc_rtt *rt, unsigned int timer, long m)
0062 {
0063     long *srtt, *sdrtt;
0064 
0065     if (timer-- == 0)
0066         return;
0067 
0068     /* jiffies wrapped; ignore this one */
0069     if (m < 0)
0070         return;
0071 
0072     if (m == 0)
0073         m = 1L;
0074 
0075     srtt = (long *)&rt->srtt[timer];
0076     m -= *srtt >> 3;
0077     *srtt += m;
0078 
0079     if (m < 0)
0080         m = -m;
0081 
0082     sdrtt = (long *)&rt->sdrtt[timer];
0083     m -= *sdrtt >> 2;
0084     *sdrtt += m;
0085 
0086     /* Set lower bound on the variance */
0087     if (*sdrtt < RPC_RTO_MIN)
0088         *sdrtt = RPC_RTO_MIN;
0089 }
0090 EXPORT_SYMBOL_GPL(rpc_update_rtt);
0091 
0092 /**
0093  * rpc_calc_rto - Provide an estimated timeout value
0094  * @rt: context to use for calculation
0095  * @timer: timer array index (request type)
0096  *
0097  * Estimate RTO for an NFS RPC sent via an unreliable datagram.  Use
0098  * the mean and mean deviation of RTT for the appropriate type of RPC
0099  * for frequently issued RPCs, and a fixed default for the others.
0100  *
0101  * The justification for doing "other" this way is that these RPCs
0102  * happen so infrequently that timer estimation would probably be
0103  * stale.  Also, since many of these RPCs are non-idempotent, a
0104  * conservative timeout is desired.
0105  *
0106  * getattr, lookup,
0107  * read, write, commit     - A+4D
0108  * other                   - timeo
0109  */
0110 unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned int timer)
0111 {
0112     unsigned long res;
0113 
0114     if (timer-- == 0)
0115         return rt->timeo;
0116 
0117     res = ((rt->srtt[timer] + 7) >> 3) + rt->sdrtt[timer];
0118     if (res > RPC_RTO_MAX)
0119         res = RPC_RTO_MAX;
0120 
0121     return res;
0122 }
0123 EXPORT_SYMBOL_GPL(rpc_calc_rto);