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
plock(int op)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