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