changeset 3930:59477feabc54

6368753 Need a patch solution to 4522909 automountd hangs with executeable maps 6509943 Apparent deadlock between fork()'s use of lwp_suspend and NFS locking (Backout 4522909)
author nr123932
date Fri, 30 Mar 2007 01:55:41 -0700
parents ef76fe400493
children 0347144fd43b
files usr/src/cmd/fs.d/autofs/Makefile usr/src/cmd/fs.d/autofs/autod_main.c usr/src/cmd/fs.d/autofs/autod_mount.c usr/src/cmd/fs.d/autofs/automount.h usr/src/cmd/fs.d/autofs/ns_files.c usr/src/uts/common/os/condvar.c usr/src/uts/common/os/sig.c usr/src/uts/common/sys/klwp.h usr/src/uts/common/vm/vm_as.c usr/src/uts/intel/fs/proc/prmachdep.c usr/src/uts/sparc/fs/proc/prmachdep.c
diffstat 11 files changed, 310 insertions(+), 135 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/fs.d/autofs/Makefile	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/cmd/fs.d/autofs/Makefile	Fri Mar 30 01:55:41 2007 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -85,9 +85,9 @@
 GREP= egrep
 SED= sed
 
-$(AUTO) := 	LDLIBS += -lnsl -lsldap
+$(AUTO) := 	LDLIBS += -lnsl -lsldap  -ldoor
 $(MOUNT):=	LDLIBS += -lnsl
-$(TYPEPROG) :=	LDLIBS += -lrpcsvc -lsocket -lnsl -lsldap -lkstat
+$(TYPEPROG) :=	LDLIBS += -lrpcsvc -lsocket -lnsl -lsldap -lkstat -ldoor
 $(TYPEPROG) :=	LDFLAGS += -R/usr/lib/fs/$(FSTYPE)
 
 CFLAGS +=	$(CCVERBOSE) -D_FILE_OFFSET_BITS=64
--- a/usr/src/cmd/fs.d/autofs/autod_main.c	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/cmd/fs.d/autofs/autod_main.c	Fri Mar 30 01:55:41 2007 -0700
@@ -60,6 +60,7 @@
 #include <sys/thread.h>
 #include <nfs/rnode.h>
 #include <nfs/nfs.h>
+#include <wait.h>
 
 static void autofs_doorfunc(void *, char *, size_t, door_desc_t *, uint_t);
 static void autofs_setdoor(int);
@@ -77,6 +78,7 @@
 static void warn_hup(int);
 static void free_action_list();
 static int start_autofs_svcs();
+static void automountd_wait_for_cleanup(pid_t);
 
 
 /*
@@ -188,6 +190,50 @@
 	openlog("automountd", LOG_PID, LOG_DAEMON);
 	(void) setlocale(LC_ALL, "");
 
+	/*
+	 * Create the door_servers to manage fork/exec requests for
+	 * mounts and executable automount maps
+	 */
+	if ((did_fork_exec = door_create(automountd_do_fork_exec,
+	    NULL, NULL)) == -1) {
+		syslog(LOG_ERR, "door_create failed: %m, Exiting.");
+		exit(errno);
+	}
+	if ((did_exec_map = door_create(automountd_do_exec_map,
+	    NULL, NULL)) == -1) {
+		syslog(LOG_ERR, "door_create failed: %m, Exiting.");
+		if (door_revoke(did_fork_exec) == -1) {
+			syslog(LOG_ERR, "failed to door_revoke(%d) %m",
+			    did_fork_exec);
+		}
+		exit(errno);
+	}
+	/*
+	 * Before we become multithreaded we fork allowing the parent
+	 * to become a door server to handle all mount and unmount
+	 * requests. This works around a potential hang in using
+	 * fork1() within a multithreaded environment
+	 */
+
+	pid = fork1();
+	if (pid < 0) {
+		syslog(LOG_ERR,
+			"can't fork the automountd mount process %m");
+		if (door_revoke(did_fork_exec) == -1) {
+			syslog(LOG_ERR, "failed to door_revoke(%d) %m",
+				did_fork_exec);
+		}
+		if (door_revoke(did_exec_map) == -1) {
+			syslog(LOG_ERR, "failed to door_revoke(%d) %m",
+				did_exec_map);
+		}
+		exit(1);
+	} else if (pid > 0) {
+		/* this is the door server process */
+		automountd_wait_for_cleanup(pid);
+	}
+
+
 	(void) rwlock_init(&cache_lock, USYNC_THREAD, NULL);
 	(void) rwlock_init(&autofs_rddir_cache_lock, USYNC_THREAD, NULL);
 
@@ -220,8 +266,7 @@
 	case 0:
 		break;
 	case -1:
-		syslog(LOG_ERR, "error locking for %s: %s", AUTOMOUNTD,
-		    strerror(errno));
+		syslog(LOG_ERR, "error locking for %s: %m", AUTOMOUNTD);
 		exit(2);
 	default:
 		/* daemon was already running */
@@ -990,3 +1035,31 @@
 	(*results)->res_status = 0;
 	return (TRUE);
 }
+
+static void
+automountd_wait_for_cleanup(pid_t pid)
+{
+	int status;
+	int child_exitval;
+
+	/*
+	 * Wait for the main automountd process to exit so we cleanup
+	 */
+	(void) waitpid(pid, &status, 0);
+
+	child_exitval = WEXITSTATUS(status);
+
+	/*
+	 * Shutdown the door server for mounting and unmounting
+	 * filesystems
+	 */
+	if (door_revoke(did_fork_exec) == -1) {
+		syslog(LOG_ERR, "failed to door_revoke(%d) %m",
+			did_fork_exec);
+	}
+	if (door_revoke(did_exec_map) == -1) {
+		syslog(LOG_ERR, "failed to door_revoke(%d) %m",
+			did_exec_map);
+	}
+	exit(child_exitval);
+}
--- a/usr/src/cmd/fs.d/autofs/autod_mount.c	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/cmd/fs.d/autofs/autod_mount.c	Fri Mar 30 01:55:41 2007 -0700
@@ -52,12 +52,13 @@
 #include <limits.h>
 #include <assert.h>
 #include <fcntl.h>
+#include <strings.h>
 
 #include "automount.h"
 #include "replica.h"
 
 static int unmount_mntpnt(struct mnttab *);
-static int fork_exec(char *, char *, char **, int);
+static int call_fork_exec(char *, char *, char **, int);
 static void remove_browse_options(char *);
 static int inherit_options(char *, char **);
 
@@ -373,7 +374,7 @@
 	newargv[i++] = special;
 	newargv[i++] = mntpnt;
 	newargv[i] = NULL;
-	res = fork_exec(fstype, "mount", newargv, verbose);
+	res = call_fork_exec(fstype, "mount", newargv, verbose);
 	if (res == 0 && trace > 1) {
 		if (stat(mntpnt, &stbuf) == 0) {
 			trace_prt(1, "  mount of %s dev=%x rdev=%x OK\n",
@@ -385,57 +386,58 @@
 	return (res);
 }
 
-static int
-fork_exec(fstype, cmd, newargv, console)
-	char *fstype;
-	char *cmd;
-	char **newargv;
-	int console;
+void
+automountd_do_fork_exec(void *cookie, char *argp, size_t arg_size,
+		door_desc_t *dfd, uint_t n_desc)
 {
-	char path[MAXPATHLEN];
-	int i;
 	int stat_loc;
 	int fd = 0;
 	struct stat stbuf;
 	int res;
 	int child_pid;
+	command_t *command;
+	char *newargv[ARGV_MAX];
+	int i;
 
-	/* build the full path name of the fstype dependent command */
-	(void) sprintf(path, "%s/%s/%s", VFS_PATH, fstype, cmd);
 
-	if (stat(path, &stbuf) != 0) {
-		res = errno;
-		return (res);
+	command = (command_t *)argp;
+	if (sizeof (*command) != arg_size) {
+		res = EINVAL;
+		door_return((char *)&res, sizeof (res), NULL, 0);
 	}
 
-	if (trace > 1) {
-		trace_prt(1, "  fork_exec: %s ", path);
-		for (i = 2; newargv[i]; i++)
-			trace_prt(0, "%s ", newargv[i]);
-		trace_prt(0, "\n");
-	}
-
-
-	newargv[1] = cmd;
 	switch ((child_pid = fork1())) {
 	case -1:
 		syslog(LOG_ERR, "Cannot fork: %m");
-		return (errno);
+		res = errno;
+		break;
 	case 0:
 		/*
 		 * Child
 		 */
 		(void) setsid();
-		fd = open(console ? "/dev/console" : "/dev/null", O_WRONLY);
+		fd = open(command->console ? "/dev/console" : "/dev/null",
+			    O_WRONLY);
 		if (fd != -1) {
 			(void) dup2(fd, 1);
 			(void) dup2(fd, 2);
 			(void) close(fd);
 		}
 
-		(void) execv(path, &newargv[1]);
+		for (i = 0; *command->argv[i]; i++) {
+			newargv[i] = strdup(command->argv[i]);
+			if (newargv[i] == (char *)NULL) {
+				syslog(LOG_ERR, "failed to copy argument '%s'"
+				    " of %s: %m", command->argv[i],
+				    command->file);
+				_exit(errno);
+			}
+		}
+		newargv[i] = NULL;
+
+		(void) execv(command->file, newargv);
 		if (errno == EACCES)
-			syslog(LOG_ERR, "exec %s: %m", path);
+			syslog(LOG_ERR, "exec %s: %m", command->file);
 
 		_exit(errno);
 	default:
@@ -451,22 +453,25 @@
 				    WEXITSTATUS(stat_loc));
 			}
 
-			return (WEXITSTATUS(stat_loc));
-		} else
-		if (WIFSIGNALED(stat_loc)) {
-			if (trace > 1) {
+			res = WEXITSTATUS(stat_loc);
+		} else if (WIFSIGNALED(stat_loc)) {
+			if (trace > 1)
 				trace_prt(1,
 				    "  fork_exec: returns signal status %d\n",
 				    WTERMSIG(stat_loc));
-			}
+			res = 1;
 		} else {
 			if (trace > 1)
 				trace_prt(1,
 				    "  fork_exec: returns unknown status\n");
+			res = 1;
 		}
 
-		return (1);
 	}
+	door_return((char *)&res, sizeof (res), NULL, 0);
+	trace_prt(1, "automountd_do_fork_exec, door return failed %s, %s\n",
+	    command->file, strerror(errno));
+	door_return(NULL, 0, NULL, 0);
 }
 
 int
@@ -551,7 +556,7 @@
 		newargv[2] = mountp;
 		newargv[3] = NULL;
 
-		res = fork_exec(fstype, "umount", newargv, verbose);
+		res = call_fork_exec(fstype, "umount", newargv, verbose);
 		if (res == ENOENT) {
 			/*
 			 * filesystem specific unmount command not found
@@ -646,3 +651,57 @@
 
 	return (hasmntopt(&mt, MNTOPT_RESTRICT) != NULL);
 }
+
+static int
+call_fork_exec(fstype, cmd, newargv, console)
+	char *fstype;
+	char *cmd;
+	char **newargv;
+	int console;
+{
+	command_t command;
+	door_arg_t darg;
+	char path[MAXPATHLEN];
+	struct stat stbuf;
+	int ret;
+	int sz;
+	int status;
+	int i;
+
+	bzero(&command, sizeof (command));
+	/* build the full path name of the fstype dependent command */
+	(void) snprintf(path, MAXPATHLEN, "%s/%s/%s", VFS_PATH, fstype, cmd);
+
+	if (stat(path, &stbuf) != 0) {
+		ret = errno;
+		return (ret);
+	}
+
+	strlcpy(command.file, path, MAXPATHLEN);
+	strlcpy(command.argv[0], path, MAXOPTSLEN);
+	for (i = 2; newargv[i]; i++) {
+		strlcpy(command.argv[i-1], newargv[i], MAXOPTSLEN);
+	}
+	if (trace > 1) {
+		trace_prt(1, "  call_fork_exec: %s ", command.file);
+		for (i = 0; *command.argv[i]; i++)
+			trace_prt(0, "%s ", command.argv[i]);
+		trace_prt(0, "\n");
+	}
+
+	command.console = console;
+
+	darg.data_ptr = (char *)&command;
+	darg.data_size = sizeof (command);
+	darg.desc_ptr = NULL;
+	darg.desc_num = 0;
+	darg.rbuf = (char *)&status;
+	darg.rsize = sizeof (status);
+
+	ret = door_call(did_fork_exec, &darg);
+	if (trace > 1) {
+		trace_prt(1, "  call_fork_exec: door_call failed %d\n", ret);
+	}
+
+	return (status);
+}
--- a/usr/src/cmd/fs.d/autofs/automount.h	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/cmd/fs.d/autofs/automount.h	Fri Mar 30 01:55:41 2007 -0700
@@ -36,6 +36,7 @@
 #include <rpc/rpc.h>
 #include <sys/fs/autofs.h>
 #include <netinet/in.h>		/* needed for sockaddr_in declaration */
+#include <door.h>
 
 #ifdef MALLOC_DEBUG
 #include <debug_alloc.h>
@@ -93,6 +94,8 @@
 #define	INITDELAY	5
 #define	DELAY_BACKOFF	2
 #define	MAXDELAY	120
+#define	ARGV_MAX	16
+#define	VFS_PATH	"/usr/lib/fs"
 #define	DELAY(delay) { \
 	(void) sleep(delay); \
 	delay *= DELAY_BACKOFF; \
@@ -224,6 +227,23 @@
 	struct myaddrs *myaddrs_next;
 };
 
+/*
+ * structure used to pass commands to the door servers
+ */
+
+typedef struct command {
+	char file[MAXPATHLEN];
+	char argv[ARGV_MAX][MAXOPTSLEN];
+	char key[MAXOPTSLEN];
+	int console;
+} command_t;
+
+/*
+ * globally visible door_server file descriptor
+ */
+int did_exec_map;
+int did_fork_exec;
+
 extern time_t timenow;	/* set at start of processing of each RPC call */
 extern char self[];
 extern int verbose;
@@ -375,6 +395,12 @@
 extern int __nis_reset_state();
 extern int __rpc_negotiate_uid(int);
 
+/*
+ * door_server functions to handle fork activity within the automounter
+ */
+void automountd_do_fork_exec(void *, char *, size_t, door_desc_t *, uint_t);
+void automountd_do_exec_map(void *, char *, size_t, door_desc_t *, uint_t);
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/cmd/fs.d/autofs/ns_files.c	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/cmd/fs.d/autofs/ns_files.c	Fri Mar 30 01:55:41 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -22,7 +21,7 @@
 /*
  *	ns_files.c
  *
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -46,10 +45,13 @@
 #include <synch.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <strings.h>
 #include "automount.h"
 
 static int read_execout(char *key, char **lp, char *fname, char *line,
 			int linesz);
+static int call_read_execout(char *key, char **lp, char *fname, char *line,
+			int linesz);
 static FILE *file_open(char *, char *, char **, char ***);
 
 /*
@@ -114,14 +116,14 @@
 				fname, key);
 		}
 
-		rc = read_execout(key, &lp, fname, ml->linebuf, LINESZ);
+		rc = call_read_execout(key, &lp, fname, ml->linebuf, LINESZ);
 
 		if (rc != 0) {
 			nserr = __NSW_UNAVAIL;
 			goto done;
 		}
 
-		if (lp == NULL || strlen(ml->linebuf) == 0) {
+		if (strlen(ml->linebuf) == 0) {
 			nserr = __NSW_NOTFOUND;
 			goto done;
 		}
@@ -643,3 +645,64 @@
 		return (status);
 	}
 }
+
+void
+automountd_do_exec_map(void *cookie, char *argp, size_t arg_size,
+		door_desc_t *dfd, uint_t n_desc)
+{
+	command_t	*command;
+	char	line[LINESZ];
+	char	*lp;
+	int	rc;
+
+	command = (command_t *)argp;
+
+	if (sizeof (*command) != arg_size) {
+		rc = 0;
+		syslog(LOG_ERR, "read_execout: invalid door arguments");
+		door_return((char *)&rc, sizeof (rc), NULL, 0);
+	}
+
+	rc = read_execout(command->key, &lp, command->file, line, LINESZ);
+
+	if (rc != 0) {
+		/*
+		 * read_execout returned an error, return 0 to the door_client
+		 * to indicate failure
+		 */
+		rc = 0;
+		door_return((char *)&rc, sizeof (rc), NULL, 0);
+	} else {
+		door_return((char *)line, LINESZ, NULL, 0);
+	}
+	trace_prt(1, "automountd_do_exec_map, door return failed %s, %s\n",
+	    command->file, strerror(errno));
+	door_return(NULL, 0, NULL, 0);
+}
+
+int
+call_read_execout(char *key, char **lp, char *fname, char *line,
+			int linesz)
+{
+	command_t command;
+	door_arg_t darg;
+	int ret;
+
+	bzero(&command, sizeof (command));
+	(void) strlcpy(command.file, fname, MAXPATHLEN);
+	(void) strlcpy(command.key, key, MAXOPTSLEN);
+
+	if (trace >= 1)
+		trace_prt(1, "call_read_execout %s %s\n", fname, key);
+	darg.data_ptr = (char *)&command;
+	darg.data_size = sizeof (command);
+	darg.desc_ptr = NULL;
+	darg.desc_num = 0;
+	darg.rbuf = line;
+	darg.rsize = linesz;
+
+	ret = door_call(did_exec_map, &darg);
+
+	lp = &line;
+	return (ret);
+}
--- a/usr/src/uts/common/os/condvar.c	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/uts/common/os/condvar.c	Fri Mar 30 01:55:41 2007 -0700
@@ -555,49 +555,45 @@
 	(void) untimeout(id);
 
 	/*
-	 * Check for reasons to stop, and stop if lwp_nostop is zero.
+	 * Check for reasons to stop, if lwp_nostop is not true.
 	 * See issig_forreal() for explanations of the various stops.
-	 * Like issig_forreal(), we allow a PR_SUSPENDED/SUSPEND_NORMAL
-	 * to occur even if lwp_nostop is set.
 	 */
 	mutex_enter(&p->p_lock);
-	while (!(p->p_flag & SEXITLWPS)) {
+	while (lwp->lwp_nostop == 0 && !(p->p_flag & SEXITLWPS)) {
 		/*
 		 * Hold the lwp here for watchpoint manipulation.
 		 */
-		if ((t->t_proc_flag & TP_PAUSE) && !lwp->lwp_nostop) {
+		if (t->t_proc_flag & TP_PAUSE) {
 			stop(PR_SUSPENDED, SUSPEND_PAUSE);
 			continue;
 		}
 		/*
 		 * System checkpoint.
 		 */
-		if ((t->t_proc_flag & TP_CHKPT) && !lwp->lwp_nostop) {
+		if (t->t_proc_flag & TP_CHKPT) {
 			stop(PR_CHECKPOINT, 0);
 			continue;
 		}
 		/*
 		 * Honor fork1(), watchpoint activity (remapping a page),
-		 * and lwp_suspend() regardless of whether lwp_nostop is
-		 * set but not if lwp_nostop_r is set (to avoid a recursive
-		 * call to prstop()).
+		 * and lwp_suspend() requests.
 		 */
-		if (((p->p_flag & (SHOLDFORK1|SHOLDWATCH)) ||
-		    (t->t_proc_flag & TP_HOLDLWP)) && !lwp->lwp_nostop_r) {
+		if ((p->p_flag & (SHOLDFORK1|SHOLDWATCH)) ||
+		    (t->t_proc_flag & TP_HOLDLWP)) {
 			stop(PR_SUSPENDED, SUSPEND_NORMAL);
 			continue;
 		}
 		/*
 		 * Honor /proc requested stop.
 		 */
-		if ((t->t_proc_flag & TP_PRSTOP) && !lwp->lwp_nostop) {
+		if (t->t_proc_flag & TP_PRSTOP) {
 			stop(PR_REQUESTED, 0);
 		}
 		/*
 		 * If some lwp in the process has already stopped
 		 * showing PR_JOBCONTROL, stop in sympathy with it.
 		 */
-		if (p->p_stopsig && !lwp->lwp_nostop && (t != p->p_agenttp)) {
+		if (p->p_stopsig && t != p->p_agenttp) {
 			stop(PR_JOBCONTROL, p->p_stopsig);
 			continue;
 		}
--- a/usr/src/uts/common/os/sig.c	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/uts/common/os/sig.c	Fri Mar 30 01:55:41 2007 -0700
@@ -447,10 +447,10 @@
 
 	if ((lwp->lwp_asleep && MUSTRETURN(p, t)) ||
 	    (p->p_flag & (SEXITLWPS|SKILLED)) ||
-	    (!lwp->lwp_nostop_r && ((p->p_flag & (SHOLDFORK1|SHOLDWATCH)) |
-		(t->t_proc_flag & TP_HOLDLWP))) ||
-	    (!lwp->lwp_nostop && (p->p_stopsig | (t->t_proc_flag &
-		(TP_PRSTOP|TP_CHKPT|TP_PAUSE)))) ||
+	    (lwp->lwp_nostop == 0 &&
+	    (p->p_stopsig | (p->p_flag & (SHOLDFORK1|SHOLDWATCH)) |
+	    (t->t_proc_flag &
+	    (TP_PRSTOP|TP_HOLDLWP|TP_CHKPT|TP_PAUSE)))) ||
 	    lwp->lwp_cursig)
 		return (1);
 
@@ -588,15 +588,9 @@
 		 * or is executing lwp_suspend() on this lwp.
 		 * Again, go back to top of loop to check if an exit
 		 * or hold event has occurred while stopped.
-		 * We explicitly allow this form of stopping of one
-		 * lwp in a process by another lwp in the same process,
-		 * even if lwp->lwp_nostop is set, because otherwise a
-		 * process can become deadlocked on a fork1().
-		 * Allow this only if lwp_nostop_r is not set,
-		 * to avoid a recursive call to prstop().
 		 */
 		if (((p->p_flag & (SHOLDFORK1|SHOLDWATCH)) ||
-		    (t->t_proc_flag & TP_HOLDLWP)) && !lwp->lwp_nostop_r) {
+		    (t->t_proc_flag & TP_HOLDLWP)) && !lwp->lwp_nostop) {
 			stop(PR_SUSPENDED, SUSPEND_NORMAL);
 			continue;
 		}
@@ -863,11 +857,9 @@
 
 	/*
 	 * Make sure we don't deadlock on a recursive call to prstop().
-	 * prstop() sets the lwp_nostop_r flag and increments lwp_nostop.
+	 * prstop() sets the lwp_nostop flag.
 	 */
-	if (lwp->lwp_nostop_r ||
-	    (lwp->lwp_nostop &&
-	    (why != PR_SUSPENDED || what != SUSPEND_NORMAL)))
+	if (lwp->lwp_nostop)
 		return;
 
 	/*
--- a/usr/src/uts/common/sys/klwp.h	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/uts/common/sys/klwp.h	Fri Mar 30 01:55:41 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -160,34 +160,12 @@
 	struct itimerval lwp_timer[3];
 
 	/*
-	 * There are a number of places where you do not wish an lwp to
-	 * be stopped due to some interaction with other lwps in the process.
-	 * In these cases the lwp_nostop value is incremented. At places where
-	 * the lwp would normally be stopped the stop is allowed if lwp_nostop
-	 * is zero. There are a very few cases where even if lwp_nostop is set
-	 * we need to allow the lwp to stop. In those cases the lwp is
-	 * stopped if lwp_nostop_r is not set regardless of the state of
-	 * lwp_nostop. These conditions are:
-	 *
-	 * 1. In issig_forreal() when another lwp is undergoing fork1()
-	 * or watchpoint activity (p_flag contains either SHOLDFORK1 or
-	 * SHOLDWATCH or t_proc_flag contains TP_HOLDLWP)
-	 *
-	 * 2. In stop() when the why argument is not PR_SUSPENDED or the what
-	 * argument is not SUSPEND_NORMAL.
-	 *
-	 * 3. In cv_wait_stop() when another lwp is undergoing fork1() or
-	 * watchpoint activity (p_flag contains either SHOLDFORK1 or
-	 * SHOLDWATCH or t_proc_flag contains TP_HOLDLWP)
-	 *
-	 * lwp_nostop_r is set in prstop(). ie we honour the presence of
-	 * SHOLDFORK1 or SHOLDWATCH or TP_HOLDLWP in the case of
-	 * stop(PR_SUSPENDED, SUSPEND_NORMAL)
+	 * used to stop/alert lwps
 	 */
 	char	lwp_unused;
 	char	lwp_state;	/* Running in User/Kernel mode (no lock req) */
-	ushort_t lwp_nostop;	/* Don't stop this lwp except SUSPEND_NORMAL */
-	ushort_t lwp_nostop_r;	/* Don't stop this lwp (avoid recursion) */
+	ushort_t lwp_nostop;	/* Don't stop this lwp (no lock required) */
+	ushort_t lwp_pad;	/* Reserved for future use */
 
 	/*
 	 * Last failed privilege.
--- a/usr/src/uts/common/vm/vm_as.c	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/uts/common/vm/vm_as.c	Fri Mar 30 01:55:41 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -878,10 +878,8 @@
 		 * for a pagefault.  This is to avoid deadlock while debugging
 		 * a process via /proc over NFS (in particular).
 		 */
-		if (lwp != NULL) {
+		if (lwp != NULL)
 			lwp->lwp_nostop++;
-			lwp->lwp_nostop_r++;
-		}
 
 		/*
 		 * same length must be used when we softlock and softunlock.
@@ -959,10 +957,8 @@
 		seg = as_segat(as, raddr);
 		if (seg == NULL) {
 			AS_LOCK_EXIT(as, &as->a_lock);
-			if ((lwp != NULL) && (!is_xhat)) {
+			if ((lwp != NULL) && (!is_xhat))
 				lwp->lwp_nostop--;
-				lwp->lwp_nostop_r--;
-			}
 			return (FC_NOMAP);
 		}
 
@@ -1042,10 +1038,9 @@
 	}
 	if (as_lock_held)
 		AS_LOCK_EXIT(as, &as->a_lock);
-	if ((lwp != NULL) && (!is_xhat)) {
+	if ((lwp != NULL) && (!is_xhat))
 		lwp->lwp_nostop--;
-		lwp->lwp_nostop_r--;
-	}
+
 	/*
 	 * If the lower levels returned EDEADLK for a fault,
 	 * It means that we should retry the fault.  Let's wait
@@ -1083,10 +1078,8 @@
 	 * for a pagefault.  This is to avoid deadlock while debugging
 	 * a process via /proc over NFS (in particular).
 	 */
-	if (lwp != NULL) {
+	if (lwp != NULL)
 		lwp->lwp_nostop++;
-		lwp->lwp_nostop_r++;
-	}
 
 	raddr = (caddr_t)((uintptr_t)addr & (uintptr_t)PAGEMASK);
 	rsize = (((size_t)(addr + size) + PAGEOFFSET) & PAGEMASK) -
@@ -1096,10 +1089,8 @@
 	seg = as_segat(as, raddr);
 	if (seg == NULL) {
 		AS_LOCK_EXIT(as, &as->a_lock);
-		if (lwp != NULL) {
+		if (lwp != NULL)
 			lwp->lwp_nostop--;
-			lwp->lwp_nostop_r--;
-		}
 		return (FC_NOMAP);
 	}
 
@@ -1116,10 +1107,8 @@
 			break;
 	}
 	AS_LOCK_EXIT(as, &as->a_lock);
-	if (lwp != NULL) {
+	if (lwp != NULL)
 		lwp->lwp_nostop--;
-		lwp->lwp_nostop_r--;
-	}
 	/*
 	 * If the lower levels returned EDEADLK for a fault,
 	 * It means that we should retry the fault.  Let's wait
--- a/usr/src/uts/intel/fs/proc/prmachdep.c	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/uts/intel/fs/proc/prmachdep.c	Fri Mar 30 01:55:41 2007 -0700
@@ -433,11 +433,11 @@
 	struct regs *r = lwptoregs(lwp);
 
 	/*
-	 * Make sure we don't deadlock on a recursive call to prstop().
-	 * stop() tests the lwp_nostop_r and lwp_nostop flags.
+	 * Make sure we don't deadlock on a recursive call
+	 * to prstop().  stop() tests the lwp_nostop flag.
 	 */
-	lwp->lwp_nostop_r++;
-	lwp->lwp_nostop++;
+	ASSERT(lwp->lwp_nostop == 0);
+	lwp->lwp_nostop = 1;
 
 	if (copyin_nowatch((caddr_t)r->r_pc, &lwp->lwp_pcb.pcb_instr,
 		    sizeof (lwp->lwp_pcb.pcb_instr)) == 0)
@@ -448,8 +448,8 @@
 	}
 
 	(void) save_syscall_args();
-	lwp->lwp_nostop--;
-	lwp->lwp_nostop_r--;
+	ASSERT(lwp->lwp_nostop == 1);
+	lwp->lwp_nostop = 0;
 }
 
 /*
--- a/usr/src/uts/sparc/fs/proc/prmachdep.c	Fri Mar 30 01:18:25 2007 -0700
+++ b/usr/src/uts/sparc/fs/proc/prmachdep.c	Fri Mar 30 01:55:41 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -881,11 +880,11 @@
 	extern void fp_prsave(kfpu_t *);
 
 	/*
-	 * Make sure we don't deadlock on a recursive call to prstop().
-	 * stop() tests the lwp_nostop_r and lwp_nostop flags.
+	 * Make sure we don't deadlock on a recursive call
+	 * to prstop().  stop() tests the lwp_nostop flag.
 	 */
-	lwp->lwp_nostop_r++;
-	lwp->lwp_nostop++;
+	ASSERT(lwp->lwp_nostop == 0);
+	lwp->lwp_nostop = 1;
 	(void) flush_user_windows_to_stack(NULL);
 	if (lwp->lwp_pcb.pcb_step != STEP_NONE)
 		(void) prundostep();
@@ -968,8 +967,8 @@
 	}
 
 	(void) save_syscall_args();
-	lwp->lwp_nostop--;
-	lwp->lwp_nostop_r--;
+	ASSERT(lwp->lwp_nostop == 1);
+	lwp->lwp_nostop = 0;
 }
 
 /*