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