1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * plock - lock "segments" in physical memory. 31 * 32 * Supports SVID-compatible plock, taking into account dynamically linked 33 * objects (such as shared libraries). 34 */ 35 36 #include "lint.h" 37 #include <mtlib.h> 38 #include <sys/types.h> 39 #include <sys/mman.h> 40 #include <sys/lock.h> 41 #include <errno.h> 42 #include <stddef.h> 43 #include <unistd.h> 44 #include <thread.h> 45 #include <synch.h> 46 47 /* 48 * Module-scope variables. 49 */ 50 static int lock_state = 0; /* lock state */ 51 static pid_t state_pid = -1; /* pid to which state belongs */ 52 static mutex_t plock_lock = DEFAULTMUTEX; 53 54 /* 55 * plock 56 */ 57 int 58 plock(int op) /* desired operation */ 59 { 60 int e; /* return value */ 61 pid_t pid; /* current pid */ 62 63 lmutex_lock(&plock_lock); 64 65 /* 66 * Validate state of lock's. If parent has forked, then 67 * the lock state needs to be reset (children do not inherit 68 * memory locks, and thus do not inherit their state). 69 */ 70 if ((pid = getpid()) != state_pid) { 71 lock_state = 0; 72 state_pid = pid; 73 } 74 75 /* 76 * Dispatch on operation. Note: plock and its relatives depend 77 * upon "op" being bit encoded. 78 */ 79 switch (op) { 80 81 /* 82 * UNLOCK: remove all memory locks. Requires that some be set! 83 */ 84 case UNLOCK: 85 if (lock_state == 0) { 86 errno = EINVAL; 87 lmutex_unlock(&plock_lock); 88 return (-1); 89 } 90 e = munlockall(); 91 if (e) { 92 lmutex_unlock(&plock_lock); 93 return (-1); 94 } else { 95 lock_state = 0; 96 lmutex_unlock(&plock_lock); 97 return (0); 98 } 99 /*NOTREACHED*/ 100 101 /* 102 * TXTLOCK: locks text segments. 103 */ 104 case TXTLOCK: 105 106 /* 107 * If a text or process lock is already set, then fail. 108 */ 109 if ((lock_state & TXTLOCK) || (lock_state & PROCLOCK)) { 110 errno = EINVAL; 111 lmutex_unlock(&plock_lock); 112 return (-1); 113 } 114 115 /* 116 * Try to apply the lock(s). If a failure occurs, 117 * memcntl backs them out automatically. 118 */ 119 e = memcntl(NULL, 0, MC_LOCKAS, (caddr_t)MCL_CURRENT, 120 PROC_TEXT|PRIVATE, (int)NULL); 121 if (!e) 122 lock_state |= TXTLOCK; 123 lmutex_unlock(&plock_lock); 124 return (e); 125 /*NOTREACHED*/ 126 127 /* 128 * DATLOCK: locks data segment(s), including the stack and all 129 * future growth in the address space. 130 */ 131 case DATLOCK: 132 133 /* 134 * If a data or process lock is already set, then fail. 135 */ 136 if ((lock_state & DATLOCK) || (lock_state & PROCLOCK)) { 137 errno = EINVAL; 138 lmutex_unlock(&plock_lock); 139 return (-1); 140 } 141 142 /* 143 * Try to lock the data and stack segments. On failure 144 * memcntl undoes the locks internally. 145 */ 146 e = memcntl(NULL, 0, MC_LOCKAS, (caddr_t)MCL_CURRENT, 147 PROC_DATA|PRIVATE, (int)NULL); 148 if (e) { 149 lmutex_unlock(&plock_lock); 150 return (-1); 151 } 152 153 /* try to set a lock for all future mappings. */ 154 e = mlockall(MCL_FUTURE); 155 156 /* 157 * If failures have occurred, back out the locks 158 * and return failure. 159 */ 160 if (e) { 161 e = errno; 162 (void) memcntl(NULL, 0, MC_UNLOCKAS, 163 (caddr_t)MCL_CURRENT, PROC_DATA|PRIVATE, (int)NULL); 164 errno = e; 165 lmutex_unlock(&plock_lock); 166 return (-1); 167 } 168 169 /* 170 * Data, stack, and growth have been locked. Set state 171 * and return success. 172 */ 173 lock_state |= DATLOCK; 174 lmutex_unlock(&plock_lock); 175 return (0); 176 /*NOTREACHED*/ 177 178 /* 179 * PROCLOCK: lock everything, and all future things as well. 180 * There should be nothing locked when this is called. 181 */ 182 case PROCLOCK: 183 if (lock_state) { 184 errno = EINVAL; 185 lmutex_unlock(&plock_lock); 186 return (-1); 187 } 188 if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) { 189 lock_state |= PROCLOCK; 190 lmutex_unlock(&plock_lock); 191 return (0); 192 } else { 193 lmutex_unlock(&plock_lock); 194 return (-1); 195 } 196 /*NOTREACHED*/ 197 198 /* 199 * Invalid operation. 200 */ 201 default: 202 errno = EINVAL; 203 lmutex_unlock(&plock_lock); 204 return (-1); 205 /*NOTREACHED*/ 206 } 207 } 208