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 /* 28 * plock - lock "segments" in physical memory. 29 * 30 * Supports SVID-compatible plock, taking into account dynamically linked 31 * objects (such as shared libraries). 32 */ 33 34 #include "lint.h" 35 #include <mtlib.h> 36 #include <sys/types.h> 37 #include <sys/mman.h> 38 #include <sys/lock.h> 39 #include <errno.h> 40 #include <stddef.h> 41 #include <unistd.h> 42 #include <thread.h> 43 #include <synch.h> 44 45 /* 46 * Module-scope variables. 47 */ 48 static int lock_state = 0; /* lock state */ 49 static pid_t state_pid = -1; /* pid to which state belongs */ 50 static mutex_t plock_lock = DEFAULTMUTEX; 51 52 /* 53 * plock 54 */ 55 int 56 plock(int op) /* desired operation */ 57 { 58 int e; /* return value */ 59 pid_t pid; /* current pid */ 60 61 lmutex_lock(&plock_lock); 62 63 /* 64 * Validate state of lock's. If parent has forked, then 65 * the lock state needs to be reset (children do not inherit 66 * memory locks, and thus do not inherit their state). 67 */ 68 if ((pid = getpid()) != state_pid) { 69 lock_state = 0; 70 state_pid = pid; 71 } 72 73 /* 74 * Dispatch on operation. Note: plock and its relatives depend 75 * upon "op" being bit encoded. 76 */ 77 switch (op) { 78 79 /* 80 * UNLOCK: remove all memory locks. Requires that some be set! 81 */ 82 case UNLOCK: 83 if (lock_state == 0) { 84 errno = EINVAL; 85 lmutex_unlock(&plock_lock); 86 return (-1); 87 } 88 e = munlockall(); 89 if (e) { 90 lmutex_unlock(&plock_lock); 91 return (-1); 92 } else { 93 lock_state = 0; 94 lmutex_unlock(&plock_lock); 95 return (0); 96 } 97 /*NOTREACHED*/ 98 99 /* 100 * TXTLOCK: locks text segments. 101 */ 102 case TXTLOCK: 103 104 /* 105 * If a text or process lock is already set, then fail. 106 */ 107 if ((lock_state & TXTLOCK) || (lock_state & PROCLOCK)) { 108 errno = EINVAL; 109 lmutex_unlock(&plock_lock); 110 return (-1); 111 } 112 113 /* 114 * Try to apply the lock(s). If a failure occurs, 115 * memcntl backs them out automatically. 116 */ 117 e = memcntl(NULL, 0, MC_LOCKAS, (caddr_t)MCL_CURRENT, 118 PROC_TEXT|PRIVATE, 0); 119 if (!e) 120 lock_state |= TXTLOCK; 121 lmutex_unlock(&plock_lock); 122 return (e); 123 /*NOTREACHED*/ 124 125 /* 126 * DATLOCK: locks data segment(s), including the stack and all 127 * future growth in the address space. 128 */ 129 case DATLOCK: 130 131 /* 132 * If a data or process lock is already set, then fail. 133 */ 134 if ((lock_state & DATLOCK) || (lock_state & PROCLOCK)) { 135 errno = EINVAL; 136 lmutex_unlock(&plock_lock); 137 return (-1); 138 } 139 140 /* 141 * Try to lock the data and stack segments. On failure 142 * memcntl undoes the locks internally. 143 */ 144 e = memcntl(NULL, 0, MC_LOCKAS, (caddr_t)MCL_CURRENT, 145 PROC_DATA|PRIVATE, 0); 146 if (e) { 147 lmutex_unlock(&plock_lock); 148 return (-1); 149 } 150 151 /* try to set a lock for all future mappings. */ 152 e = mlockall(MCL_FUTURE); 153 154 /* 155 * If failures have occurred, back out the locks 156 * and return failure. 157 */ 158 if (e) { 159 e = errno; 160 (void) memcntl(NULL, 0, MC_UNLOCKAS, 161 (caddr_t)MCL_CURRENT, PROC_DATA|PRIVATE, 0); 162 errno = e; 163 lmutex_unlock(&plock_lock); 164 return (-1); 165 } 166 167 /* 168 * Data, stack, and growth have been locked. Set state 169 * and return success. 170 */ 171 lock_state |= DATLOCK; 172 lmutex_unlock(&plock_lock); 173 return (0); 174 /*NOTREACHED*/ 175 176 /* 177 * PROCLOCK: lock everything, and all future things as well. 178 * There should be nothing locked when this is called. 179 */ 180 case PROCLOCK: 181 if (lock_state) { 182 errno = EINVAL; 183 lmutex_unlock(&plock_lock); 184 return (-1); 185 } 186 if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) { 187 lock_state |= PROCLOCK; 188 lmutex_unlock(&plock_lock); 189 return (0); 190 } else { 191 lmutex_unlock(&plock_lock); 192 return (-1); 193 } 194 /*NOTREACHED*/ 195 196 /* 197 * Invalid operation. 198 */ 199 default: 200 errno = EINVAL; 201 lmutex_unlock(&plock_lock); 202 return (-1); 203 /*NOTREACHED*/ 204 } 205 } 206