/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/exacct_catalog.h>
#include <sys/sysmacros.h>
/*
* exacct usage and recording routines
*
* wracct(2), getacct(2), and the records written at process or task
* termination are constructed using the exacct_assemble_[task,proc]_usage()
* functions, which take a callback that takes the appropriate action on
* the packed exacct record for the task or process. For the process-related
* actions, we partition the routines such that the data collecting component
* can be performed while holding p_lock, and all sleeping or blocking
* operations can be performed without acquiring p_lock.
*
* putacct(2), which allows an application to construct a customized record
* associated with an existing process or task, has its own entry points:
* exacct_tag_task() and exacct_tag_proc().
*/
{
return (item);
}
{
return (group);
}
{
return (item);
}
/*
* exacct_add_task_mstate() and exacct_sub_task_mstate() add and subtract
* microstate accounting data and resource usage counters from one task_usage_t
* from those supplied in another. These functions do not operate on *all*
* members of a task_usage_t: for some (e.g. tu_anctaskid) it would not make
* sense.
*/
static void
{
}
/*
* See the comments for exacct_add_task_mstate(), above.
*/
static void
{
}
/*
* Wrapper for vn_rdwr() used by exacct_vn_write() and exacct_write_header()
* to write to the accounting file without corrupting it in case of an I/O or
* filesystem error.
*/
static int
{
int error;
/*
* Save the size. If vn_rdwr fails, reset the size to avoid corrupting
* the present accounting file.
*/
if (error == 0) {
if (error) {
} else if (resid != 0) {
}
}
return (error);
}
/*
* exacct_vn_write() safely writes to an accounting file. acctctl() prevents
* the two accounting vnodes from being equal, and the appropriate ac_lock is
* held across the call, so we're single threaded through this code for each
* file.
*/
static int
{
int error;
return (0);
/*
* Don't do anything unless accounting file is set.
*/
return (0);
}
return (error);
}
/*
* void *exacct_create_header(size_t *)
*
* Overview
* exacct_create_header() constructs an exacct file header identifying the
* accounting file as the output of the kernel. exacct_create_header() and
* the static write_header() and verify_header() routines in libexacct must
* remain synchronized.
*
* Return values
* A pointer to a packed exacct buffer containing the appropriate header is
* returned; the size of the buffer is placed in the location indicated by
* sizep.
*
* Caller's context
* Suitable for KM_SLEEP allocations.
*/
void *
{
void *buf;
/*
* To prevent reading the header when reading the file backwards,
* set the large backskip of the header group to 0 (last 4 bytes).
*/
bskip = 0;
sizeof (bskip));
return (buf);
}
/*
* int exacct_write_header(ac_info_t *, void *, size_t)
*
* Overview
* exacct_write_header() writes the given header buffer to the indicated
* vnode.
*
* Return values
* The result of the write operation is returned.
*
* Caller's context
* Caller must hold the ac_lock of the appropriate accounting file
* information block (ac_info_t).
*/
int
{
return (0);
}
static void
{
if (getzoneid() != GLOBAL_ZONEID) {
} else {
}
/*
* In case we have any accounting information
* saved from the previous interval record.
*/
/*
* Copy the data from our temporary storage to the task's
* previous interval usage structure for future reference.
*/
} else {
/*
* Store current statistics in the task's previous interval
* usage structure for future references.
*/
}
}
static void
{
proc_t *p;
return;
/*
* exacct_snapshot_task_usage() provides an approximate snapshot of the
* usage of the potentially many members of the task. Since we don't
* guarantee exactness, we don't acquire the p_lock of any of the member
* processes.
*/
do {
mutex_enter(&p->p_lock);
mutex_exit(&p->p_lock);
/*
* The resource usage accounted for so far will include that
* contributed by the task's first process. If this process
* came from another task, then its accumulated resource usage
* will include a contribution from work performed there.
* We must therefore subtract any resource usage that was
* inherited with the first process.
*/
gethrestime(&ts);
}
/*
* void exacct_update_task_mstate(proc_t *)
*
* Overview
* exacct_update_task_mstate() updates the task usage; it is intended
* to be called from proc_exit().
*
* Return values
* None.
*
* Caller's context
* p_lock must be held at entry.
*/
void
{
}
static void
{
switch (flag) {
case EW_PARTIAL:
/*
* For partial records we must report the sum of current
* accounting statistics with previously accumulated
* statistics.
*/
break;
case EW_INTERVAL:
/*
* We need to allocate spare task_usage_t buffer before
* grabbing pidlock because we might need it later in
* exacct_get_interval_task_usage().
*/
/*
* For interval records, we deduct the previous microstate
* accounting data and cpu usage times from previously saved
* results and update the previous task usage structure.
*/
break;
case EW_FINAL:
/*
* For final records, we deduct, from the task's current
* usage, any usage that was inherited with the arrival
* of a process from a previous task. We then record
* the task's finish time.
*/
gethrestime(&ts);
break;
}
}
static int
int res)
{
switch (res) {
case AC_TASK_TASKID:
break;
case AC_TASK_PROJID:
break;
case AC_TASK_CPU: {
}
break;
case AC_TASK_TIME:
break;
case AC_TASK_HOSTNAME:
break;
case AC_TASK_MICROSTATE:
break;
case AC_TASK_ANCTASKID:
break;
case AC_TASK_ZONENAME:
break;
default:
attached = 0;
}
return (attached);
}
static ea_object_t *
{
/*
* Assemble usage values into group.
*/
if (count == 0) {
}
return (record);
}
/*
* int exacct_assemble_task_usage(task_t *, int (*)(void *, size_t, void *,
* size_t, size_t *), void *, size_t, size_t *, int)
*
* Overview
* exacct_assemble_task_usage() builds the packed exacct buffer for the
* indicated task, executes the given callback function, and free the packed
* buffer.
*
* Return values
* Returns 0 on success; otherwise the appropriate error code is returned.
*
* Caller's context
* Suitable for KM_SLEEP allocations.
*/
int
{
void *buf;
int ret;
return (ENOTACTIVE);
}
switch (flag) {
case EW_FINAL:
break;
case EW_PARTIAL:
break;
case EW_INTERVAL:
break;
}
/*
* Calculate task usage and assemble it into the task record.
*/
if (task_record == NULL) {
/*
* The current configuration of the accounting system has
* resulted in records with no data; accordingly, we don't write
* these, but we return success.
*/
return (0);
}
/*
* Pack object into buffer and run callback on it.
*/
/*
* Free all previously allocated structures.
*/
return (ret);
}
/*
* void exacct_commit_task(void *)
*
* Overview
* exacct_commit_task() calculates the final usage for a task, updating the
* task usage if task accounting is active, and writing a task record if task
* accounting is active. exacct_commit_task() is intended for being called
* from a task queue (taskq_t).
*
* Return values
* None.
*
* Caller's context
* Suitable for KM_SLEEP allocations.
*/
void
{
/*
* Don't do any extra work if the acctctl module isn't loaded.
* If acctctl module is loaded when zone is in down state then
* zone_getspecific can return NULL for that zone.
*/
if (exacct_zone_key != ZONE_KEY_UNINITIALIZED) {
goto err;
}
}
/*
* Release associated project and finalize task.
*/
err:
}
static int
{
switch (res) {
case AC_PROC_PID:
break;
case AC_PROC_UID:
break;
case AC_PROC_FLAG:
break;
case AC_PROC_GID:
break;
case AC_PROC_PROJID:
break;
case AC_PROC_TASKID:
break;
case AC_PROC_CPU:
break;
case AC_PROC_TIME:
break;
case AC_PROC_COMMAND:
break;
case AC_PROC_HOSTNAME:
break;
case AC_PROC_TTY:
break;
case AC_PROC_MICROSTATE:
break;
case AC_PROC_ANCPID:
break;
case AC_PROC_WAIT_STATUS:
break;
case AC_PROC_ZONENAME:
break;
case AC_PROC_MEM:
break;
default:
attached = 0;
}
return (attached);
}
static ea_object_t *
{
/*
* Assemble usage values into group.
*/
if (count == 0) {
}
return (record);
}
/*
* The following two routines assume that process's p_lock is held or
* exacct_commit_proc has been called from exit() when all lwps are stopped.
*/
static void
{
kthread_t *t;
return;
do {
}
static void
{
}
void
{
/*
*/
}
gethrestime(&ts);
}
}
}
/*
* Compute average RSS in K. The denominator is the number of
* samples: the number of clock ticks plus the initial value.
*/
(PAGESIZE / 1024);
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
/*
* Calculate microstate accounting data for a process that is still
* running. Presently, we explicitly collect all of the LWP usage into
* the proc usage structure here.
*/
if (flag & EW_PARTIAL)
}
/*
* int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void
* *, size_t, size_t *), void *, size_t, size_t *)
*
* Overview
* Assemble record with miscellaneous accounting information about the process
* and execute the callback on it. It is the callback's job to set "actual" to
* the size of record.
*
* Return values
* The result of the callback function, unless the extended process accounting
* feature is not active, in which case ENOTACTIVE is returned.
*
* Caller's context
* Suitable for KM_SLEEP allocations.
*/
int
{
void *buf;
int ret;
return (ENOTACTIVE);
}
switch (flag) {
case EW_FINAL:
break;
case EW_PARTIAL:
break;
}
if (proc_record == NULL)
return (0);
/*
* Pack object into buffer and pass to callback.
*/
/*
* Free all previously allocations.
*/
return (ret);
}
/*
* int exacct_commit_callback(ac_info_t *, void *, size_t, void *, size_t,
* size_t *)
*
* Overview
* exacct_commit_callback() writes the indicated buffer to the indicated
* extended accounting file.
*
* Return values
* The result of the write operation is returned. "actual" is updated to
* contain the number of bytes actually written.
*
* Caller's context
* Suitable for a vn_rdwr() operation.
*/
/*ARGSUSED*/
int
{
int error = 0;
*actual = 0;
return (error);
}
static void
{
} else {
return;
}
mutex_enter(&p->p_lock);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
mutex_exit(&p->p_lock);
}
/*
* void exacct_commit_proc(proc_t *, int)
*
* Overview
* exacct_commit_proc() calculates the final usage for a process, updating the
* task usage if task accounting is active, and writing a process record if
* process accounting is active. exacct_commit_proc() is intended for being
* called from proc_exit().
*
* Return values
* None.
*
* Caller's context
* Suitable for KM_SLEEP allocations. p_lock must not be held at entry.
*/
void
{
if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
/*
* acctctl module not loaded. Nothing to do.
*/
return;
}
/*
* If acctctl module is loaded when zone is in down state then
* zone_getspecific can return NULL for that zone.
*/
return;
if (zone != global_zone) {
}
}
static int
{
switch (res) {
case AC_NET_NAME:
break;
case AC_NET_CURTIME:
{
gethrestime(&ts);
}
break;
case AC_NET_IBYTES:
break;
case AC_NET_OBYTES:
break;
case AC_NET_IPKTS:
break;
case AC_NET_OPKTS:
break;
case AC_NET_IERRPKTS:
break;
case AC_NET_OERRPKTS:
break;
default:
attached = 0;
}
return (attached);
}
static int
{
switch (res) {
case AC_NET_NAME:
break;
case AC_NET_DEVNAME:
break;
case AC_NET_EHOST:
break;
case AC_NET_EDEST:
break;
case AC_NET_VLAN_TPID:
break;
case AC_NET_VLAN_TCI:
break;
case AC_NET_SAP:
break;
case AC_NET_PRIORITY:
break;
case AC_NET_BWLIMIT:
break;
case AC_NET_SADDR:
sizeof (uint32_t), EXT_UINT32 |
} else {
}
break;
case AC_NET_DADDR:
sizeof (uint32_t), EXT_UINT32 |
} else {
}
break;
case AC_NET_SPORT:
break;
case AC_NET_DPORT:
break;
case AC_NET_PROTOCOL:
break;
case AC_NET_DSFIELD:
break;
default:
attached = 0;
}
return (attached);
}
static ea_object_t *
int what)
{
int res;
int count;
/*
* Assemble usage values into group.
*/
if (what == EX_NET_LNDESC_REC ||
what == EX_NET_FLDESC_REC) {
} else {
}
}
if (count == 0) {
}
return (record);
}
int
{
void *buf;
int ret;
return (ENOTACTIVE);
}
switch (what) {
case EX_NET_LNDESC_REC:
break;
case EX_NET_LNSTAT_REC:
break;
case EX_NET_FLDESC_REC:
break;
case EX_NET_FLSTAT_REC:
break;
}
return (0);
/*
* Pack object into buffer and pass to callback.
*/
return (ENOMEM);
/*
* Free all previously allocations.
*/
return (ret);
}
int
{
if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
/*
* acctctl module not loaded. Nothing to do.
*/
return (ENOTACTIVE);
}
/*
* Even though each zone nominally has its own flow accounting settings
* (ac_flow), these are only maintained by and for the global zone.
*
* If this were to change in the future, this function should grow a
* second zoneid (or zone) argument, and use the corresponding zone's
* settings rather than always using those of the global zone.
*/
return (ENOTACTIVE);
}
}
static int
{
switch (res) {
case AC_FLOW_SADDR:
} else {
}
break;
case AC_FLOW_DADDR:
} else {
}
break;
case AC_FLOW_SPORT:
break;
case AC_FLOW_DPORT:
break;
case AC_FLOW_PROTOCOL:
break;
case AC_FLOW_DSFIELD:
break;
case AC_FLOW_CTIME:
break;
case AC_FLOW_LSEEN:
break;
case AC_FLOW_NBYTES:
break;
case AC_FLOW_NPKTS:
break;
case AC_FLOW_PROJID:
}
break;
case AC_FLOW_UID:
}
break;
case AC_FLOW_ANAME:
break;
default:
attached = 0;
}
return (attached);
}
static ea_object_t *
{
/*
* Assemble usage values into group.
*/
if (count == 0) {
}
return (record);
}
int
{
void *buf;
int ret;
return (ENOTACTIVE);
}
if (flow_usage == NULL) {
return (0);
}
/*
* Pack object into buffer and pass to callback.
*/
return (ENOMEM);
}
/*
* Free all previously allocations.
*/
return (ret);
}
void
{
if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
/*
* acctctl module not loaded. Nothing to do.
*/
return;
}
/*
* Even though each zone nominally has its own flow accounting settings
* (ac_flow), these are only maintained by and for the global zone.
*
* If this were to change in the future, this function should grow a
* second zoneid (or zone) argument, and use the corresponding zone's
* settings rather than always using those of the global zone.
*/
return;
}
}
/*
* int exacct_tag_task(task_t *, void *, size_t, int)
*
* Overview
* exacct_tag_task() provides the exacct record construction and writing
* support required by putacct(2) for task entities.
*
* Return values
* The result of the write operation is returned, unless the extended
* accounting facility is not active, in which case ENOTACTIVE is returned.
*
* Caller's context
* Suitable for KM_SLEEP allocations.
*/
int
int flags)
{
int error = 0;
void *buf;
return (ENOTACTIVE);
}
else
return (error);
}
/*
* exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *)
*
* Overview
* exacct_tag_proc() provides the exacct record construction and writing
* support required by putacct(2) for processes.
*
* Return values
* The result of the write operation is returned, unless the extended
* accounting facility is not active, in which case ENOTACTIVE is returned.
*
* Caller's context
* Suitable for KM_SLEEP allocations.
*/
int
{
int error = 0;
void *buf;
return (ENOTACTIVE);
}
else
return (error);
}
/*
* void exacct_init(void)
*
* Overview
* Initialized the extended accounting subsystem.
*
* Return values
* None.
*
* Caller's context
* Suitable for KM_SLEEP allocations.
*/
void
{
}
/*
* exacct_snapshot_proc_mstate() copies a process's microstate accounting data
* and resource usage counters into a given task_usage_t. It differs from
* exacct_copy_proc_mstate() in that here a) we are copying to a task_usage_t,
* b) p_lock will have been acquired earlier in the call path and c) we
* are here including the process's user and system times.
*/
static void
{
}
/*
* void exacct_move_mstate(proc_t *, task_t *, task_t *)
*
* Overview
* exacct_move_mstate() is called by task_change() and accounts for
* a process's resource usage when it is moved from one task to another.
*
* The process's usage at this point is recorded in the new task so
* that it can be excluded from the calculation of resources consumed
* by that task.
*
* The resource usage inherited by the new task is also added to the
* aggregate maintained by the old task for processes that have exited.
*
* Return values
* None.
*
* Caller's context
* pidlock and p_lock held across exacct_move_mstate().
*/
void
{
/* Take a snapshot of this process's mstate and RU counters */
/*
* Use the snapshot to increment the aggregate usage of the old
* task, and the inherited usage of the new one.
*/
}