From b72d3fc34ad0d7fa79edb89f8b8cbe5e30ffc80c Mon Sep 17 00:00:00 2001
From: NeilBrown <neil@brown.name>
Date: Fri, 19 Feb 2021 12:09:05 +1100
Subject: [PATCH] mountd: make default ttl settable by option

The DEFAULT_TTL affects the rate at which authentication messages are
logged.  So it is useful to make it settable.

Add "-ttl" and "-T", and add clear statement in the documentation of
both the benefits and the possible negative effects of choosing a larger
value

Signed-off-by: NeilBrown <neil@brown.name>
---
 support/include/exportfs.h |    3 ++-
 support/nfs/exports.c      |    4 +++-
 utils/mountd/cache.c       |    6 +++---
 utils/mountd/mountd.c      |   14 +++++++++++++-
 utils/mountd/mountd.man    |   18 +++++++++++++++---
 utils/mountd/v4root.c      |    3 ++-
 6 files changed, 38 insertions(+), 10 deletions(-)

--- a/support/include/exportfs.h
+++ b/support/include/exportfs.h
@@ -104,7 +104,8 @@ typedef struct mexport {
 } nfs_export;
 
 #define HASH_TABLE_SIZE 1021
-#define DEFAULT_TTL	(30 * 60)
+
+extern int default_ttl;
 
 typedef struct _exp_hash_entry {
 	nfs_export * p_first;
--- a/support/nfs/exports.c
+++ b/support/nfs/exports.c
@@ -47,6 +47,8 @@ struct flav_info flav_map[] = {
 
 const int flav_map_size = sizeof(flav_map)/sizeof(flav_map[0]);
 
+int default_ttl = 30 * 60;
+
 static char	*efname = NULL;
 static XFILE	*efp = NULL;
 static int	first;
@@ -100,7 +102,7 @@ static void init_exportent (struct expor
 	ee->e_nsquids = 0;
 	ee->e_nsqgids = 0;
 	ee->e_uuid = NULL;
-	ee->e_ttl = DEFAULT_TTL;
+	ee->e_ttl = default_ttl;
 }
 
 struct exportent *
--- a/utils/mountd/cache.c
+++ b/utils/mountd/cache.c
@@ -120,7 +120,7 @@ static void auth_unix_ip(FILE *f)
 
 	qword_print(f, "nfsd");
 	qword_print(f, ipaddr);
-	qword_printtimefrom(f, DEFAULT_TTL);
+	qword_printtimefrom(f, default_ttl);
 	if (use_ipaddr && client) {
 		memmove(ipaddr + 1, ipaddr, strlen(ipaddr) + 1);
 		ipaddr[0] = '$';
@@ -186,7 +186,7 @@ static void auth_unix_gid(FILE *f)
 		}
 	}
 	qword_printuint(f, uid);
-	qword_printtimefrom(f, DEFAULT_TTL);
+	qword_printtimefrom(f, default_ttl);
 	if (rv >= 0) {
 		qword_printuint(f, ngroups);
 		for (i=0; i<ngroups; i++)
@@ -818,7 +818,7 @@ static int dump_to_cache(FILE *f, char *
 		xlog(D_AUTH, "granted access to %s for %s",
 		     path, *domain == '$' ? domain+1 : domain);
 	} else {
-		qword_printtimefrom(f, DEFAULT_TTL);
+		qword_printtimefrom(f, default_ttl);
 		xlog(D_AUTH, "denied access to %s for %s",
 		     path, *domain == '$' ? domain+1 : domain);
 	}
--- a/utils/mountd/mountd.c
+++ b/utils/mountd/mountd.c
@@ -71,9 +71,10 @@ static struct option longopts[] =
 	{ "no-udp", 0, 0, 'u' },
 	{ "log-auth", 0, 0, 'l'},
 	{ "cache-use-ipaddr", 0, 0, 'i'},
+	{ "ttl", 1, 0, 'T'},
 	{ NULL, 0, 0, 0 }
 };
-static char shortopts[] = "o:nFd:f:p:P:hH:N:V:vurs:t:gli";
+static char shortopts[] = "o:nFd:f:p:P:hH:N:V:vurs:t:gliT:";
 
 #define NFSVERSBIT(vers)	(0x1 << (vers - 1))
 #define NFSVERSBIT_ALL		(NFSVERSBIT(2) | NFSVERSBIT(3) | NFSVERSBIT(4))
@@ -701,6 +702,7 @@ main(int argc, char **argv)
 	int	descriptors = 0;
 	int	c;
 	int	vers;
+	int	ttl;
 	struct sigaction sa;
 	struct rlimit rlim;
 
@@ -795,6 +797,15 @@ main(int argc, char **argv)
 		case 'i':
 			use_ipaddr = 2;
 			break;
+		case 'T':
+			ttl = atoi(optarg);
+			if (ttl <= 0) {
+				fprintf(stderr, "%s: bad ttl number of seconds: %s\n",
+					argv[0], optarg);
+				usage(argv[0], 1);
+			}
+			default_ttl = ttl;
+			break;
 		case 0:
 			break;
 		case '?':
@@ -917,6 +928,7 @@ usage(const char *prog, int n)
 {
 	fprintf(stderr,
 "Usage: %s [-F|--foreground] [-h|--help] [-v|--version] [-d kind|--debug kind]\n"
+"	[-l|--log-auth] [-i|--cache-use-ipaddr] [-T|--ttl ttl]\n"
 "	[-o num|--descriptors num] [-f exports-file|--exports-file=file]\n"
 "	[-p|--port port] [-V version|--nfs-version version]\n"
 "	[-N version|--no-nfs-version version] [-n|--no-tcp]\n"
--- a/utils/mountd/mountd.man
+++ b/utils/mountd/mountd.man
@@ -99,9 +99,10 @@ Turn on debugging. Valid kinds are: all,
 .TP
 .BR \-l " or " \-\-log\-auth
 Enable logging of responses to authentication and access requests from
-nfsd.  Each response is then cached by the kernel for 30 minutes, and
-will be refreshed after 15 minutes if the relevant client remains
-active.
+nfsd.  Each response is then cached by the kernel for 30 minutes (or as set by
+.B \-\-ttl
+below), and will be refreshed after 15 minutes (half the ttl time) if
+the relevant client remains active.
 Note that
 .B -l
 is equivalent to
@@ -135,6 +136,17 @@ log messages produced by the
 .B -l
 option easier to read.
 .TP
+.B \-T " or " \-\-ttl
+Provide a time-to-live (TTL) for cached information given to the kernel.
+The kernel will normally request an update if the information is needed
+after half of this time has expired.  Increasing the provided number,
+which is in seconds, reduces the rate of cache update requests, and this
+is particularly noticeable when these requests are logged with
+.BR \-l .
+However increasing also means that changes to hostname to address
+mappings can take longer to be noticed.
+The default TTL is 1800 (30 minutes).
+.TP
 .B \-F " or " \-\-foreground
 Run in foreground (do not daemonize)
 .TP
--- a/utils/mountd/v4root.c
+++ b/utils/mountd/v4root.c
@@ -46,7 +46,7 @@ static nfs_export pseudo_root = {
 		.e_nsqgids = 0,
 		.e_fsid = 0,
 		.e_mountpoint = NULL,
-		.e_ttl = DEFAULT_TTL,
+		.e_ttl = 0,
 	},
 	.m_exported = 0,
 	.m_xtabent = 1,
@@ -87,6 +87,7 @@ v4root_create(char *path, nfs_export *ex
 	struct exportent *curexp = &export->m_export;
 
 	dupexportent(&eep, &pseudo_root.m_export);
+	eep.e_ttl = default_ttl;
 	eep.e_hostname = curexp->e_hostname;
 	strncpy(eep.e_path, path, sizeof(eep.e_path));
 	if (strcmp(path, "/") != 0)
