Print this page
patch as-lock-macro-simplification
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/syscall/rlimit.c
+++ new/usr/src/uts/common/syscall/rlimit.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 28 /* All Rights Reserved */
29 29
30 30
31 31 #pragma ident "%Z%%M% %I% %E% SMI"
32 32
33 33 #include <sys/param.h>
34 34 #include <sys/types.h>
35 35 #include <sys/inttypes.h>
36 36 #include <sys/sysmacros.h>
37 37 #include <sys/systm.h>
38 38 #include <sys/tuneable.h>
39 39 #include <sys/user.h>
40 40 #include <sys/errno.h>
41 41 #include <sys/vnode.h>
42 42 #include <sys/file.h>
43 43 #include <sys/proc.h>
44 44 #include <sys/resource.h>
45 45 #include <sys/ulimit.h>
46 46 #include <sys/debug.h>
47 47 #include <sys/rctl.h>
48 48
49 49 #include <vm/as.h>
50 50
51 51 /*
52 52 * Perhaps ulimit could be moved into a user library, as calls to
53 53 * getrlimit and setrlimit, were it not for binary compatibility
54 54 * restrictions.
55 55 */
56 56 long
57 57 ulimit(int cmd, long arg)
58 58 {
59 59 proc_t *p = curproc;
60 60 long retval;
61 61
62 62 switch (cmd) {
63 63
64 64 case UL_GFILLIM: /* Return current file size limit. */
65 65 {
66 66 rlim64_t filesize;
67 67
68 68 mutex_enter(&p->p_lock);
69 69 filesize = rctl_enforced_value(rctlproc_legacy[RLIMIT_FSIZE],
70 70 p->p_rctls, p);
71 71 mutex_exit(&p->p_lock);
72 72
73 73 if (get_udatamodel() == DATAMODEL_ILP32) {
74 74 /*
75 75 * File size is returned in blocks for ulimit.
76 76 * This function is deprecated and therefore LFS API
77 77 * didn't define the behaviour of ulimit.
78 78 * Here we return maximum value of file size possible
79 79 * so that applications that do not check errors
80 80 * continue to work.
81 81 */
82 82 if (filesize > MAXOFF32_T)
83 83 filesize = MAXOFF32_T;
84 84 retval = ((int)filesize >> SCTRSHFT);
85 85 } else
86 86 retval = filesize >> SCTRSHFT;
87 87 break;
88 88 }
89 89
90 90 case UL_SFILLIM: /* Set new file size limit. */
91 91 {
92 92 int error = 0;
93 93 rlim64_t lim = (rlim64_t)arg;
94 94 struct rlimit64 rl64;
95 95 rctl_alloc_gp_t *gp = rctl_rlimit_set_prealloc(1);
96 96
97 97 if (lim >= (((rlim64_t)MAXOFFSET_T) >> SCTRSHFT))
98 98 lim = (rlim64_t)RLIM64_INFINITY;
99 99 else
100 100 lim <<= SCTRSHFT;
101 101
102 102 rl64.rlim_max = rl64.rlim_cur = lim;
103 103 mutex_enter(&p->p_lock);
104 104 if (error = rctl_rlimit_set(rctlproc_legacy[RLIMIT_FSIZE], p,
105 105 &rl64, gp, RCTL_LOCAL_DENY | RCTL_LOCAL_SIGNAL, SIGXFSZ,
106 106 CRED())) {
107 107 mutex_exit(&p->p_lock);
108 108 rctl_prealloc_destroy(gp);
109 109 return (set_errno(error));
110 110 }
111 111 mutex_exit(&p->p_lock);
112 112 rctl_prealloc_destroy(gp);
113 113 retval = arg;
114 114 break;
115 115 }
116 116
117 117 case UL_GMEMLIM: /* Return maximum possible break value. */
118 118 {
119 119 struct seg *seg;
120 120 struct seg *nextseg;
121 121 struct as *as = p->p_as;
122 122 caddr_t brkend;
123 123 caddr_t brkbase;
124 124 size_t size;
125 125 rlim64_t size_ctl;
126 126 rlim64_t vmem_ctl;
127 127
128 128 /*
129 129 * Find the segment with a virtual address
130 130 * greater than the end of the current break.
131 131 */
132 132 nextseg = NULL;
133 133 mutex_enter(&p->p_lock);
↓ open down ↓ |
133 lines elided |
↑ open up ↑ |
134 134 brkbase = (caddr_t)p->p_brkbase;
135 135 brkend = (caddr_t)p->p_brkbase + p->p_brksize;
136 136 mutex_exit(&p->p_lock);
137 137
138 138 /*
139 139 * Since we can't return less than the current break,
140 140 * initialize the return value to the current break
141 141 */
142 142 retval = (long)brkend;
143 143
144 - AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
144 + AS_LOCK_ENTER(as, RW_READER);
145 145 for (seg = as_findseg(as, brkend, 0); seg != NULL;
146 146 seg = AS_SEGNEXT(as, seg)) {
147 147 if (seg->s_base >= brkend) {
148 148 nextseg = seg;
149 149 break;
150 150 }
151 151 }
152 152
153 153 mutex_enter(&p->p_lock);
154 154 size_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_DATA],
155 155 p->p_rctls, p);
156 156 vmem_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_VMEM],
157 157 p->p_rctls, p);
158 158 mutex_exit(&p->p_lock);
159 159
160 160 /*
161 161 * First, calculate the maximum break value based on
162 162 * the user's RLIMIT_DATA, but also taking into account
163 163 * that this value cannot be greater than as->a_userlimit.
164 164 * We also take care to make sure that we don't overflow
165 165 * in the calculation.
166 166 */
167 167 /*
168 168 * Since we are casting the RLIMIT_DATA value to a
169 169 * ulong (a 32-bit value in the 32-bit kernel) we have
170 170 * to pass this assertion.
171 171 */
172 172 ASSERT32((size_t)size_ctl <= UINT32_MAX);
173 173
174 174 size = (size_t)size_ctl;
175 175 if (as->a_userlimit - brkbase > size)
176 176 retval = MAX((size_t)retval, (size_t)(brkbase + size));
177 177 /* don't return less than current */
178 178 else
179 179 retval = (long)as->a_userlimit;
180 180
181 181 /*
182 182 * The max break cannot extend into the next segment
183 183 */
184 184 if (nextseg != NULL)
185 185 retval = MIN((uintptr_t)retval,
186 186 (uintptr_t)nextseg->s_base);
187 187
188 188 /*
189 189 * Handle the case where there is an limit on RLIMIT_VMEM
190 190 */
191 191 if (vmem_ctl < UINT64_MAX) {
192 192 /* calculate brkend based on the end of page */
193 193 caddr_t brkendpg = (caddr_t)roundup((uintptr_t)brkend,
194 194 PAGESIZE);
195 195 /*
196 196 * Large Files: The following assertion has to pass
197 197 * through to ensure the correctness of the cast.
198 198 */
199 199 ASSERT32(vmem_ctl <= UINT32_MAX);
200 200
201 201 size = (size_t)(vmem_ctl & PAGEMASK);
202 202
203 203 if (as->a_size < size)
204 204 size -= as->a_size;
↓ open down ↓ |
50 lines elided |
↑ open up ↑ |
205 205 else
206 206 size = 0;
207 207 /*
208 208 * Take care to not overflow the calculation
209 209 */
210 210 if (as->a_userlimit - brkendpg > size)
211 211 retval = MIN((size_t)retval,
212 212 (size_t)(brkendpg + size));
213 213 }
214 214
215 - AS_LOCK_EXIT(as, &as->a_lock);
215 + AS_LOCK_EXIT(as);
216 216
217 217 /* truncate to same boundary as sbrk */
218 218
219 219 switch (get_udatamodel()) {
220 220 default:
221 221 case DATAMODEL_ILP32:
222 222 retval = retval & ~(8-1);
223 223 break;
224 224 case DATAMODEL_LP64:
225 225 retval = retval & ~(16-1);
226 226 break;
227 227 }
228 228 break;
229 229 }
230 230
231 231 case UL_GDESLIM: /* Return approximate number of open files */
232 232 {
233 233 rlim64_t fdno_ctl;
234 234
235 235 mutex_enter(&curproc->p_lock);
236 236 fdno_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_NOFILE],
237 237 curproc->p_rctls, curproc);
238 238 ASSERT(fdno_ctl <= INT_MAX);
239 239 retval = (rlim_t)fdno_ctl;
240 240 mutex_exit(&curproc->p_lock);
241 241 break;
242 242 }
243 243
244 244 default:
245 245 return (set_errno(EINVAL));
246 246
247 247 }
248 248 return (retval);
249 249 }
250 250
251 251 #ifdef _SYSCALL32_IMPL
252 252
253 253 int
254 254 ulimit32(int cmd, int arg)
255 255 {
256 256 return ((int)ulimit(cmd, (long)arg));
257 257 }
258 258
259 259 #endif /* _SYSCALL32_IMPL */
260 260
261 261 #if defined(_ILP32) || defined(_SYSCALL32_IMPL)
262 262
263 263 /*
264 264 * Large Files: getrlimit returns RLIM_SAVED_CUR or RLIM_SAVED_MAX when
265 265 * rlim_cur or rlim_max is not representable in 32-bit rlim_t. These
266 266 * values are just tokens which will be used in setrlimit to set the
267 267 * correct limits. The current limits are saved in the saved_rlimit members
268 268 * in user structures when the token is returned. setrlimit restores
269 269 * the limit values to these saved values when the token is passed.
270 270 * Consider the following common scenario of the apps:
271 271 *
272 272 * limit = getrlimit();
273 273 * savedlimit = limit;
274 274 * limit = limit1;
275 275 * setrlimit(limit)
276 276 * // execute all processes in the new rlimit state.
277 277 * setrlimit(savedlimit) // restore the old values.
278 278 *
279 279 * Most apps don't check error returns from getrlimit or setrlimit
280 280 * and this is why we return tokens when the correct value
281 281 * cannot be represented in rlim_t. For more discussion refer to
282 282 * the LFS API document.
283 283 *
284 284 * In the 64-bit kernel, all existing resource limits are treated in this
285 285 * manner. In the 32-bit kernel, CPU time is treated equivalently to the
286 286 * file size limit above; the VM-related limits are not. The macro,
287 287 * RLIM_SAVED(x), returns true if the resource limit should be handled in
288 288 * this way on the current kernel.
289 289 */
290 290 int
291 291 getrlimit32(int resource, struct rlimit32 *rlp)
292 292 {
293 293 struct rlimit32 rlim32;
294 294 struct rlimit64 rlim64;
295 295 struct proc *p = curproc;
296 296 struct user *up = PTOU(p);
297 297 int savecur = 0;
298 298 int savemax = 0;
299 299
300 300 if (resource < 0 || resource >= RLIM_NLIMITS)
301 301 return (set_errno(EINVAL));
302 302
303 303 mutex_enter(&p->p_lock);
304 304 (void) rctl_rlimit_get(rctlproc_legacy[resource], p, &rlim64);
305 305 mutex_exit(&p->p_lock);
306 306
307 307 if (rlim64.rlim_max > (rlim64_t)UINT32_MAX) {
308 308
309 309 if (rlim64.rlim_max == RLIM64_INFINITY)
310 310 rlim32.rlim_max = RLIM32_INFINITY;
311 311 else {
312 312 savemax = 1;
313 313 rlim32.rlim_max = RLIM32_SAVED_MAX;
314 314 /*CONSTCOND*/
315 315 ASSERT(RLIM_SAVED(resource));
316 316 }
317 317
318 318 if (rlim64.rlim_cur == RLIM64_INFINITY)
319 319 rlim32.rlim_cur = RLIM32_INFINITY;
320 320 else if (rlim64.rlim_cur == rlim64.rlim_max) {
321 321 savecur = 1;
322 322 rlim32.rlim_cur = RLIM32_SAVED_MAX;
323 323 /*CONSTCOND*/
324 324 ASSERT(RLIM_SAVED(resource));
325 325 } else if (rlim64.rlim_cur > (rlim64_t)UINT32_MAX) {
326 326 savecur = 1;
327 327 rlim32.rlim_cur = RLIM32_SAVED_CUR;
328 328 /*CONSTCOND*/
329 329 ASSERT(RLIM_SAVED(resource));
330 330 } else
331 331 rlim32.rlim_cur = rlim64.rlim_cur;
332 332
333 333 /*
334 334 * save the current limits in user structure.
335 335 */
336 336 /*CONSTCOND*/
337 337 if (RLIM_SAVED(resource)) {
338 338 mutex_enter(&p->p_lock);
339 339 if (savemax)
340 340 up->u_saved_rlimit[resource].rlim_max =
341 341 rlim64.rlim_max;
342 342 if (savecur)
343 343 up->u_saved_rlimit[resource].rlim_cur =
344 344 rlim64.rlim_cur;
345 345 mutex_exit(&p->p_lock);
346 346 }
347 347 } else {
348 348 ASSERT(rlim64.rlim_cur <= (rlim64_t)UINT32_MAX);
349 349 rlim32.rlim_max = rlim64.rlim_max;
350 350 rlim32.rlim_cur = rlim64.rlim_cur;
351 351 }
352 352
353 353 if (copyout(&rlim32, rlp, sizeof (rlim32)))
354 354 return (set_errno(EFAULT));
355 355
356 356 return (0);
357 357 }
358 358
359 359 /*
360 360 * See comments above getrlimit32(). When the tokens are passed in the
361 361 * rlimit structure the values are considered equal to the values
362 362 * stored in saved_rlimit members of user structure.
363 363 * When the user passes RLIM_INFINITY to set the resource limit to
364 364 * unlimited internally understand this value as RLIM64_INFINITY and
365 365 * let rlimit() do the job.
366 366 */
367 367 int
368 368 setrlimit32(int resource, struct rlimit32 *rlp)
369 369 {
370 370 struct rlimit32 rlim32;
371 371 struct rlimit64 rlim64;
372 372 struct rlimit64 saved_rlim;
373 373 int error;
374 374 struct proc *p = ttoproc(curthread);
375 375 struct user *up = PTOU(p);
376 376 rctl_alloc_gp_t *gp;
377 377
378 378 if (resource < 0 || resource >= RLIM_NLIMITS)
379 379 return (set_errno(EINVAL));
380 380 if (copyin(rlp, &rlim32, sizeof (rlim32)))
381 381 return (set_errno(EFAULT));
382 382
383 383 gp = rctl_rlimit_set_prealloc(1);
384 384
385 385 /*
386 386 * Disallow resource limit tunnelling
387 387 */
388 388 /*CONSTCOND*/
389 389 if (RLIM_SAVED(resource)) {
390 390 mutex_enter(&p->p_lock);
391 391 saved_rlim = up->u_saved_rlimit[resource];
392 392 mutex_exit(&p->p_lock);
393 393 } else {
394 394 saved_rlim.rlim_max = (rlim64_t)rlim32.rlim_max;
395 395 saved_rlim.rlim_cur = (rlim64_t)rlim32.rlim_cur;
396 396 }
397 397
398 398 switch (rlim32.rlim_cur) {
399 399 case RLIM32_INFINITY:
400 400 rlim64.rlim_cur = RLIM64_INFINITY;
401 401 break;
402 402 case RLIM32_SAVED_CUR:
403 403 rlim64.rlim_cur = saved_rlim.rlim_cur;
404 404 break;
405 405 case RLIM32_SAVED_MAX:
406 406 rlim64.rlim_cur = saved_rlim.rlim_max;
407 407 break;
408 408 default:
409 409 rlim64.rlim_cur = (rlim64_t)rlim32.rlim_cur;
410 410 break;
411 411 }
412 412
413 413 switch (rlim32.rlim_max) {
414 414 case RLIM32_INFINITY:
415 415 rlim64.rlim_max = RLIM64_INFINITY;
416 416 break;
417 417 case RLIM32_SAVED_MAX:
418 418 rlim64.rlim_max = saved_rlim.rlim_max;
419 419 break;
420 420 case RLIM32_SAVED_CUR:
421 421 rlim64.rlim_max = saved_rlim.rlim_cur;
422 422 break;
423 423 default:
424 424 rlim64.rlim_max = (rlim64_t)rlim32.rlim_max;
425 425 break;
426 426 }
427 427
428 428 mutex_enter(&p->p_lock);
429 429 if (error = rctl_rlimit_set(rctlproc_legacy[resource], p, &rlim64, gp,
430 430 rctlproc_flags[resource], rctlproc_signals[resource], CRED())) {
431 431 mutex_exit(&p->p_lock);
432 432 rctl_prealloc_destroy(gp);
433 433 return (set_errno(error));
434 434 }
435 435 mutex_exit(&p->p_lock);
436 436 rctl_prealloc_destroy(gp);
437 437
438 438 return (0);
439 439 }
440 440
441 441 #endif /* _ILP32 && _SYSCALL32_IMPL */
442 442
443 443 int
444 444 getrlimit64(int resource, struct rlimit64 *rlp)
445 445 {
446 446 struct rlimit64 rlim64;
447 447 struct proc *p = ttoproc(curthread);
448 448
449 449 if (resource < 0 || resource >= RLIM_NLIMITS)
450 450 return (set_errno(EINVAL));
451 451
452 452 mutex_enter(&p->p_lock);
453 453 (void) rctl_rlimit_get(rctlproc_legacy[resource], p, &rlim64);
454 454 mutex_exit(&p->p_lock);
455 455
456 456 if (copyout(&rlim64, rlp, sizeof (rlim64)))
457 457 return (set_errno(EFAULT));
458 458 return (0);
459 459 }
460 460
461 461 int
462 462 setrlimit64(int resource, struct rlimit64 *rlp)
463 463 {
464 464 struct rlimit64 rlim64;
465 465 struct proc *p = ttoproc(curthread);
466 466 int error;
467 467 rctl_alloc_gp_t *gp;
468 468
469 469 if (resource < 0 || resource >= RLIM_NLIMITS)
470 470 return (set_errno(EINVAL));
471 471 if (copyin(rlp, &rlim64, sizeof (rlim64)))
472 472 return (set_errno(EFAULT));
473 473
474 474 gp = rctl_rlimit_set_prealloc(1);
475 475
476 476 mutex_enter(&p->p_lock);
477 477 if (error = rctl_rlimit_set(rctlproc_legacy[resource], p, &rlim64, gp,
478 478 rctlproc_flags[resource], rctlproc_signals[resource], CRED())) {
479 479 mutex_exit(&p->p_lock);
480 480 rctl_prealloc_destroy(gp);
481 481 return (set_errno(error));
482 482 }
483 483 mutex_exit(&p->p_lock);
484 484 rctl_prealloc_destroy(gp);
485 485 return (0);
486 486
487 487 }
↓ open down ↓ |
262 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX