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 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/inttypes.h>
34 #include <sys/sysmacros.h>
35 #include <sys/systm.h>
36 #include <sys/tuneable.h>
38 #include <sys/errno.h>
39 #include <sys/vnode.h>
42 #include <sys/resource.h>
43 #include <sys/ulimit.h>
44 #include <sys/debug.h>
50 * Perhaps ulimit could be moved into a user library, as calls to
51 * getrlimit and setrlimit, were it not for binary compatibility
55 ulimit(int cmd
, long arg
)
62 case UL_GFILLIM
: /* Return current file size limit. */
66 mutex_enter(&p
->p_lock
);
67 filesize
= rctl_enforced_value(rctlproc_legacy
[RLIMIT_FSIZE
],
69 mutex_exit(&p
->p_lock
);
71 if (get_udatamodel() == DATAMODEL_ILP32
) {
73 * File size is returned in blocks for ulimit.
74 * This function is deprecated and therefore LFS API
75 * didn't define the behaviour of ulimit.
76 * Here we return maximum value of file size possible
77 * so that applications that do not check errors
80 if (filesize
> MAXOFF32_T
)
81 filesize
= MAXOFF32_T
;
82 retval
= ((int)filesize
>> SCTRSHFT
);
84 retval
= filesize
>> SCTRSHFT
;
88 case UL_SFILLIM
: /* Set new file size limit. */
91 rlim64_t lim
= (rlim64_t
)arg
;
93 rctl_alloc_gp_t
*gp
= rctl_rlimit_set_prealloc(1);
95 if (lim
>= (((rlim64_t
)MAXOFFSET_T
) >> SCTRSHFT
))
96 lim
= (rlim64_t
)RLIM64_INFINITY
;
100 rl64
.rlim_max
= rl64
.rlim_cur
= lim
;
101 mutex_enter(&p
->p_lock
);
102 if (error
= rctl_rlimit_set(rctlproc_legacy
[RLIMIT_FSIZE
], p
,
103 &rl64
, gp
, RCTL_LOCAL_DENY
| RCTL_LOCAL_SIGNAL
, SIGXFSZ
,
105 mutex_exit(&p
->p_lock
);
106 rctl_prealloc_destroy(gp
);
107 return (set_errno(error
));
109 mutex_exit(&p
->p_lock
);
110 rctl_prealloc_destroy(gp
);
115 case UL_GMEMLIM
: /* Return maximum possible break value. */
119 struct as
*as
= p
->p_as
;
127 * Find the segment with a virtual address
128 * greater than the end of the current break.
131 mutex_enter(&p
->p_lock
);
132 brkbase
= (caddr_t
)p
->p_brkbase
;
133 brkend
= (caddr_t
)p
->p_brkbase
+ p
->p_brksize
;
134 mutex_exit(&p
->p_lock
);
137 * Since we can't return less than the current break,
138 * initialize the return value to the current break
140 retval
= (long)brkend
;
142 AS_LOCK_ENTER(as
, RW_READER
);
143 for (seg
= as_findseg(as
, brkend
, 0); seg
!= NULL
;
144 seg
= AS_SEGNEXT(as
, seg
)) {
145 if (seg
->s_base
>= brkend
) {
151 mutex_enter(&p
->p_lock
);
152 size_ctl
= rctl_enforced_value(rctlproc_legacy
[RLIMIT_DATA
],
154 vmem_ctl
= rctl_enforced_value(rctlproc_legacy
[RLIMIT_VMEM
],
156 mutex_exit(&p
->p_lock
);
159 * First, calculate the maximum break value based on
160 * the user's RLIMIT_DATA, but also taking into account
161 * that this value cannot be greater than as->a_userlimit.
162 * We also take care to make sure that we don't overflow
163 * in the calculation.
166 * Since we are casting the RLIMIT_DATA value to a
167 * ulong (a 32-bit value in the 32-bit kernel) we have
168 * to pass this assertion.
170 ASSERT32((size_t)size_ctl
<= UINT32_MAX
);
172 size
= (size_t)size_ctl
;
173 if (as
->a_userlimit
- brkbase
> size
)
174 retval
= MAX((size_t)retval
, (size_t)(brkbase
+ size
));
175 /* don't return less than current */
177 retval
= (long)as
->a_userlimit
;
180 * The max break cannot extend into the next segment
183 retval
= MIN((uintptr_t)retval
,
184 (uintptr_t)nextseg
->s_base
);
187 * Handle the case where there is an limit on RLIMIT_VMEM
189 if (vmem_ctl
< UINT64_MAX
) {
190 /* calculate brkend based on the end of page */
191 caddr_t brkendpg
= (caddr_t
)roundup((uintptr_t)brkend
,
194 * Large Files: The following assertion has to pass
195 * through to ensure the correctness of the cast.
197 ASSERT32(vmem_ctl
<= UINT32_MAX
);
199 size
= (size_t)(vmem_ctl
& PAGEMASK
);
201 if (as
->a_size
< size
)
206 * Take care to not overflow the calculation
208 if (as
->a_userlimit
- brkendpg
> size
)
209 retval
= MIN((size_t)retval
,
210 (size_t)(brkendpg
+ size
));
215 /* truncate to same boundary as sbrk */
217 switch (get_udatamodel()) {
219 case DATAMODEL_ILP32
:
220 retval
= retval
& ~(8-1);
223 retval
= retval
& ~(16-1);
229 case UL_GDESLIM
: /* Return approximate number of open files */
233 mutex_enter(&curproc
->p_lock
);
234 fdno_ctl
= rctl_enforced_value(rctlproc_legacy
[RLIMIT_NOFILE
],
235 curproc
->p_rctls
, curproc
);
236 ASSERT(fdno_ctl
<= INT_MAX
);
237 retval
= (rlim_t
)fdno_ctl
;
238 mutex_exit(&curproc
->p_lock
);
243 return (set_errno(EINVAL
));
249 #ifdef _SYSCALL32_IMPL
252 ulimit32(int cmd
, int arg
)
254 return ((int)ulimit(cmd
, (long)arg
));
257 #endif /* _SYSCALL32_IMPL */
259 #if defined(_ILP32) || defined(_SYSCALL32_IMPL)
262 * Large Files: getrlimit returns RLIM_SAVED_CUR or RLIM_SAVED_MAX when
263 * rlim_cur or rlim_max is not representable in 32-bit rlim_t. These
264 * values are just tokens which will be used in setrlimit to set the
265 * correct limits. The current limits are saved in the saved_rlimit members
266 * in user structures when the token is returned. setrlimit restores
267 * the limit values to these saved values when the token is passed.
268 * Consider the following common scenario of the apps:
270 * limit = getrlimit();
271 * savedlimit = limit;
274 * // execute all processes in the new rlimit state.
275 * setrlimit(savedlimit) // restore the old values.
277 * Most apps don't check error returns from getrlimit or setrlimit
278 * and this is why we return tokens when the correct value
279 * cannot be represented in rlim_t. For more discussion refer to
280 * the LFS API document.
282 * In the 64-bit kernel, all existing resource limits are treated in this
283 * manner. In the 32-bit kernel, CPU time is treated equivalently to the
284 * file size limit above; the VM-related limits are not. The macro,
285 * RLIM_SAVED(x), returns true if the resource limit should be handled in
286 * this way on the current kernel.
289 getrlimit32(int resource
, struct rlimit32
*rlp
)
291 struct rlimit32 rlim32
;
292 struct rlimit64 rlim64
;
293 struct proc
*p
= curproc
;
294 struct user
*up
= PTOU(p
);
298 if (resource
< 0 || resource
>= RLIM_NLIMITS
)
299 return (set_errno(EINVAL
));
301 mutex_enter(&p
->p_lock
);
302 (void) rctl_rlimit_get(rctlproc_legacy
[resource
], p
, &rlim64
);
303 mutex_exit(&p
->p_lock
);
305 if (rlim64
.rlim_max
> (rlim64_t
)UINT32_MAX
) {
307 if (rlim64
.rlim_max
== RLIM64_INFINITY
)
308 rlim32
.rlim_max
= RLIM32_INFINITY
;
311 rlim32
.rlim_max
= RLIM32_SAVED_MAX
;
313 ASSERT(RLIM_SAVED(resource
));
316 if (rlim64
.rlim_cur
== RLIM64_INFINITY
)
317 rlim32
.rlim_cur
= RLIM32_INFINITY
;
318 else if (rlim64
.rlim_cur
== rlim64
.rlim_max
) {
320 rlim32
.rlim_cur
= RLIM32_SAVED_MAX
;
322 ASSERT(RLIM_SAVED(resource
));
323 } else if (rlim64
.rlim_cur
> (rlim64_t
)UINT32_MAX
) {
325 rlim32
.rlim_cur
= RLIM32_SAVED_CUR
;
327 ASSERT(RLIM_SAVED(resource
));
329 rlim32
.rlim_cur
= rlim64
.rlim_cur
;
332 * save the current limits in user structure.
335 if (RLIM_SAVED(resource
)) {
336 mutex_enter(&p
->p_lock
);
338 up
->u_saved_rlimit
[resource
].rlim_max
=
341 up
->u_saved_rlimit
[resource
].rlim_cur
=
343 mutex_exit(&p
->p_lock
);
346 ASSERT(rlim64
.rlim_cur
<= (rlim64_t
)UINT32_MAX
);
347 rlim32
.rlim_max
= rlim64
.rlim_max
;
348 rlim32
.rlim_cur
= rlim64
.rlim_cur
;
351 if (copyout(&rlim32
, rlp
, sizeof (rlim32
)))
352 return (set_errno(EFAULT
));
358 * See comments above getrlimit32(). When the tokens are passed in the
359 * rlimit structure the values are considered equal to the values
360 * stored in saved_rlimit members of user structure.
361 * When the user passes RLIM_INFINITY to set the resource limit to
362 * unlimited internally understand this value as RLIM64_INFINITY and
363 * let rlimit() do the job.
366 setrlimit32(int resource
, struct rlimit32
*rlp
)
368 struct rlimit32 rlim32
;
369 struct rlimit64 rlim64
;
370 struct rlimit64 saved_rlim
;
372 struct proc
*p
= ttoproc(curthread
);
373 struct user
*up
= PTOU(p
);
376 if (resource
< 0 || resource
>= RLIM_NLIMITS
)
377 return (set_errno(EINVAL
));
378 if (copyin(rlp
, &rlim32
, sizeof (rlim32
)))
379 return (set_errno(EFAULT
));
381 gp
= rctl_rlimit_set_prealloc(1);
384 * Disallow resource limit tunnelling
387 if (RLIM_SAVED(resource
)) {
388 mutex_enter(&p
->p_lock
);
389 saved_rlim
= up
->u_saved_rlimit
[resource
];
390 mutex_exit(&p
->p_lock
);
392 saved_rlim
.rlim_max
= (rlim64_t
)rlim32
.rlim_max
;
393 saved_rlim
.rlim_cur
= (rlim64_t
)rlim32
.rlim_cur
;
396 switch (rlim32
.rlim_cur
) {
397 case RLIM32_INFINITY
:
398 rlim64
.rlim_cur
= RLIM64_INFINITY
;
400 case RLIM32_SAVED_CUR
:
401 rlim64
.rlim_cur
= saved_rlim
.rlim_cur
;
403 case RLIM32_SAVED_MAX
:
404 rlim64
.rlim_cur
= saved_rlim
.rlim_max
;
407 rlim64
.rlim_cur
= (rlim64_t
)rlim32
.rlim_cur
;
411 switch (rlim32
.rlim_max
) {
412 case RLIM32_INFINITY
:
413 rlim64
.rlim_max
= RLIM64_INFINITY
;
415 case RLIM32_SAVED_MAX
:
416 rlim64
.rlim_max
= saved_rlim
.rlim_max
;
418 case RLIM32_SAVED_CUR
:
419 rlim64
.rlim_max
= saved_rlim
.rlim_cur
;
422 rlim64
.rlim_max
= (rlim64_t
)rlim32
.rlim_max
;
426 mutex_enter(&p
->p_lock
);
427 if (error
= rctl_rlimit_set(rctlproc_legacy
[resource
], p
, &rlim64
, gp
,
428 rctlproc_flags
[resource
], rctlproc_signals
[resource
], CRED())) {
429 mutex_exit(&p
->p_lock
);
430 rctl_prealloc_destroy(gp
);
431 return (set_errno(error
));
433 mutex_exit(&p
->p_lock
);
434 rctl_prealloc_destroy(gp
);
439 #endif /* _ILP32 && _SYSCALL32_IMPL */
442 getrlimit64(int resource
, struct rlimit64
*rlp
)
444 struct rlimit64 rlim64
;
445 struct proc
*p
= ttoproc(curthread
);
447 if (resource
< 0 || resource
>= RLIM_NLIMITS
)
448 return (set_errno(EINVAL
));
450 mutex_enter(&p
->p_lock
);
451 (void) rctl_rlimit_get(rctlproc_legacy
[resource
], p
, &rlim64
);
452 mutex_exit(&p
->p_lock
);
454 if (copyout(&rlim64
, rlp
, sizeof (rlim64
)))
455 return (set_errno(EFAULT
));
460 setrlimit64(int resource
, struct rlimit64
*rlp
)
462 struct rlimit64 rlim64
;
463 struct proc
*p
= ttoproc(curthread
);
467 if (resource
< 0 || resource
>= RLIM_NLIMITS
)
468 return (set_errno(EINVAL
));
469 if (copyin(rlp
, &rlim64
, sizeof (rlim64
)))
470 return (set_errno(EFAULT
));
472 gp
= rctl_rlimit_set_prealloc(1);
474 mutex_enter(&p
->p_lock
);
475 if (error
= rctl_rlimit_set(rctlproc_legacy
[resource
], p
, &rlim64
, gp
,
476 rctlproc_flags
[resource
], rctlproc_signals
[resource
], CRED())) {
477 mutex_exit(&p
->p_lock
);
478 rctl_prealloc_destroy(gp
);
479 return (set_errno(error
));
481 mutex_exit(&p
->p_lock
);
482 rctl_prealloc_destroy(gp
);