xref: /titanic_44/usr/src/cmd/ppgsz/ppgsz.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <unistd.h>
32*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
33*7c478bd9Sstevel@tonic-gate #include <ctype.h>
34*7c478bd9Sstevel@tonic-gate #include <string.h>
35*7c478bd9Sstevel@tonic-gate #include <signal.h>
36*7c478bd9Sstevel@tonic-gate #include <errno.h>
37*7c478bd9Sstevel@tonic-gate #include <dirent.h>
38*7c478bd9Sstevel@tonic-gate #include <limits.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
43*7c478bd9Sstevel@tonic-gate #include <libproc.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
45*7c478bd9Sstevel@tonic-gate #include <libgen.h>
46*7c478bd9Sstevel@tonic-gate #include <thread.h>
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #ifndef TRUE
49*7c478bd9Sstevel@tonic-gate #define	TRUE	1
50*7c478bd9Sstevel@tonic-gate #endif
51*7c478bd9Sstevel@tonic-gate #ifndef FALSE
52*7c478bd9Sstevel@tonic-gate #define	FALSE	0
53*7c478bd9Sstevel@tonic-gate #endif
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate static struct	ps_prochandle *Pr;
56*7c478bd9Sstevel@tonic-gate static char	*command;
57*7c478bd9Sstevel@tonic-gate static volatile int interrupt;
58*7c478bd9Sstevel@tonic-gate static int	Fflag;
59*7c478bd9Sstevel@tonic-gate static int	cflag = 1;
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate static void	intr(int);
62*7c478bd9Sstevel@tonic-gate static int	setpgsz(struct ps_prochandle *, int, size_t *);
63*7c478bd9Sstevel@tonic-gate static int	setpgsz_anon(struct ps_prochandle *, size_t, int);
64*7c478bd9Sstevel@tonic-gate static caddr_t	setup_mha(uint_t, size_t, int);
65*7c478bd9Sstevel@tonic-gate static size_t	discover_optimal_pagesize(struct ps_prochandle *,
66*7c478bd9Sstevel@tonic-gate 		uint_t, pid_t);
67*7c478bd9Sstevel@tonic-gate static void	usage();
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #define	INVPGSZ		3
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /* subopt */
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate static char	*suboptstr[] = {
74*7c478bd9Sstevel@tonic-gate 	"heap",
75*7c478bd9Sstevel@tonic-gate 	"stack",
76*7c478bd9Sstevel@tonic-gate 	"anon",
77*7c478bd9Sstevel@tonic-gate 	NULL
78*7c478bd9Sstevel@tonic-gate };
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate enum	suboptenum {
81*7c478bd9Sstevel@tonic-gate 	E_HEAP,
82*7c478bd9Sstevel@tonic-gate 	E_STACK,
83*7c478bd9Sstevel@tonic-gate 	E_ANON
84*7c478bd9Sstevel@tonic-gate };
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate static size_t
atosz(char * optarg)87*7c478bd9Sstevel@tonic-gate atosz(char *optarg)
88*7c478bd9Sstevel@tonic-gate {
89*7c478bd9Sstevel@tonic-gate 	size_t		sz = 0;
90*7c478bd9Sstevel@tonic-gate 	char		*endptr;
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate 	if (optarg == NULL || optarg[0] == '\0')
93*7c478bd9Sstevel@tonic-gate 		return (INVPGSZ);
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	sz = strtoll(optarg, &endptr, 0);
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 	switch (*endptr) {
98*7c478bd9Sstevel@tonic-gate 	case 'T':
99*7c478bd9Sstevel@tonic-gate 	case 't':
100*7c478bd9Sstevel@tonic-gate 		sz *= 1024;
101*7c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
102*7c478bd9Sstevel@tonic-gate 	case 'G':
103*7c478bd9Sstevel@tonic-gate 	case 'g':
104*7c478bd9Sstevel@tonic-gate 		sz *= 1024;
105*7c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
106*7c478bd9Sstevel@tonic-gate 	case 'M':
107*7c478bd9Sstevel@tonic-gate 	case 'm':
108*7c478bd9Sstevel@tonic-gate 		sz *= 1024;
109*7c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
110*7c478bd9Sstevel@tonic-gate 	case 'K':
111*7c478bd9Sstevel@tonic-gate 	case 'k':
112*7c478bd9Sstevel@tonic-gate 		sz *= 1024;
113*7c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
114*7c478bd9Sstevel@tonic-gate 	case 'B':
115*7c478bd9Sstevel@tonic-gate 	case 'b':
116*7c478bd9Sstevel@tonic-gate 	default:
117*7c478bd9Sstevel@tonic-gate 		break;
118*7c478bd9Sstevel@tonic-gate 	}
119*7c478bd9Sstevel@tonic-gate 	return (sz);
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /* pgsz array sufficient for max page sizes */
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate static size_t	pgsza[8 * sizeof (void *)];
125*7c478bd9Sstevel@tonic-gate static int	nelem;
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate static void
getpgsz()128*7c478bd9Sstevel@tonic-gate getpgsz()
129*7c478bd9Sstevel@tonic-gate {
130*7c478bd9Sstevel@tonic-gate 	if ((nelem = getpagesizes(NULL, 0)) == 0) {
131*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: cannot determine system page"
132*7c478bd9Sstevel@tonic-gate 		    " sizes\n", command);
133*7c478bd9Sstevel@tonic-gate 		exit(125);
134*7c478bd9Sstevel@tonic-gate 	}
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	(void) getpagesizes(pgsza, nelem);
137*7c478bd9Sstevel@tonic-gate }
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate static size_t
cnvpgsz(char * optarg)140*7c478bd9Sstevel@tonic-gate cnvpgsz(char *optarg)
141*7c478bd9Sstevel@tonic-gate {
142*7c478bd9Sstevel@tonic-gate 	size_t		pgsz = atosz(optarg);
143*7c478bd9Sstevel@tonic-gate 	int		i;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	if (!ISP2(pgsz) || ((pgsz < pgsza[0]) && pgsz != 0)) {
146*7c478bd9Sstevel@tonic-gate 		pgsz = INVPGSZ;
147*7c478bd9Sstevel@tonic-gate 	} else {
148*7c478bd9Sstevel@tonic-gate 		for (i = nelem - 1; i >= 0; i--) {
149*7c478bd9Sstevel@tonic-gate 			if (pgsz == pgsza[i])
150*7c478bd9Sstevel@tonic-gate 				break;
151*7c478bd9Sstevel@tonic-gate 			if (pgsz > pgsza[i]) {
152*7c478bd9Sstevel@tonic-gate 				pgsz = INVPGSZ;
153*7c478bd9Sstevel@tonic-gate 				break;
154*7c478bd9Sstevel@tonic-gate 			}
155*7c478bd9Sstevel@tonic-gate 		}
156*7c478bd9Sstevel@tonic-gate 	}
157*7c478bd9Sstevel@tonic-gate 	if (pgsz == INVPGSZ) {
158*7c478bd9Sstevel@tonic-gate 		if (optarg != NULL) {
159*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
160*7c478bd9Sstevel@tonic-gate 			    "%s: invalid page size specified (%s)\n",
161*7c478bd9Sstevel@tonic-gate 			    command, optarg);
162*7c478bd9Sstevel@tonic-gate 		} else {
163*7c478bd9Sstevel@tonic-gate 			usage();
164*7c478bd9Sstevel@tonic-gate 		}
165*7c478bd9Sstevel@tonic-gate 		exit(125);
166*7c478bd9Sstevel@tonic-gate 	}
167*7c478bd9Sstevel@tonic-gate 	return (pgsz);
168*7c478bd9Sstevel@tonic-gate }
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate static void
usage()171*7c478bd9Sstevel@tonic-gate usage()
172*7c478bd9Sstevel@tonic-gate {
173*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
174*7c478bd9Sstevel@tonic-gate 	    "usage:\t%s -o option[,option] [-F] cmd | -p pid ...\n"
175*7c478bd9Sstevel@tonic-gate 	    "    (set preferred page size of cmd or each process)\n"
176*7c478bd9Sstevel@tonic-gate 	    "    -o option[,option]: options are\n"
177*7c478bd9Sstevel@tonic-gate 	    "         stack=sz\n"
178*7c478bd9Sstevel@tonic-gate 	    "         heap=sz\n"
179*7c478bd9Sstevel@tonic-gate 	    "         anon=sz		(sz: valid page size or 0 (zero))\n"
180*7c478bd9Sstevel@tonic-gate 	    "    -F: force grabbing of the target process(es)\n"
181*7c478bd9Sstevel@tonic-gate 	    "    cmd: launch command\n"
182*7c478bd9Sstevel@tonic-gate 	    "    -p pid ...: process id list\n",
183*7c478bd9Sstevel@tonic-gate 	    command);
184*7c478bd9Sstevel@tonic-gate 	exit(125);
185*7c478bd9Sstevel@tonic-gate }
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])188*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
189*7c478bd9Sstevel@tonic-gate {
190*7c478bd9Sstevel@tonic-gate 	int		rc, err = 0;
191*7c478bd9Sstevel@tonic-gate 	int		opt, subopt;
192*7c478bd9Sstevel@tonic-gate 	int		errflg = 0;
193*7c478bd9Sstevel@tonic-gate 	char		*options, *value;
194*7c478bd9Sstevel@tonic-gate 	size_t		pgsz[] = {INVPGSZ, INVPGSZ, INVPGSZ};
195*7c478bd9Sstevel@tonic-gate 	pid_t		pid;
196*7c478bd9Sstevel@tonic-gate 	int		status;
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	if ((command = strrchr(argv[0], '/')) != NULL)
199*7c478bd9Sstevel@tonic-gate 		command++;
200*7c478bd9Sstevel@tonic-gate 	else
201*7c478bd9Sstevel@tonic-gate 		command = argv[0];
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	getpgsz();
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	/* options */
206*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "o:Fp")) != EOF) {
207*7c478bd9Sstevel@tonic-gate 		switch (opt) {
208*7c478bd9Sstevel@tonic-gate 		case 'o':		/* options */
209*7c478bd9Sstevel@tonic-gate 			options = optarg;
210*7c478bd9Sstevel@tonic-gate 			while (*options != '\0') {
211*7c478bd9Sstevel@tonic-gate 				subopt = getsubopt(&options, suboptstr, &value);
212*7c478bd9Sstevel@tonic-gate 				switch (subopt) {
213*7c478bd9Sstevel@tonic-gate 				case E_HEAP:
214*7c478bd9Sstevel@tonic-gate 				case E_STACK:
215*7c478bd9Sstevel@tonic-gate 				case E_ANON:
216*7c478bd9Sstevel@tonic-gate 					pgsz[subopt] = cnvpgsz(value);
217*7c478bd9Sstevel@tonic-gate 					break;
218*7c478bd9Sstevel@tonic-gate 				default:
219*7c478bd9Sstevel@tonic-gate 					errflg = 1;
220*7c478bd9Sstevel@tonic-gate 					break;
221*7c478bd9Sstevel@tonic-gate 				}
222*7c478bd9Sstevel@tonic-gate 			}
223*7c478bd9Sstevel@tonic-gate 			break;
224*7c478bd9Sstevel@tonic-gate 		case 'F':		/* force grabbing (no O_EXCL) */
225*7c478bd9Sstevel@tonic-gate 			Fflag = PGRAB_FORCE;
226*7c478bd9Sstevel@tonic-gate 			break;
227*7c478bd9Sstevel@tonic-gate 		case 'p':
228*7c478bd9Sstevel@tonic-gate 			cflag = 0;
229*7c478bd9Sstevel@tonic-gate 			break;
230*7c478bd9Sstevel@tonic-gate 		default:
231*7c478bd9Sstevel@tonic-gate 			errflg = 1;
232*7c478bd9Sstevel@tonic-gate 			break;
233*7c478bd9Sstevel@tonic-gate 		}
234*7c478bd9Sstevel@tonic-gate 	}
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	argc -= optind;
237*7c478bd9Sstevel@tonic-gate 	argv += optind;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	if ((pgsz[E_HEAP] == INVPGSZ && pgsz[E_STACK] == INVPGSZ &&
240*7c478bd9Sstevel@tonic-gate 	    pgsz[E_ANON] == INVPGSZ) || errflg || argc <= 0) {
241*7c478bd9Sstevel@tonic-gate 		usage();
242*7c478bd9Sstevel@tonic-gate 	}
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	/* catch signals from terminal */
245*7c478bd9Sstevel@tonic-gate 	if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
246*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGHUP, intr);
247*7c478bd9Sstevel@tonic-gate 	if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
248*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGINT, intr);
249*7c478bd9Sstevel@tonic-gate 	if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
250*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGQUIT, intr);
251*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTERM, intr);
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	if (cflag && !interrupt) {		/* command */
254*7c478bd9Sstevel@tonic-gate 		int		err;
255*7c478bd9Sstevel@tonic-gate 		char		path[PATH_MAX];
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 		Pr = Pcreate(argv[0], &argv[0], &err, path, sizeof (path));
258*7c478bd9Sstevel@tonic-gate 		if (Pr == NULL) {
259*7c478bd9Sstevel@tonic-gate 			switch (err) {
260*7c478bd9Sstevel@tonic-gate 			case C_PERM:
261*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
262*7c478bd9Sstevel@tonic-gate 				    "%s: cannot control set-id or "
263*7c478bd9Sstevel@tonic-gate 				    "unreadable object file: %s\n",
264*7c478bd9Sstevel@tonic-gate 				    command, path);
265*7c478bd9Sstevel@tonic-gate 				break;
266*7c478bd9Sstevel@tonic-gate 			case C_LP64:
267*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
268*7c478bd9Sstevel@tonic-gate 				    "%s: cannot control _LP64 "
269*7c478bd9Sstevel@tonic-gate 				    "program: %s\n", command, path);
270*7c478bd9Sstevel@tonic-gate 				break;
271*7c478bd9Sstevel@tonic-gate 			case C_NOEXEC:
272*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: cannot execute "
273*7c478bd9Sstevel@tonic-gate 				    "program: %s\n", command, argv[0]);
274*7c478bd9Sstevel@tonic-gate 				exit(126);
275*7c478bd9Sstevel@tonic-gate 				break;
276*7c478bd9Sstevel@tonic-gate 			case C_NOENT:
277*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: cannot find "
278*7c478bd9Sstevel@tonic-gate 				    "program: %s\n", command, argv[0]);
279*7c478bd9Sstevel@tonic-gate 				exit(127);
280*7c478bd9Sstevel@tonic-gate 				break;
281*7c478bd9Sstevel@tonic-gate 			case C_STRANGE:
282*7c478bd9Sstevel@tonic-gate 				break;
283*7c478bd9Sstevel@tonic-gate 			default:
284*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
285*7c478bd9Sstevel@tonic-gate 				    "%s: %s\n", command, Pcreate_error(err));
286*7c478bd9Sstevel@tonic-gate 				break;
287*7c478bd9Sstevel@tonic-gate 			}
288*7c478bd9Sstevel@tonic-gate 			exit(125);
289*7c478bd9Sstevel@tonic-gate 		}
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 		if ((rc = setpgsz(Pr, Pstatus(Pr)->pr_dmodel, pgsz)) != 0) {
292*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: set page size "
293*7c478bd9Sstevel@tonic-gate 			    "failed for program: %s\n", command, argv[0]);
294*7c478bd9Sstevel@tonic-gate 			(void) pr_exit(Pr, 1);
295*7c478bd9Sstevel@tonic-gate 			exit(125);
296*7c478bd9Sstevel@tonic-gate 		}
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 		/*
299*7c478bd9Sstevel@tonic-gate 		 * release the command to run, wait for it and
300*7c478bd9Sstevel@tonic-gate 		 * return it's exit status if we can.
301*7c478bd9Sstevel@tonic-gate 		 */
302*7c478bd9Sstevel@tonic-gate 		Prelease(Pr, 0);
303*7c478bd9Sstevel@tonic-gate 		do {
304*7c478bd9Sstevel@tonic-gate 			pid = wait(&status);
305*7c478bd9Sstevel@tonic-gate 		} while (pid == -1 && errno == EINTR);
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 		if (pid == -1) {
308*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: wait() error: %s\n",
309*7c478bd9Sstevel@tonic-gate 			    command, strerror(errno));
310*7c478bd9Sstevel@tonic-gate 			exit(125);
311*7c478bd9Sstevel@tonic-gate 		}
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 		/*
314*7c478bd9Sstevel@tonic-gate 		 * Pass thru the child's exit value.
315*7c478bd9Sstevel@tonic-gate 		 */
316*7c478bd9Sstevel@tonic-gate 		if (WIFEXITED(status))
317*7c478bd9Sstevel@tonic-gate 			exit(WEXITSTATUS(status));
318*7c478bd9Sstevel@tonic-gate 		exit(status | WCOREFLG);
319*7c478bd9Sstevel@tonic-gate 	}
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	/* process pids */
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	while (--argc >= 0 && !interrupt) {
324*7c478bd9Sstevel@tonic-gate 		char *arg;
325*7c478bd9Sstevel@tonic-gate 		psinfo_t psinfo;
326*7c478bd9Sstevel@tonic-gate 		int gret;
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);	/* line-at-a-time */
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 		/* get the specified pid and the psinfo struct */
331*7c478bd9Sstevel@tonic-gate 		arg = *argv++;
332*7c478bd9Sstevel@tonic-gate 		pid = proc_arg_psinfo(arg, PR_ARG_PIDS, &psinfo, &gret);
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 		if (pid == -1) {
335*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: cannot examine pid %s:"
336*7c478bd9Sstevel@tonic-gate 			    " %s\n", command, arg, Pgrab_error(gret));
337*7c478bd9Sstevel@tonic-gate 			if (!isdigit(arg[0]) && strncmp(arg, "/proc/", 6)) {
338*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
339*7c478bd9Sstevel@tonic-gate 				    "\tdo not use -p option"
340*7c478bd9Sstevel@tonic-gate 				    " to launch a command\n");
341*7c478bd9Sstevel@tonic-gate 			}
342*7c478bd9Sstevel@tonic-gate 			err++;
343*7c478bd9Sstevel@tonic-gate 		} else if ((Pr = Pgrab(pid, Fflag, &gret)) != NULL) {
344*7c478bd9Sstevel@tonic-gate 			rc = setpgsz(Pr, Pstatus(Pr)->pr_dmodel, pgsz);
345*7c478bd9Sstevel@tonic-gate 			if (rc != 0) {
346*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: set page size "
347*7c478bd9Sstevel@tonic-gate 				    "failed for pid: %d\n", command, (int)pid);
348*7c478bd9Sstevel@tonic-gate 				err++;
349*7c478bd9Sstevel@tonic-gate 			}
350*7c478bd9Sstevel@tonic-gate 			Prelease(Pr, 0);
351*7c478bd9Sstevel@tonic-gate 			Pr = NULL;
352*7c478bd9Sstevel@tonic-gate 		} else {
353*7c478bd9Sstevel@tonic-gate 			switch (gret) {
354*7c478bd9Sstevel@tonic-gate 			case G_SYS:
355*7c478bd9Sstevel@tonic-gate 				proc_unctrl_psinfo(&psinfo);
356*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: cannot set page "
357*7c478bd9Sstevel@tonic-gate 				    "size for system process: %d [ %s ]\n",
358*7c478bd9Sstevel@tonic-gate 				    command, (int)pid, psinfo.pr_psargs);
359*7c478bd9Sstevel@tonic-gate 				err++;
360*7c478bd9Sstevel@tonic-gate 				break;
361*7c478bd9Sstevel@tonic-gate 			case G_SELF:
362*7c478bd9Sstevel@tonic-gate 				/* do it to own self */
363*7c478bd9Sstevel@tonic-gate 				rc = setpgsz(NULL, psinfo.pr_dmodel, pgsz);
364*7c478bd9Sstevel@tonic-gate 				if (rc != 0) {
365*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, "%s: set page"
366*7c478bd9Sstevel@tonic-gate 					    "size failed for self: %d\n",
367*7c478bd9Sstevel@tonic-gate 					    command, (int)pid);
368*7c478bd9Sstevel@tonic-gate 					err++;
369*7c478bd9Sstevel@tonic-gate 				}
370*7c478bd9Sstevel@tonic-gate 				break;
371*7c478bd9Sstevel@tonic-gate 			default:
372*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: %s: %d\n",
373*7c478bd9Sstevel@tonic-gate 				    command, Pgrab_error(gret), (int)pid);
374*7c478bd9Sstevel@tonic-gate 				err++;
375*7c478bd9Sstevel@tonic-gate 				break;
376*7c478bd9Sstevel@tonic-gate 			}
377*7c478bd9Sstevel@tonic-gate 		}
378*7c478bd9Sstevel@tonic-gate 	}
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	if (interrupt || err)
381*7c478bd9Sstevel@tonic-gate 		exit(125);
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	return (0);
384*7c478bd9Sstevel@tonic-gate }
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
387*7c478bd9Sstevel@tonic-gate static void
intr(int sig)388*7c478bd9Sstevel@tonic-gate intr(int sig)
389*7c478bd9Sstevel@tonic-gate {
390*7c478bd9Sstevel@tonic-gate 	interrupt = 1;
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate /* ------ begin specific code ------ */
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate /* set process page size */
396*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
397*7c478bd9Sstevel@tonic-gate static int
setpgsz(struct ps_prochandle * Pr,int dmodel,size_t pgsz[])398*7c478bd9Sstevel@tonic-gate setpgsz(struct	ps_prochandle *Pr, int dmodel, size_t pgsz[])
399*7c478bd9Sstevel@tonic-gate {
400*7c478bd9Sstevel@tonic-gate 	int			rc;
401*7c478bd9Sstevel@tonic-gate 	int			err = 0;
402*7c478bd9Sstevel@tonic-gate 	caddr_t			mpss;
403*7c478bd9Sstevel@tonic-gate 	int			i;
404*7c478bd9Sstevel@tonic-gate 	static uint_t	pgszcmd[] =
405*7c478bd9Sstevel@tonic-gate 	{MHA_MAPSIZE_BSSBRK, MHA_MAPSIZE_STACK, MHA_MAPSIZE_VA};
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	for (i = E_HEAP; i <= E_ANON; i++) {
408*7c478bd9Sstevel@tonic-gate 		if (pgsz[i] == INVPGSZ)
409*7c478bd9Sstevel@tonic-gate 			continue;
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 		if (i == E_ANON)
412*7c478bd9Sstevel@tonic-gate 			rc = setpgsz_anon(Pr, pgsz[i], dmodel);
413*7c478bd9Sstevel@tonic-gate 		else {
414*7c478bd9Sstevel@tonic-gate 			mpss = setup_mha(pgszcmd[i], pgsz[i], dmodel);
415*7c478bd9Sstevel@tonic-gate 			rc = pr_memcntl(Pr, NULL, 0, MC_HAT_ADVISE, mpss, 0, 0);
416*7c478bd9Sstevel@tonic-gate 		}
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 		if (rc < 0) {
419*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: warning: set %s page size "
420*7c478bd9Sstevel@tonic-gate 			    "failed (%s) for pid %d\n", command, suboptstr[i],
421*7c478bd9Sstevel@tonic-gate 			    strerror(errno), (int)Pstatus(Pr)->pr_pid);
422*7c478bd9Sstevel@tonic-gate 			err++;
423*7c478bd9Sstevel@tonic-gate 		}
424*7c478bd9Sstevel@tonic-gate 	}
425*7c478bd9Sstevel@tonic-gate 	return (err);
426*7c478bd9Sstevel@tonic-gate }
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate /*
430*7c478bd9Sstevel@tonic-gate  * Walk through the process' address space segments.  Set all anonymous
431*7c478bd9Sstevel@tonic-gate  * segments to the new page size.
432*7c478bd9Sstevel@tonic-gate  */
433*7c478bd9Sstevel@tonic-gate static int
setpgsz_anon(struct ps_prochandle * Pr,size_t pgsz,int dmodel)434*7c478bd9Sstevel@tonic-gate setpgsz_anon(struct ps_prochandle *Pr, size_t pgsz, int dmodel)
435*7c478bd9Sstevel@tonic-gate {
436*7c478bd9Sstevel@tonic-gate 	caddr_t		mpss;
437*7c478bd9Sstevel@tonic-gate 	prmap_t		map;
438*7c478bd9Sstevel@tonic-gate 	uintptr_t	addr;
439*7c478bd9Sstevel@tonic-gate 	size_t		size;
440*7c478bd9Sstevel@tonic-gate 	const psinfo_t	*psinfo;
441*7c478bd9Sstevel@tonic-gate 	const pstatus_t	*pstatus;
442*7c478bd9Sstevel@tonic-gate 	int		fd;
443*7c478bd9Sstevel@tonic-gate 	int		rc;
444*7c478bd9Sstevel@tonic-gate 	char		path[PATH_MAX];
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	/*
447*7c478bd9Sstevel@tonic-gate 	 * Setting the page size for anonymous segments on a process before it
448*7c478bd9Sstevel@tonic-gate 	 * has run will have no effect, since it has not configured anonymous
449*7c478bd9Sstevel@tonic-gate 	 * memory and the page size setting is not "sticky" inside the kernel.
450*7c478bd9Sstevel@tonic-gate 	 * Any anonymous memory subsequently mapped will have the default page
451*7c478bd9Sstevel@tonic-gate 	 * size.
452*7c478bd9Sstevel@tonic-gate 	 */
453*7c478bd9Sstevel@tonic-gate 	if (cflag)
454*7c478bd9Sstevel@tonic-gate 		return (0);
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	if ((psinfo = Ppsinfo(Pr)) == NULL)
457*7c478bd9Sstevel@tonic-gate 		return (-1);
458*7c478bd9Sstevel@tonic-gate 	if ((pstatus = Pstatus(Pr)) == NULL)
459*7c478bd9Sstevel@tonic-gate 		return (-1);
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	if (pgsz == 0)
462*7c478bd9Sstevel@tonic-gate 		pgsz = discover_optimal_pagesize(Pr, dmodel, psinfo->pr_pid);
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	mpss = setup_mha(MHA_MAPSIZE_VA, pgsz, dmodel);
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	(void) snprintf(path, PATH_MAX, "/proc/%d/map", (int)psinfo->pr_pid);
467*7c478bd9Sstevel@tonic-gate 	if ((fd = open(path, O_RDONLY)) < 0)
468*7c478bd9Sstevel@tonic-gate 		return (-1);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	while (read(fd, &map, sizeof (map)) == sizeof (map)) {
471*7c478bd9Sstevel@tonic-gate 		if ((map.pr_mflags & MA_ANON) == 0) {
472*7c478bd9Sstevel@tonic-gate 			/* Not anon. */
473*7c478bd9Sstevel@tonic-gate 			continue;
474*7c478bd9Sstevel@tonic-gate 		} else if (map.pr_mflags & MA_SHARED) {
475*7c478bd9Sstevel@tonic-gate 			/* Can't change pagesize for shared mappings. */
476*7c478bd9Sstevel@tonic-gate 			continue;
477*7c478bd9Sstevel@tonic-gate 		} else if (map.pr_vaddr + map.pr_size >
478*7c478bd9Sstevel@tonic-gate 		    pstatus->pr_brkbase &&
479*7c478bd9Sstevel@tonic-gate 		    map.pr_vaddr <
480*7c478bd9Sstevel@tonic-gate 		    pstatus->pr_brkbase + pstatus->pr_brksize) {
481*7c478bd9Sstevel@tonic-gate 			/* Heap. */
482*7c478bd9Sstevel@tonic-gate 			continue;
483*7c478bd9Sstevel@tonic-gate 		} else if (map.pr_vaddr >= pstatus->pr_stkbase &&
484*7c478bd9Sstevel@tonic-gate 		    map.pr_vaddr + map.pr_size <=
485*7c478bd9Sstevel@tonic-gate 		    pstatus->pr_stkbase + pstatus->pr_stksize) {
486*7c478bd9Sstevel@tonic-gate 			/* Stack. */
487*7c478bd9Sstevel@tonic-gate 			continue;
488*7c478bd9Sstevel@tonic-gate 		} else if (map.pr_size < pgsz) {
489*7c478bd9Sstevel@tonic-gate 			/* Too small. */
490*7c478bd9Sstevel@tonic-gate 			continue;
491*7c478bd9Sstevel@tonic-gate 		}
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 		/*
494*7c478bd9Sstevel@tonic-gate 		 * Find the first address in the segment that is page-aligned.
495*7c478bd9Sstevel@tonic-gate 		 */
496*7c478bd9Sstevel@tonic-gate 		if (pgsz == 0 || ((map.pr_vaddr % pgsz) == 0))
497*7c478bd9Sstevel@tonic-gate 			addr = map.pr_vaddr;
498*7c478bd9Sstevel@tonic-gate 		else
499*7c478bd9Sstevel@tonic-gate 			addr = map.pr_vaddr + (pgsz - (map.pr_vaddr % pgsz));
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 		/*
502*7c478bd9Sstevel@tonic-gate 		 * Calculate how many pages will fit in the segment.
503*7c478bd9Sstevel@tonic-gate 		 */
504*7c478bd9Sstevel@tonic-gate 		if (pgsz == 0)
505*7c478bd9Sstevel@tonic-gate 			size = map.pr_size;
506*7c478bd9Sstevel@tonic-gate 		else
507*7c478bd9Sstevel@tonic-gate 			size = map.pr_size - (addr % map.pr_vaddr) -
508*7c478bd9Sstevel@tonic-gate 			    ((map.pr_vaddr + map.pr_size) % pgsz);
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 		/*
511*7c478bd9Sstevel@tonic-gate 		 * If no aligned pages fit in the segment, ignore it.
512*7c478bd9Sstevel@tonic-gate 		 */
513*7c478bd9Sstevel@tonic-gate 		if (size < pgsz) {
514*7c478bd9Sstevel@tonic-gate 			continue;
515*7c478bd9Sstevel@tonic-gate 		}
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 		rc = pr_memcntl(Pr, (caddr_t)addr, size,
518*7c478bd9Sstevel@tonic-gate 		    MC_HAT_ADVISE, mpss, 0, 0);
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 		/*
521*7c478bd9Sstevel@tonic-gate 		 * If an error occurs on any segment, report the error here and
522*7c478bd9Sstevel@tonic-gate 		 * then go on to try setting the page size for the remaining
523*7c478bd9Sstevel@tonic-gate 		 * segments.
524*7c478bd9Sstevel@tonic-gate 		 */
525*7c478bd9Sstevel@tonic-gate 		if (rc < 0) {
526*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: warning: set page size "
527*7c478bd9Sstevel@tonic-gate 			    "failed (%s) for pid %d for anon segment at "
528*7c478bd9Sstevel@tonic-gate 			    "address: %p\n", command, strerror(errno),
529*7c478bd9Sstevel@tonic-gate 			    (int)psinfo->pr_pid, (void *)map.pr_vaddr);
530*7c478bd9Sstevel@tonic-gate 		}
531*7c478bd9Sstevel@tonic-gate 	}
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
534*7c478bd9Sstevel@tonic-gate 	return (0);
535*7c478bd9Sstevel@tonic-gate }
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate /*
538*7c478bd9Sstevel@tonic-gate  * Discover the optimal page size for the process.
539*7c478bd9Sstevel@tonic-gate  * Do this by creating a 4M segment in the target process, set its pagesize
540*7c478bd9Sstevel@tonic-gate  * to 0, and read the map file to discover the page size selected by the system.
541*7c478bd9Sstevel@tonic-gate  */
542*7c478bd9Sstevel@tonic-gate static size_t
discover_optimal_pagesize(struct ps_prochandle * Pr,uint_t dmodel,pid_t pid)543*7c478bd9Sstevel@tonic-gate discover_optimal_pagesize(struct ps_prochandle *Pr, uint_t dmodel, pid_t pid)
544*7c478bd9Sstevel@tonic-gate {
545*7c478bd9Sstevel@tonic-gate 	size_t			size = 0;
546*7c478bd9Sstevel@tonic-gate 	size_t			len = pgsza[nelem - 1];
547*7c478bd9Sstevel@tonic-gate 	prxmap_t		xmap;
548*7c478bd9Sstevel@tonic-gate 	caddr_t			mha;
549*7c478bd9Sstevel@tonic-gate 	void			*addr;
550*7c478bd9Sstevel@tonic-gate 	int			fd = -1;
551*7c478bd9Sstevel@tonic-gate 	char			path[PATH_MAX];
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	(void) snprintf(path, PATH_MAX, "/proc/%d/xmap", (int)pid);
554*7c478bd9Sstevel@tonic-gate 	if ((fd = open(path, O_RDONLY)) < 0)
555*7c478bd9Sstevel@tonic-gate 		return (size);
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	if ((addr = pr_mmap(Pr, (void *)len, len, PROT_READ | PROT_WRITE,
558*7c478bd9Sstevel@tonic-gate 	    MAP_PRIVATE | MAP_ANON | MAP_ALIGN, -1, 0)) == MAP_FAILED) {
559*7c478bd9Sstevel@tonic-gate 		goto err;
560*7c478bd9Sstevel@tonic-gate 	}
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	mha = setup_mha(MHA_MAPSIZE_VA, 0, dmodel);
563*7c478bd9Sstevel@tonic-gate 	if (pr_memcntl(Pr, addr, len, MC_HAT_ADVISE, mha, 0, 0) < 0) {
564*7c478bd9Sstevel@tonic-gate 		goto err;
565*7c478bd9Sstevel@tonic-gate 	}
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 	/*
568*7c478bd9Sstevel@tonic-gate 	 * Touch a page in the segment so the hat mapping gets created.
569*7c478bd9Sstevel@tonic-gate 	 */
570*7c478bd9Sstevel@tonic-gate 	(void) Pwrite(Pr, &len, sizeof (len), (uintptr_t)addr);
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	/*
573*7c478bd9Sstevel@tonic-gate 	 * Read through the address map looking for our segment.
574*7c478bd9Sstevel@tonic-gate 	 */
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	while (read(fd, &xmap, sizeof (xmap)) == sizeof (xmap)) {
577*7c478bd9Sstevel@tonic-gate 		if (xmap.pr_vaddr == (uintptr_t)addr)
578*7c478bd9Sstevel@tonic-gate 			break;
579*7c478bd9Sstevel@tonic-gate 	}
580*7c478bd9Sstevel@tonic-gate 	if (xmap.pr_vaddr != (uintptr_t)addr)
581*7c478bd9Sstevel@tonic-gate 		goto err;
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	size = xmap.pr_hatpagesize;
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate err:
586*7c478bd9Sstevel@tonic-gate 	if (addr != MAP_FAILED) {
587*7c478bd9Sstevel@tonic-gate 		if (pr_munmap(Pr, addr, len) == -1) {
588*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
589*7c478bd9Sstevel@tonic-gate 			    "%s: couldn't delete segment at %p\n",
590*7c478bd9Sstevel@tonic-gate 			    command, addr);
591*7c478bd9Sstevel@tonic-gate 		}
592*7c478bd9Sstevel@tonic-gate 	}
593*7c478bd9Sstevel@tonic-gate 	if (fd != -1)
594*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	return (size);
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate static struct memcntl_mha	gmha;
600*7c478bd9Sstevel@tonic-gate #ifdef _LP64
601*7c478bd9Sstevel@tonic-gate static struct memcntl_mha32	gmha32;
602*7c478bd9Sstevel@tonic-gate #endif
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate static caddr_t
605*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
setup_mha(uint_t command,size_t pagesize,int dmodel)606*7c478bd9Sstevel@tonic-gate setup_mha(uint_t command, size_t pagesize, int dmodel)
607*7c478bd9Sstevel@tonic-gate {
608*7c478bd9Sstevel@tonic-gate #ifdef _LP64
609*7c478bd9Sstevel@tonic-gate 	if (dmodel == PR_MODEL_ILP32) {
610*7c478bd9Sstevel@tonic-gate 		gmha32.mha_cmd = command;
611*7c478bd9Sstevel@tonic-gate 		gmha32.mha_flags = 0;
612*7c478bd9Sstevel@tonic-gate 		gmha32.mha_pagesize = pagesize;
613*7c478bd9Sstevel@tonic-gate 		return ((caddr_t)&gmha32);
614*7c478bd9Sstevel@tonic-gate 	}
615*7c478bd9Sstevel@tonic-gate #endif
616*7c478bd9Sstevel@tonic-gate 	gmha.mha_cmd = command;
617*7c478bd9Sstevel@tonic-gate 	gmha.mha_flags = 0;
618*7c478bd9Sstevel@tonic-gate 	gmha.mha_pagesize = pagesize;
619*7c478bd9Sstevel@tonic-gate 	return ((caddr_t)&gmha);
620*7c478bd9Sstevel@tonic-gate }
621