timer.c 2.89 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * linux/net/sunrpc/timer.c
 *
 * Estimate RPC request round trip time.
 *
 * Based on packet round-trip and variance estimator algorithms described
 * in appendix A of "Congestion Avoidance and Control" by Van Jacobson
 * and Michael J. Karels (ACM Computer Communication Review; Proceedings
 * of the Sigcomm '88 Symposium in Stanford, CA, August, 1988).
 *
 * This RTT estimator is used only for RPC over datagram protocols.
 *
 * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
 */

#include <asm/param.h>

#include <linux/types.h>
#include <linux/unistd.h>
20
#include <linux/module.h>
Linus Torvalds's avatar
Linus Torvalds committed
21 22 23 24 25 26 27

#include <linux/sunrpc/clnt.h>

#define RPC_RTO_MAX (60*HZ)
#define RPC_RTO_INIT (HZ/5)
#define RPC_RTO_MIN (HZ/10)

28 29 30 31 32 33 34
/**
 * rpc_init_rtt - Initialize an RPC RTT estimator context
 * @rt: context to initialize
 * @timeo: initial timeout value, in jiffies
 *
 */
void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
Linus Torvalds's avatar
Linus Torvalds committed
35 36
{
	unsigned long init = 0;
37
	unsigned int i;
Linus Torvalds's avatar
Linus Torvalds committed
38 39 40 41 42 43 44 45 46 47 48

	rt->timeo = timeo;

	if (timeo > RPC_RTO_INIT)
		init = (timeo - RPC_RTO_INIT) << 3;
	for (i = 0; i < 5; i++) {
		rt->srtt[i] = init;
		rt->sdrtt[i] = RPC_RTO_INIT;
		rt->ntimeouts[i] = 0;
	}
}
49
EXPORT_SYMBOL_GPL(rpc_init_rtt);
Linus Torvalds's avatar
Linus Torvalds committed
50

51 52 53 54 55 56
/**
 * rpc_update_rtt - Update an RPC RTT estimator context
 * @rt: context to update
 * @timer: timer array index (request type)
 * @m: recent actual RTT, in jiffies
 *
Linus Torvalds's avatar
Linus Torvalds committed
57 58 59
 * NB: When computing the smoothed RTT and standard deviation,
 *     be careful not to produce negative intermediate results.
 */
60
void rpc_update_rtt(struct rpc_rtt *rt, unsigned int timer, long m)
Linus Torvalds's avatar
Linus Torvalds committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
{
	long *srtt, *sdrtt;

	if (timer-- == 0)
		return;

	/* jiffies wrapped; ignore this one */
	if (m < 0)
		return;

	if (m == 0)
		m = 1L;

	srtt = (long *)&rt->srtt[timer];
	m -= *srtt >> 3;
	*srtt += m;

	if (m < 0)
		m = -m;

	sdrtt = (long *)&rt->sdrtt[timer];
	m -= *sdrtt >> 2;
	*sdrtt += m;

	/* Set lower bound on the variance */
	if (*sdrtt < RPC_RTO_MIN)
		*sdrtt = RPC_RTO_MIN;
}
89
EXPORT_SYMBOL_GPL(rpc_update_rtt);
Linus Torvalds's avatar
Linus Torvalds committed
90

91 92 93 94 95 96 97 98 99 100 101 102 103 104
/**
 * rpc_calc_rto - Provide an estimated timeout value
 * @rt: context to use for calculation
 * @timer: timer array index (request type)
 *
 * Estimate RTO for an NFS RPC sent via an unreliable datagram.  Use
 * the mean and mean deviation of RTT for the appropriate type of RPC
 * for frequently issued RPCs, and a fixed default for the others.
 *
 * The justification for doing "other" this way is that these RPCs
 * happen so infrequently that timer estimation would probably be
 * stale.  Also, since many of these RPCs are non-idempotent, a
 * conservative timeout is desired.
 *
Linus Torvalds's avatar
Linus Torvalds committed
105 106 107 108
 * getattr, lookup,
 * read, write, commit     - A+4D
 * other                   - timeo
 */
109
unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned int timer)
Linus Torvalds's avatar
Linus Torvalds committed
110 111 112 113 114 115 116 117 118 119 120 121
{
	unsigned long res;

	if (timer-- == 0)
		return rt->timeo;

	res = ((rt->srtt[timer] + 7) >> 3) + rt->sdrtt[timer];
	if (res > RPC_RTO_MAX)
		res = RPC_RTO_MAX;

	return res;
}
122
EXPORT_SYMBOL_GPL(rpc_calc_rto);