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 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 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 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 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 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 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 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 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 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 */ 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