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 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/acctctl.h>
30 #include <sys/cmn_err.h>
32 #include <sys/errno.h>
33 #include <sys/exacct.h>
34 #include <sys/modctl.h>
35 #include <sys/procset.h>
36 #include <sys/sysmacros.h>
37 #include <sys/systm.h>
39 #include <sys/types.h>
41 #include <sys/policy.h>
44 * getacct(2), putacct(2), and wracct(2) system calls
46 * The extended accounting subsystem provides three root-privileged system
47 * calls for interacting with the actual resource data associated with each
48 * task or process. getacct() copies a packed exacct record reflecting the
49 * resource usage out to the buffer provided by the user. wracct() writes a
50 * record to the appropriate extended accounting file. putacct() takes the
51 * buffer provided by the user, and appends a "tag" record associated with the
52 * specified task or project that encapsulates the user data. All three of
53 * these functions exit early if extended accounting is not active for the
54 * requested entity type.
57 * Under the terminology introduced in os/task.c, all three of these system
58 * calls are task observers, when executing on an existing task.
62 * getacct_callback() is used to copyout the buffer with accounting records
63 * from the kernel back to the user. It also sets actual to the size of the
64 * kernel buffer--the required minimum size for a successful outbound copy.
68 getacct_callback(ac_info_t
*unused
, void *ubuf
, size_t usize
, void *kbuf
,
69 size_t ksize
, size_t *actual
)
71 size_t size
= MIN(usize
, ksize
);
73 if (ubuf
!= NULL
&& copyout(kbuf
, ubuf
, size
) != 0)
80 getacct_task(ac_info_t
*ac_task
, taskid_t tkid
, void *buf
, size_t bufsize
,
86 mutex_enter(&ac_task
->ac_lock
);
87 if (ac_task
->ac_state
== AC_OFF
) {
88 mutex_exit(&ac_task
->ac_lock
);
91 mutex_exit(&ac_task
->ac_lock
);
93 if ((tk
= task_hold_by_id(tkid
)) == NULL
)
95 error
= exacct_assemble_task_usage(ac_task
, tk
,
96 getacct_callback
, buf
, bufsize
, sizep
, EW_PARTIAL
);
103 getacct_proc(ac_info_t
*ac_proc
, pid_t pid
, void *buf
, size_t bufsize
,
108 ulong_t mask
[AC_MASK_SZ
];
109 ulong_t
*ac_mask
= &mask
[0];
112 mutex_enter(&ac_proc
->ac_lock
);
113 if (ac_proc
->ac_state
== AC_OFF
) {
114 mutex_exit(&ac_proc
->ac_lock
);
117 bt_copy(&ac_proc
->ac_mask
[0], ac_mask
, AC_MASK_SZ
);
118 mutex_exit(&ac_proc
->ac_lock
);
120 pu
= kmem_zalloc(sizeof (proc_usage_t
), KM_SLEEP
);
121 pu
->pu_command
= kmem_zalloc(MAXCOMLEN
+ 1, KM_SLEEP
);
123 mutex_enter(&pidlock
);
124 if ((p
= prfind(pid
)) == NULL
) {
125 mutex_exit(&pidlock
);
126 kmem_free(pu
->pu_command
, MAXCOMLEN
+ 1);
127 kmem_free(pu
, sizeof (proc_usage_t
));
130 mutex_enter(&p
->p_lock
);
131 mutex_exit(&pidlock
);
133 exacct_calculate_proc_usage(p
, pu
, ac_mask
, EW_PARTIAL
, 0);
134 mutex_exit(&p
->p_lock
);
136 error
= exacct_assemble_proc_usage(ac_proc
, pu
,
137 getacct_callback
, buf
, bufsize
, sizep
, EW_PARTIAL
);
139 kmem_free(pu
->pu_command
, MAXCOMLEN
+ 1);
140 kmem_free(pu
, sizeof (proc_usage_t
));
146 getacct(idtype_t idtype
, id_t id
, void *buf
, size_t bufsize
)
150 struct exacct_globals
*acg
;
152 if (bufsize
> EXACCT_MAX_BUFSIZE
)
153 bufsize
= EXACCT_MAX_BUFSIZE
;
155 acg
= zone_getspecific(exacct_zone_key
, curproc
->p_zone
);
158 error
= getacct_proc(&acg
->ac_proc
, id
, buf
, bufsize
, &size
);
161 error
= getacct_task(&acg
->ac_task
, id
, buf
, bufsize
, &size
);
167 return (error
== 0 ? (ssize_t
)size
: set_errno(error
));
171 putacct(idtype_t idtype
, id_t id
, void *buf
, size_t bufsize
, int flags
)
178 struct exacct_globals
*acg
;
180 if (bufsize
== 0 || bufsize
> EXACCT_MAX_BUFSIZE
)
181 return (set_errno(EINVAL
));
183 kbuf
= kmem_alloc(bufsize
, KM_SLEEP
);
184 if (copyin(buf
, kbuf
, bufsize
) != 0) {
189 acg
= zone_getspecific(exacct_zone_key
, curproc
->p_zone
);
192 mutex_enter(&pidlock
);
193 if ((p
= prfind(id
)) == NULL
) {
194 mutex_exit(&pidlock
);
197 zone_t
*zone
= p
->p_zone
;
199 tkid
= p
->p_task
->tk_tkid
;
201 mutex_exit(&pidlock
);
203 error
= exacct_tag_proc(&acg
->ac_proc
, id
, tkid
, kbuf
,
204 bufsize
, flags
, zone
->zone_nodename
);
209 if ((tk
= task_hold_by_id(id
)) != NULL
) {
210 error
= exacct_tag_task(&acg
->ac_task
, tk
, kbuf
,
222 kmem_free(kbuf
, bufsize
);
223 return (error
== 0 ? error
: set_errno(error
));
227 wracct_task(ac_info_t
*ac_task
, taskid_t tkid
, int flag
, size_t *sizep
)
232 mutex_enter(&ac_task
->ac_lock
);
233 if (ac_task
->ac_state
== AC_OFF
|| ac_task
->ac_vnode
== NULL
) {
234 mutex_exit(&ac_task
->ac_lock
);
237 mutex_exit(&ac_task
->ac_lock
);
239 if ((tk
= task_hold_by_id(tkid
)) == NULL
)
241 error
= exacct_assemble_task_usage(ac_task
, tk
, exacct_commit_callback
,
242 NULL
, 0, sizep
, flag
);
249 wracct_proc(ac_info_t
*ac_proc
, pid_t pid
, int flag
, size_t *sizep
)
253 ulong_t mask
[AC_MASK_SZ
];
254 ulong_t
*ac_mask
= &mask
[0];
257 mutex_enter(&ac_proc
->ac_lock
);
258 if (ac_proc
->ac_state
== AC_OFF
|| ac_proc
->ac_vnode
== NULL
) {
259 mutex_exit(&ac_proc
->ac_lock
);
262 bt_copy(&ac_proc
->ac_mask
[0], ac_mask
, AC_MASK_SZ
);
263 mutex_exit(&ac_proc
->ac_lock
);
265 pu
= kmem_zalloc(sizeof (proc_usage_t
), KM_SLEEP
);
266 pu
->pu_command
= kmem_zalloc(MAXCOMLEN
+ 1, KM_SLEEP
);
268 mutex_enter(&pidlock
);
269 if ((p
= prfind(pid
)) == NULL
) {
270 mutex_exit(&pidlock
);
271 kmem_free(pu
->pu_command
, MAXCOMLEN
+ 1);
272 kmem_free(pu
, sizeof (proc_usage_t
));
275 mutex_enter(&p
->p_lock
);
276 mutex_exit(&pidlock
);
277 exacct_calculate_proc_usage(p
, pu
, ac_mask
, flag
, 0);
278 mutex_exit(&p
->p_lock
);
280 error
= exacct_assemble_proc_usage(ac_proc
, pu
,
281 exacct_commit_callback
, NULL
, 0, sizep
, flag
);
283 kmem_free(pu
->pu_command
, MAXCOMLEN
+ 1);
284 kmem_free(pu
, sizeof (proc_usage_t
));
290 wracct(idtype_t idtype
, id_t id
, int flags
)
294 struct exacct_globals
*acg
;
304 return (set_errno(EINVAL
));
307 acg
= zone_getspecific(exacct_zone_key
, curproc
->p_zone
);
310 if (flags
== EW_INTERVAL
)
311 return (set_errno(ENOTSUP
));
312 error
= wracct_proc(&acg
->ac_proc
, id
, flags
, &size
);
315 error
= wracct_task(&acg
->ac_task
, id
, flags
, &size
);
322 return (error
== 0 ? error
: set_errno(error
));
326 exacct(int code
, idtype_t idtype
, id_t id
, void *buf
, size_t bufsize
,
329 if (secpolicy_acct(CRED()) != 0)
330 return (set_errno(EPERM
));
332 if (exacct_zone_key
== ZONE_KEY_UNINITIALIZED
)
333 return (set_errno(ENOTACTIVE
));
337 return (getacct(idtype
, id
, buf
, bufsize
));
339 return (putacct(idtype
, id
, buf
, bufsize
, flags
));
341 return (wracct(idtype
, id
, flags
));
343 return (set_errno(EINVAL
));
348 #define SE_LRVAL SE_64RVAL
350 #define SE_LRVAL SE_32RVAL1
353 static struct sysent exacctsys_sysent
= {
355 SE_NOUNLOAD
| SE_ARGC
| SE_LRVAL
,
359 static struct modlsys modlsys
= {
361 "extended accounting facility",
365 #ifdef _SYSCALL32_IMPL
367 static struct sysent exacctsys_sysent32
= {
369 SE_NOUNLOAD
| SE_ARGC
| SE_32RVAL1
,
373 static struct modlsys modlsys32
= {
375 "32-bit extended accounting facility",
381 static struct modlinkage modlinkage
= {
384 #ifdef _SYSCALL32_IMPL
393 return (mod_install(&modlinkage
));
399 return (mod_remove(&modlinkage
));
403 _info(struct modinfo
*mip
)
405 return (mod_info(&modlinkage
, mip
));