--- old/usr/src/cmd/fs.d/nfs/mountd/mountd.c	Mon Aug  5 17:14:51 2019
+++ new/usr/src/cmd/fs.d/nfs/mountd/mountd.c	Mon Aug  5 17:14:51 2019
@@ -21,8 +21,8 @@
 
 /*
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.
  * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
- * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
@@ -63,6 +63,7 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <thread.h>
+#include <pthread.h>
 #include <assert.h>
 #include <priv_utils.h>
 #include <nfs/auth.h>
@@ -88,6 +89,7 @@
 #include <pwd.h>
 #include <grp.h>
 #include <alloca.h>
+#include <atomic.h>
 
 extern int daemonize_init(void);
 extern void daemonize_fini(int);
@@ -129,8 +131,15 @@
 
 thread_t	nfsauth_thread;
 thread_t	cmd_thread;
-thread_t	logging_thread;
 
+/*
+ * The following logging and BSM related data structs
+ * are only used when mountd_bsm_audit is TRUE; this
+ * is done by specifying the undocumented -A flag to
+ * mountd(1m).
+ */
+static bool_t	mountd_bsm_audit = FALSE;
+
 typedef struct logging_data {
 	char			*ld_host;
 	char			*ld_path;
@@ -144,6 +153,23 @@
 static logging_data *logging_head = NULL;
 static logging_data *logging_tail = NULL;
 
+#define	MOUNTD_STKSZ	(16 * 1024)	/* 16KB Stacks */
+static	uint32_t	nm_thrds = 0;
+static	uint32_t	mx_thrds = 2;	/* fallback default: see main() */
+
+static	thread_key_t	door_key;
+static	mutex_t		door_lock;
+static	int		cmd_door = -1;
+static	cond_t		cdoor_cv;
+static	int		auth_door = -1;
+static	cond_t		adoor_cv;
+
+typedef enum {
+	UNKNOWN_FUNC	= 0,
+	NFSAUTH_FUNC	= 1,
+	NFSCMD_FUNC	= 2
+} dr_cmd_t;
+
 /*
  * Our copy of some system variables obtained using sysconf(3c)
  */
@@ -150,19 +176,163 @@
 static long ngroups_max;	/* _SC_NGROUPS_MAX */
 static long pw_size;		/* _SC_GETPW_R_SIZE_MAX */
 
+static char *
+cmd2str(dr_cmd_t t)
+{
+	switch (t) {
+	case NFSAUTH_FUNC:
+		return ("NFSAUTH_FUNC");
+
+	case NFSCMD_FUNC:
+		return ("NFSCMD_FUNC");
+
+	case UNKNOWN_FUNC:
+	default:
+		return ("UNKNOWN_FUNC");
+	}
+}
+
+void *
+mntd_thr_start(void *arg)
+{
+	dr_cmd_t	*cp = (dr_cmd_t *)arg;
+	dr_cmd_t	 cmd = *cp;
+	static void	*value;
+	int		 dfd = 0;
+
+	value = (nm_thrds >= mx_thrds) ? (void *)1 : (void *)0;
+	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+	(void) thr_setspecific(door_key, value);
+
+	switch (cmd) {
+	case NFSAUTH_FUNC:
+		(void) mutex_lock(&door_lock);
+		while (auth_door == -1)
+			cond_wait(&adoor_cv, &door_lock);
+		dfd = auth_door;
+		(void) mutex_unlock(&door_lock);
+		break;
+
+	case NFSCMD_FUNC:
+		(void) mutex_lock(&door_lock);
+		while (cmd_door == -1)
+			cond_wait(&cdoor_cv, &door_lock);
+		dfd = cmd_door;
+		(void) mutex_unlock(&door_lock);
+		break;
+
+	default:
+		syslog(LOG_NOTICE, "mntd_thr_start: %s", cmd2str(cmd));
+		free(cp);
+		thr_exit(NULL);
+	}
+
+	if (door_bind(dfd) < 0) {
+		syslog(LOG_ERR, "Unable to bind door for %s: %m", cmd2str(cmd));
+		exit(20);
+	}
+#ifdef	DEBUG
+	syslog(LOG_NOTICE, "%s Door Bound Successfully", cmd2str(cmd));
+#endif
+	free(cp);
+	door_return(NULL, 0, NULL, 0);
+
+	/* NOTREACHED */
+	return (NULL);
+}
+
+/*
+ * Manages stacksize and threadpool
+ */
+static void
+mntd_thr_create(door_info_t *dp)
+{
+	thread_t	 tid;
+	int		 num = 0;
+	int		 rc = 0;
+	size_t		 stksz = MOUNTD_STKSZ;
+	long		 flags = THR_DETACHED;
+	void		*proc;
+	dr_cmd_t	*cp;
+#ifdef	DEBUG
+	char		 func[1024] = {0};
+#endif
+
+	if (dp == NULL) {
+		syslog(LOG_NOTICE, "mntd_thr_create: dp == NULL");
+		return;
+	}
+	proc = (void *)(uintptr_t)dp->di_proc;
+
+	if ((cp = (dr_cmd_t *)malloc(sizeof (dr_cmd_t))) == (dr_cmd_t *)NULL) {
+		syslog(LOG_ERR, "mntd_thr_create: %m");
+		return;
+	}
+
+#ifdef	DEBUG
+	(void) addrtosymstr(proc, func, sizeof (func));
+	syslog(LOG_NOTICE, "mntd_thr_create: func = %s", func);
+#endif
+
+	if (proc == (void *)nfsauth_func)
+		*cp = NFSAUTH_FUNC;
+	else if (proc == (void *)nfscmd_func)
+		*cp = NFSCMD_FUNC;
+	else {
+		free(cp);
+		return;
+	}
+
+	if ((num = atomic_inc_32_nv(&nm_thrds)) > mx_thrds) {
+		atomic_dec_32(&nm_thrds);
+		num -= 1;
+#ifdef	DEBUG
+		syslog(LOG_ERR,
+		    "mntd_thr_create: %d threads already active", num);
+#endif
+		free(cp);
+		return;
+	}
+
+	rc = thr_create(NULL, stksz, mntd_thr_start, (void *)cp, flags, &tid);
+	if (rc != 0) {
+		atomic_dec_32(&nm_thrds);
+		syslog(LOG_ERR, "mntd_thr_create: %m");
+		free(cp);
+		return;
+	}
+#ifdef	DEBUG
+	syslog(LOG_NOTICE,
+	    "mntd_thr_create: tid %d created (nm_thrds = %d)", tid, nm_thrds);
+#endif
+}
+
+static void
+mntd_thr_destroy(void *arg)
+{
+	atomic_dec_32(&nm_thrds);
+#ifdef	DEBUG
+	syslog(LOG_NOTICE, "mntd_thr_destroy: (nm_thrds = %d)", nm_thrds);
+#endif
+}
+
 /* ARGSUSED */
 static void *
 nfsauth_svc(void *arg)
 {
-	int	doorfd = -1;
 	uint_t	darg;
+	uint_t	flags = (DOOR_PRIVATE | DOOR_NO_CANCEL | DOOR_REFUSE_DESC);
 #ifdef DEBUG
 	int	dfd;
 #endif
 
-	if ((doorfd = door_create(nfsauth_func, NULL,
-	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
-		syslog(LOG_ERR, "Unable to create door: %m\n");
+	/* register 'nfsauth_func' as the new door service */
+	(void) mutex_lock(&door_lock);
+	auth_door = door_create(nfsauth_func, NULL, flags);
+	(void) mutex_unlock(&door_lock);
+
+	if (auth_door < 0) {
+		syslog(LOG_ERR, "nfsauth_svc: %m");
 		exit(10);
 	}
 
@@ -173,7 +343,7 @@
 	if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
 	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
 		syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
-		(void) close(doorfd);
+		(void) close(auth_door);
 		exit(11);
 	}
 
@@ -185,10 +355,10 @@
 	/*
 	 * Register in namespace to pass to the kernel to door_ki_open
 	 */
-	if (fattach(doorfd, MOUNTD_DOOR) == -1) {
+	if (fattach(auth_door, MOUNTD_DOOR) == -1) {
 		syslog(LOG_ERR, "Unable to fattach door: %m\n");
 		(void) close(dfd);
-		(void) close(doorfd);
+		(void) close(auth_door);
 		exit(12);
 	}
 	(void) close(dfd);
@@ -197,10 +367,17 @@
 	/*
 	 * Must pass the doorfd down to the kernel.
 	 */
-	darg = doorfd;
+	darg = auth_door;
 	(void) _nfssys(MOUNTD_ARGS, &darg);
 
 	/*
+	 * Signal thread that kernel has door descriptor
+	 */
+	(void) mutex_lock(&door_lock);
+	cond_signal(&adoor_cv);
+	(void) mutex_unlock(&door_lock);
+
+	/*
 	 * Wait for incoming calls
 	 */
 	/*CONSTCOND*/
@@ -217,26 +394,36 @@
  * nfs_cmd requests for character set conversion and other future
  * events.
  */
-
 static void *
 cmd_svc(void *arg)
 {
-	int	doorfd = -1;
 	uint_t	darg;
+	uint_t	flags = (DOOR_PRIVATE | DOOR_NO_CANCEL | DOOR_REFUSE_DESC);
 
-	if ((doorfd = door_create(nfscmd_func, NULL,
-	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
+	/* register 'nfscmd_func' as the new door service */
+	(void) mutex_lock(&door_lock);
+	cmd_door = door_create(nfscmd_func, NULL, flags);
+	(void) mutex_unlock(&door_lock);
+
+	if (cmd_door < 0) {
 		syslog(LOG_ERR, "Unable to create cmd door: %m\n");
 		exit(10);
 	}
 
 	/*
-	 * Must pass the doorfd down to the kernel.
+	 * Must pass the cmd_door down to the kernel.
 	 */
-	darg = doorfd;
+	darg = cmd_door;
 	(void) _nfssys(NFSCMD_ARGS, &darg);
 
 	/*
+	 * Signal thread that kernel has door descriptor
+	 */
+	(void) mutex_lock(&door_lock);
+	cond_signal(&cdoor_cv);
+	(void) mutex_unlock(&door_lock);
+
+	/*
 	 * Wait for incoming calls
 	 */
 	/*CONSTCOND*/
@@ -251,6 +438,8 @@
 static void
 free_logging_data(logging_data *lq)
 {
+	assert(mountd_bsm_audit == TRUE);
+
 	if (lq != NULL) {
 		free(lq->ld_host);
 		free(lq->ld_netid);
@@ -272,6 +461,8 @@
 {
 	logging_data    *lq;
 
+	assert(mountd_bsm_audit == TRUE);
+
 	/*
 	 * Pull it off the queue.
 	 */
@@ -296,6 +487,8 @@
 	int		cleared = 0;
 	char		*host;
 
+	assert(mountd_bsm_audit == TRUE);
+
 	while (lq) {
 		struct cln cln;
 
@@ -331,6 +524,8 @@
 {
 	logging_data	*lq;
 
+	assert(mountd_bsm_audit == TRUE);
+
 	for (;;) {
 		(void) mutex_lock(&logging_queue_lock);
 		while (logging_head == NULL) {
@@ -511,7 +706,7 @@
 		    "failed, using default value");
 	}
 
-	while ((c = getopt(argc, argv, "dvrm:p:")) != EOF) {
+	while ((c = getopt(argc, argv, "dvrm:p:A")) != EOF) {
 		switch (c) {
 		case 'd':
 			debug++;
@@ -531,6 +726,8 @@
 			}
 			max_threads = tmp;
 			break;
+		case 'A':
+			mountd_bsm_audit = TRUE;
 		case 'p':
 			if (convert_int(&tmp, optarg) != 0 || tmp < 1 ||
 			    tmp > UINT16_MAX) {
@@ -598,8 +795,10 @@
 	(void) setlocale(LC_ALL, "");
 	(void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
 	(void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
-	(void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
-	(void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
+	if (mountd_bsm_audit) {
+		(void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
+		(void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
+	}
 
 	netgroup_init();
 
@@ -641,7 +840,8 @@
 		exit(0);
 	}
 
-	audit_mountd_setup();	/* BSM */
+	if (mountd_bsm_audit)
+		audit_mountd_setup();	/* BSM */
 
 	/*
 	 * Get required system variables
@@ -701,9 +901,13 @@
 	 * If max_threads was specified, then set the
 	 * maximum number of threads to the value specified.
 	 */
-	if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
-		fprintf(stderr, "unable to set max_threads\n");
-		exit(1);
+	if (max_threads > 0) {
+		if (!rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
+			fprintf(stderr, "unable to set max_threads\n");
+			exit(1);
+		}
+		/* Default to one fourth of all threads */
+		mx_thrds = (uint32_t)(max_threads / 4);
 	}
 
 	if (mountd_port < 0 || mountd_port > UINT16_MAX) {
@@ -719,6 +923,18 @@
 	svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
 	svc_unreg(MOUNTPROG, MOUNTVERS3);
 
+	(void) mutex_init(&door_lock, USYNC_THREAD, NULL);
+	(void) cond_init(&adoor_cv, USYNC_THREAD, NULL);
+	(void) cond_init(&cdoor_cv, USYNC_THREAD, NULL);
+
+	/* server function to create/optimize door threads */
+	(void) door_server_create(mntd_thr_create);
+	if (thr_keycreate(&door_key, mntd_thr_destroy) != 0) {
+		fprintf(stderr, "thr_keycreate (server thread): %s\n",
+		    strerror(errno));
+		exit(3);
+	}
+
 	/*
 	 * Create the nfsauth thread with same signal disposition
 	 * as the main thread. We need to create a separate thread
@@ -749,9 +965,12 @@
 	 * a separate thread to allow the mount request threads to
 	 * clear as soon as possible.
 	 */
-	if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
-		syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
-		exit(2);
+	if (mountd_bsm_audit) {
+		if (thr_create(NULL, 0, logging_svc, 0, thr_flags, NULL)) {
+			syslog(LOG_ERR,
+			    gettext("Failed to create LOGGING svc thread"));
+			exit(2);
+		}
 	}
 
 	/*
@@ -852,8 +1071,6 @@
 	saverrno = errno;	/* save error code */
 
 	host = cln_gethost(cln);
-	if (host == NULL)
-		return;
 
 	errno = saverrno;
 	if (errno == 0)
@@ -1078,6 +1295,8 @@
 	logging_data	*lq;
 	struct netbuf	*nb;
 
+	assert(mountd_bsm_audit == TRUE);
+
 	lq = (logging_data *)calloc(1, sizeof (logging_data));
 	if (lq == NULL)
 		goto cleanup;
@@ -1155,7 +1374,6 @@
 
 
 #define	CLN_CLNAMES	(1 << 0)
-#define	CLN_HOST	(1 << 1)
 
 static void
 cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid,
@@ -1170,11 +1388,30 @@
 		cln->nbuf = nbuf;
 	}
 
-	cln->nconf = NULL;
 	cln->clnames = NULL;
-	cln->host = NULL;
-
 	cln->flags = 0;
+
+	bzero(cln->host, sizeof (cln->host));
+
+	if (cln->netid != NULL && cln->nbuf != NULL &&
+	    (cln->nconf = getnetconfigent(cln->netid)) != NULL) {
+		if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
+			struct sockaddr_in *sa;
+			/* LINTED pointer alignment */
+			sa = (struct sockaddr_in *)(cln->nbuf->buf);
+			(void) inet_ntop(AF_INET, &sa->sin_addr.s_addr,
+			    cln->host, sizeof (cln->host));
+		} else if (strcmp(cln->nconf->nc_protofmly, NC_INET6) == 0) {
+			struct sockaddr_in6 *sa;
+			/* LINTED pointer alignment */
+			sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
+			(void) inet_ntop(AF_INET6, &sa->sin6_addr.s6_addr,
+			    cln->host, sizeof (cln->host));
+		}
+	}
+
+	if (strlen(cln->host) == 0)
+		(void) strlcpy(cln->host, "(unknown)", sizeof (cln->host));
 }
 
 void
@@ -1197,8 +1434,6 @@
 
 	if (cln->clnames != NULL)
 		netdir_free(cln->clnames, ND_HOSTSERVLIST);
-
-	free(cln->host);
 }
 
 struct netbuf *
@@ -1211,22 +1446,10 @@
 cln_getclientsnames(struct cln *cln)
 {
 	if ((cln->flags & CLN_CLNAMES) == 0) {
-		/*
-		 * nconf is not needed if we do not have nbuf (see
-		 * cln_gethost() too), so we check for nbuf and in a case it is
-		 * NULL we do not try to get nconf.
-		 */
-		if (cln->netid != NULL && cln->nbuf != NULL) {
-			cln->nconf = getnetconfigent(cln->netid);
-			if (cln->nconf == NULL)
-				syslog(LOG_ERR, "%s: getnetconfigent failed",
-				    cln->netid);
-		}
-
-		if (cln->nconf != NULL && cln->nbuf != NULL)
+		if (cln->nconf != NULL && cln->nbuf != NULL) {
 			(void) __netdir_getbyaddr_nosrv(cln->nconf,
 			    &cln->clnames, cln->nbuf);
-
+		}
 		cln->flags |= CLN_CLNAMES;
 	}
 
@@ -1233,15 +1456,6 @@
 	return (cln->clnames);
 }
 
-/*
- * Return B_TRUE if the host is already available at no cost
- */
-boolean_t
-cln_havehost(struct cln *cln)
-{
-	return ((cln->flags & (CLN_CLNAMES | CLN_HOST)) != 0);
-}
-
 char *
 cln_gethost(struct cln *cln)
 {
@@ -1248,42 +1462,6 @@
 	if (cln_getclientsnames(cln) != NULL)
 		return (cln->clnames->h_hostservs[0].h_host);
 
-	if ((cln->flags & CLN_HOST) == 0) {
-		if (cln->nconf == NULL || cln->nbuf == NULL) {
-			cln->host = strdup("(anon)");
-		} else {
-			char host[MAXIPADDRLEN];
-
-			if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
-				struct sockaddr_in *sa;
-
-				/* LINTED pointer alignment */
-				sa = (struct sockaddr_in *)(cln->nbuf->buf);
-				(void) inet_ntoa_r(sa->sin_addr, host);
-
-				cln->host = strdup(host);
-			} else if (strcmp(cln->nconf->nc_protofmly,
-			    NC_INET6) == 0) {
-				struct sockaddr_in6 *sa;
-
-				/* LINTED pointer alignment */
-				sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
-				(void) inet_ntop(AF_INET6,
-				    sa->sin6_addr.s6_addr,
-				    host, INET6_ADDRSTRLEN);
-
-				cln->host = strdup(host);
-			} else {
-				syslog(LOG_ERR, gettext("Client's address is "
-				    "neither IPv4 nor IPv6"));
-
-				cln->host = strdup("(anon)");
-			}
-		}
-
-		cln->flags |= CLN_HOST;
-	}
-
 	return (cln->host);
 }
 
@@ -1330,16 +1508,7 @@
 	 */
 	if (verbose) {
 		DTRACE_PROBE(mountd, name_by_verbose);
-		if ((host = cln_gethost(&cln)) == NULL) {
-			/*
-			 * We failed to get a name for the client, even
-			 * 'anon', probably because we ran out of memory.
-			 * In this situation it doesn't make sense to
-			 * allow the mount to succeed.
-			 */
-			error = EACCES;
-			goto reply;
-		}
+		host = cln_gethost(&cln);
 	}
 
 	/*
@@ -1545,30 +1714,30 @@
 		break;
 	}
 
-	if (cln_havehost(&cln))
+	if (host == NULL)
 		host = cln_gethost(&cln);
 
 	if (verbose)
-		syslog(LOG_NOTICE, "MOUNT: %s %s %s",
-		    (host == NULL) ? "unknown host" : host,
+		syslog(LOG_NOTICE, "MOUNT: %s %s %s", host,
 		    error ? "denied" : "mounted", path);
 
-	/*
-	 * If we can not create a queue entry, go ahead and do it
-	 * in the context of this thread.
-	 */
-	enqueued = enqueue_logging_data(host, transp, path, rpath,
-	    audit_status, error);
-	if (enqueued == FALSE) {
-		if (host == NULL) {
-			DTRACE_PROBE(mountd, name_by_in_thread);
-			host = cln_gethost(&cln);
+	if (mountd_bsm_audit) {
+		/*
+		 * If we can not create a queue entry, go ahead and do it
+		 * in the context of this thread.
+		 */
+		enqueued = enqueue_logging_data(host, transp, path, rpath,
+		    audit_status, error);
+
+		if (enqueued == FALSE) {
+			DTRACE_PROBE(mountd, logged_in_thread);
+			audit_mountd_mount(host, path, audit_status); /* BSM */
 		}
+	}
 
-		DTRACE_PROBE(mountd, logged_in_thread);
-		audit_mountd_mount(host, path, audit_status); /* BSM */
-		if (!error)
-			mntlist_new(host, rpath); /* add entry to mount list */
+	if (enqueued == FALSE && !error) {
+		/* Add entry to mount list */
+		mntlist_new(host, rpath);
 	}
 
 	if (path != NULL)
@@ -1975,6 +2144,13 @@
 		}
 
 		/*
+		 * Before doing clients names lookup, check if it's individual
+		 * IP address specified without @ prefix.
+		 */
+		if (strcmp(gr, cln->host) == 0)
+			return (response);
+
+		/*
 		 * No other checks can be performed if client address
 		 * can't be resolved.
 		 */
@@ -3225,19 +3401,12 @@
 		log_cant_reply_cln(&cln);
 
 	host = cln_gethost(&cln);
-	if (host == NULL) {
-		/*
-		 * Without the hostname we can't do audit or delete
-		 * this host from the mount entries.
-		 */
-		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
-		return;
-	}
 
 	if (verbose)
 		syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
 
-	audit_mountd_umount(host, path);
+	if (mountd_bsm_audit)
+		audit_mountd_umount(host, path);
 
 	remove_path = rpath;	/* assume we will use the cannonical path */
 	if (realpath(path, rpath) == NULL) {
@@ -3279,10 +3448,6 @@
 	cln_init(&cln, transp);
 
 	host = cln_gethost(&cln);
-	if (host == NULL) {
-		/* Can't do anything without the name of the client */
-		return;
-	}
 
 	/*
 	 * Remove all hosts entries from mount list
