4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/inttypes.h>
36 #include <sys/sysmacros.h>
37 #include <sys/systm.h>
38 #include <sys/tuneable.h>
40 #include <sys/errno.h>
41 #include <sys/vnode.h>
44 #include <sys/resource.h>
45 #include <sys/ulimit.h>
46 #include <sys/debug.h>
52 * Perhaps ulimit could be moved into a user library, as calls to
53 * getrlimit and setrlimit, were it not for binary compatibility
57 ulimit(int cmd
, long arg
)
64 case UL_GFILLIM
: /* Return current file size limit. */
68 mutex_enter(&p
->p_lock
);
69 filesize
= rctl_enforced_value(rctlproc_legacy
[RLIMIT_FSIZE
],
71 mutex_exit(&p
->p_lock
);
73 if (get_udatamodel() == DATAMODEL_ILP32
) {
75 * File size is returned in blocks for ulimit.
76 * This function is deprecated and therefore LFS API
77 * didn't define the behaviour of ulimit.
78 * Here we return maximum value of file size possible
79 * so that applications that do not check errors
82 if (filesize
> MAXOFF32_T
)
83 filesize
= MAXOFF32_T
;
84 retval
= ((int)filesize
>> SCTRSHFT
);
86 retval
= filesize
>> SCTRSHFT
;
90 case UL_SFILLIM
: /* Set new file size limit. */
93 rlim64_t lim
= (rlim64_t
)arg
;
95 rctl_alloc_gp_t
*gp
= rctl_rlimit_set_prealloc(1);
97 if (lim
>= (((rlim64_t
)MAXOFFSET_T
) >> SCTRSHFT
))
98 lim
= (rlim64_t
)RLIM64_INFINITY
;
102 rl64
.rlim_max
= rl64
.rlim_cur
= lim
;
103 mutex_enter(&p
->p_lock
);
104 if (error
= rctl_rlimit_set(rctlproc_legacy
[RLIMIT_FSIZE
], p
,
105 &rl64
, gp
, RCTL_LOCAL_DENY
| RCTL_LOCAL_SIGNAL
, SIGXFSZ
,
107 mutex_exit(&p
->p_lock
);
108 rctl_prealloc_destroy(gp
);
109 return (set_errno(error
));
111 mutex_exit(&p
->p_lock
);
112 rctl_prealloc_destroy(gp
);
117 case UL_GMEMLIM
: /* Return maximum possible break value. */
121 struct as
*as
= p
->p_as
;
129 * Find the segment with a virtual address
130 * greater than the end of the current break.
133 mutex_enter(&p
->p_lock
);
134 brkbase
= (caddr_t
)p
->p_brkbase
;
135 brkend
= (caddr_t
)p
->p_brkbase
+ p
->p_brksize
;
136 mutex_exit(&p
->p_lock
);
139 * Since we can't return less than the current break,
140 * initialize the return value to the current break
142 retval
= (long)brkend
;
144 AS_LOCK_ENTER(as
, &as
->a_lock
, RW_READER
);
145 for (seg
= as_findseg(as
, brkend
, 0); seg
!= NULL
;
146 seg
= AS_SEGNEXT(as
, seg
)) {
147 if (seg
->s_base
>= brkend
) {
153 mutex_enter(&p
->p_lock
);
154 size_ctl
= rctl_enforced_value(rctlproc_legacy
[RLIMIT_DATA
],
156 vmem_ctl
= rctl_enforced_value(rctlproc_legacy
[RLIMIT_VMEM
],
158 mutex_exit(&p
->p_lock
);
161 * First, calculate the maximum break value based on
162 * the user's RLIMIT_DATA, but also taking into account
163 * that this value cannot be greater than as->a_userlimit.
164 * We also take care to make sure that we don't overflow
165 * in the calculation.
168 * Since we are casting the RLIMIT_DATA value to a
169 * ulong (a 32-bit value in the 32-bit kernel) we have
170 * to pass this assertion.
172 ASSERT32((size_t)size_ctl
<= UINT32_MAX
);
174 size
= (size_t)size_ctl
;
175 if (as
->a_userlimit
- brkbase
> size
)
176 retval
= MAX((size_t)retval
, (size_t)(brkbase
+ size
));
177 /* don't return less than current */
179 retval
= (long)as
->a_userlimit
;
182 * The max break cannot extend into the next segment
185 retval
= MIN((uintptr_t)retval
,
186 (uintptr_t)nextseg
->s_base
);
189 * Handle the case where there is an limit on RLIMIT_VMEM
191 if (vmem_ctl
< UINT64_MAX
) {
192 /* calculate brkend based on the end of page */
193 caddr_t brkendpg
= (caddr_t
)roundup((uintptr_t)brkend
,
196 * Large Files: The following assertion has to pass
197 * through to ensure the correctness of the cast.
199 ASSERT32(vmem_ctl
<= UINT32_MAX
);
201 size
= (size_t)(vmem_ctl
& PAGEMASK
);
203 if (as
->a_size
< size
)
208 * Take care to not overflow the calculation
210 if (as
->a_userlimit
- brkendpg
> size
)
211 retval
= MIN((size_t)retval
,
212 (size_t)(brkendpg
+ size
));
215 AS_LOCK_EXIT(as
, &as
->a_lock
);
217 /* truncate to same boundary as sbrk */
219 switch (get_udatamodel()) {
221 case DATAMODEL_ILP32
:
222 retval
= retval
& ~(8-1);
225 retval
= retval
& ~(16-1);
231 case UL_GDESLIM
: /* Return approximate number of open files */
235 mutex_enter(&curproc
->p_lock
);
236 fdno_ctl
= rctl_enforced_value(rctlproc_legacy
[RLIMIT_NOFILE
],
237 curproc
->p_rctls
, curproc
);
238 ASSERT(fdno_ctl
<= INT_MAX
);
239 retval
= (rlim_t
)fdno_ctl
;
240 mutex_exit(&curproc
->p_lock
);
245 return (set_errno(EINVAL
));
251 #ifdef _SYSCALL32_IMPL
254 ulimit32(int cmd
, int arg
)
256 return ((int)ulimit(cmd
, (long)arg
));
259 #endif /* _SYSCALL32_IMPL */
261 #if defined(_ILP32) || defined(_SYSCALL32_IMPL)
264 * Large Files: getrlimit returns RLIM_SAVED_CUR or RLIM_SAVED_MAX when
265 * rlim_cur or rlim_max is not representable in 32-bit rlim_t. These
266 * values are just tokens which will be used in setrlimit to set the
267 * correct limits. The current limits are saved in the saved_rlimit members
268 * in user structures when the token is returned. setrlimit restores
269 * the limit values to these saved values when the token is passed.
270 * Consider the following common scenario of the apps:
272 * limit = getrlimit();
273 * savedlimit = limit;
276 * // execute all processes in the new rlimit state.
277 * setrlimit(savedlimit) // restore the old values.
279 * Most apps don't check error returns from getrlimit or setrlimit
280 * and this is why we return tokens when the correct value
281 * cannot be represented in rlim_t. For more discussion refer to
282 * the LFS API document.
284 * In the 64-bit kernel, all existing resource limits are treated in this
285 * manner. In the 32-bit kernel, CPU time is treated equivalently to the
286 * file size limit above; the VM-related limits are not. The macro,
287 * RLIM_SAVED(x), returns true if the resource limit should be handled in
288 * this way on the current kernel.
291 getrlimit32(int resource
, struct rlimit32
*rlp
)
293 struct rlimit32 rlim32
;
294 struct rlimit64 rlim64
;
295 struct proc
*p
= curproc
;
296 struct user
*up
= PTOU(p
);
300 if (resource
< 0 || resource
>= RLIM_NLIMITS
)
301 return (set_errno(EINVAL
));
303 mutex_enter(&p
->p_lock
);
304 (void) rctl_rlimit_get(rctlproc_legacy
[resource
], p
, &rlim64
);
305 mutex_exit(&p
->p_lock
);
307 if (rlim64
.rlim_max
> (rlim64_t
)UINT32_MAX
) {
309 if (rlim64
.rlim_max
== RLIM64_INFINITY
)
310 rlim32
.rlim_max
= RLIM32_INFINITY
;
313 rlim32
.rlim_max
= RLIM32_SAVED_MAX
;
315 ASSERT(RLIM_SAVED(resource
));
318 if (rlim64
.rlim_cur
== RLIM64_INFINITY
)
319 rlim32
.rlim_cur
= RLIM32_INFINITY
;
320 else if (rlim64
.rlim_cur
== rlim64
.rlim_max
) {
322 rlim32
.rlim_cur
= RLIM32_SAVED_MAX
;
324 ASSERT(RLIM_SAVED(resource
));
325 } else if (rlim64
.rlim_cur
> (rlim64_t
)UINT32_MAX
) {
327 rlim32
.rlim_cur
= RLIM32_SAVED_CUR
;
329 ASSERT(RLIM_SAVED(resource
));
331 rlim32
.rlim_cur
= rlim64
.rlim_cur
;
334 * save the current limits in user structure.
337 if (RLIM_SAVED(resource
)) {
338 mutex_enter(&p
->p_lock
);
340 up
->u_saved_rlimit
[resource
].rlim_max
=
343 up
->u_saved_rlimit
[resource
].rlim_cur
=
345 mutex_exit(&p
->p_lock
);
348 ASSERT(rlim64
.rlim_cur
<= (rlim64_t
)UINT32_MAX
);
349 rlim32
.rlim_max
= rlim64
.rlim_max
;
350 rlim32
.rlim_cur
= rlim64
.rlim_cur
;
353 if (copyout(&rlim32
, rlp
, sizeof (rlim32
)))
354 return (set_errno(EFAULT
));
360 * See comments above getrlimit32(). When the tokens are passed in the
361 * rlimit structure the values are considered equal to the values
362 * stored in saved_rlimit members of user structure.
363 * When the user passes RLIM_INFINITY to set the resource limit to
364 * unlimited internally understand this value as RLIM64_INFINITY and
365 * let rlimit() do the job.
368 setrlimit32(int resource
, struct rlimit32
*rlp
)
370 struct rlimit32 rlim32
;
371 struct rlimit64 rlim64
;
372 struct rlimit64 saved_rlim
;
374 struct proc
*p
= ttoproc(curthread
);
375 struct user
*up
= PTOU(p
);
378 if (resource
< 0 || resource
>= RLIM_NLIMITS
)
379 return (set_errno(EINVAL
));
380 if (copyin(rlp
, &rlim32
, sizeof (rlim32
)))
381 return (set_errno(EFAULT
));
383 gp
= rctl_rlimit_set_prealloc(1);
386 * Disallow resource limit tunnelling
389 if (RLIM_SAVED(resource
)) {
390 mutex_enter(&p
->p_lock
);
391 saved_rlim
= up
->u_saved_rlimit
[resource
];
392 mutex_exit(&p
->p_lock
);
394 saved_rlim
.rlim_max
= (rlim64_t
)rlim32
.rlim_max
;
395 saved_rlim
.rlim_cur
= (rlim64_t
)rlim32
.rlim_cur
;
398 switch (rlim32
.rlim_cur
) {
399 case RLIM32_INFINITY
:
400 rlim64
.rlim_cur
= RLIM64_INFINITY
;
402 case RLIM32_SAVED_CUR
:
403 rlim64
.rlim_cur
= saved_rlim
.rlim_cur
;
405 case RLIM32_SAVED_MAX
:
406 rlim64
.rlim_cur
= saved_rlim
.rlim_max
;
409 rlim64
.rlim_cur
= (rlim64_t
)rlim32
.rlim_cur
;
413 switch (rlim32
.rlim_max
) {
414 case RLIM32_INFINITY
:
415 rlim64
.rlim_max
= RLIM64_INFINITY
;
417 case RLIM32_SAVED_MAX
:
418 rlim64
.rlim_max
= saved_rlim
.rlim_max
;
420 case RLIM32_SAVED_CUR
:
421 rlim64
.rlim_max
= saved_rlim
.rlim_cur
;
424 rlim64
.rlim_max
= (rlim64_t
)rlim32
.rlim_max
;
428 mutex_enter(&p
->p_lock
);
429 if (error
= rctl_rlimit_set(rctlproc_legacy
[resource
], p
, &rlim64
, gp
,
430 rctlproc_flags
[resource
], rctlproc_signals
[resource
], CRED())) {
431 mutex_exit(&p
->p_lock
);
432 rctl_prealloc_destroy(gp
);
433 return (set_errno(error
));
435 mutex_exit(&p
->p_lock
);
436 rctl_prealloc_destroy(gp
);
441 #endif /* _ILP32 && _SYSCALL32_IMPL */
444 getrlimit64(int resource
, struct rlimit64
*rlp
)
446 struct rlimit64 rlim64
;
447 struct proc
*p
= ttoproc(curthread
);
449 if (resource
< 0 || resource
>= RLIM_NLIMITS
)
450 return (set_errno(EINVAL
));
452 mutex_enter(&p
->p_lock
);
453 (void) rctl_rlimit_get(rctlproc_legacy
[resource
], p
, &rlim64
);
454 mutex_exit(&p
->p_lock
);
456 if (copyout(&rlim64
, rlp
, sizeof (rlim64
)))
457 return (set_errno(EFAULT
));
462 setrlimit64(int resource
, struct rlimit64
*rlp
)
464 struct rlimit64 rlim64
;
465 struct proc
*p
= ttoproc(curthread
);
469 if (resource
< 0 || resource
>= RLIM_NLIMITS
)
470 return (set_errno(EINVAL
));
471 if (copyin(rlp
, &rlim64
, sizeof (rlim64
)))
472 return (set_errno(EFAULT
));
474 gp
= rctl_rlimit_set_prealloc(1);
476 mutex_enter(&p
->p_lock
);
477 if (error
= rctl_rlimit_set(rctlproc_legacy
[resource
], p
, &rlim64
, gp
,
478 rctlproc_flags
[resource
], rctlproc_signals
[resource
], CRED())) {
479 mutex_exit(&p
->p_lock
);
480 rctl_prealloc_destroy(gp
);
481 return (set_errno(error
));
483 mutex_exit(&p
->p_lock
);
484 rctl_prealloc_destroy(gp
);