70 #include <sys/cdefs.h>
73 #include <sys/param.h>
74 #include <sys/systm.h>
76 #include <sys/fcntl.h>
77 #include <sys/kernel.h>
78 #include <sys/kthread.h>
79 #include <sys/limits.h>
81 #include <sys/mount.h>
82 #include <sys/mutex.h>
83 #include <sys/namei.h>
86 #include <sys/resourcevar.h>
87 #include <sys/sched.h>
89 #include <sys/sysctl.h>
90 #include <sys/sysent.h>
91 #include <sys/syslog.h>
92 #include <sys/sysproto.h>
94 #include <sys/vnode.h>
96 #include <security/mac/mac_framework.h>
113 #define FLT_MANT_DIG 24
114 #define FLT_MAX_EXP 128
147 #define ACCT_RUNNING 1
148 #define ACCT_EXITREQ 2
154 SYSCTL_INT(_kern, OID_AUTO, acct_suspend, CTLFLAG_RW,
155 &
acctsuspend, 0,
"percentage of free disk space below which accounting stops");
158 SYSCTL_INT(_kern, OID_AUTO, acct_resume, CTLFLAG_RW,
159 &
acctresume, 0,
"percentage of free disk space above which accounting resumes");
169 error = SYSCTL_OUT(req, &
acctchkfreq,
sizeof(
int));
170 if (error || req->newptr == NULL)
174 error = SYSCTL_IN(req, &value,
sizeof(
int));
182 SYSCTL_PROC(_kern, OID_AUTO, acct_chkfreq, CTLTYPE_INT|CTLFLAG_RW,
184 "frequency for checking the free space");
187 "Accounting configured or not");
190 "Accounting suspended or not");
200 int error, flags, i, vfslocked, replacing;
210 if (uap->path != NULL) {
211 NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1,
212 UIO_USERSPACE, uap->path, td);
213 flags = FWRITE | O_APPEND;
214 error =
vn_open(&nd, &flags, 0, NULL);
217 vfslocked = NDHASGIANT(&nd);
218 NDFREE(&nd, NDF_ONLY_PNBUF);
220 error = mac_system_check_acct(td->td_ucred, nd.ni_vp);
222 VOP_UNLOCK(nd.ni_vp, 0);
223 vn_close(nd.ni_vp, flags, td->td_ucred, td);
224 VFS_UNLOCK_GIANT(vfslocked);
228 VOP_UNLOCK(nd.ni_vp, 0);
229 if (nd.ni_vp->v_type != VREG) {
230 vn_close(nd.ni_vp, flags, td->td_ucred, td);
231 VFS_UNLOCK_GIANT(vfslocked);
234 VFS_UNLOCK_GIANT(vfslocked);
237 error = mac_system_check_acct(td->td_ucred, NULL);
254 replacing = (
acct_vp != NULL && uap->path != NULL);
264 vfslocked = VFS_LOCK_GIANT(
acct_vp->v_mount);
266 VFS_UNLOCK_GIANT(vfslocked);
268 if (uap->path == NULL) {
282 for (i = 0; i < RLIM_NLIMITS; i++)
284 acct_limit->pl_rlimit[i].rlim_max = RLIM_INFINITY;
304 vfslocked = VFS_LOCK_GIANT(
acct_vp->v_mount);
306 VFS_UNLOCK_GIANT(vfslocked);
308 log(LOG_NOTICE,
"Unable to start accounting thread\n");
315 log(LOG_NOTICE,
"Accounting enabled\n");
328 sx_assert(&
acct_sx, SX_XLOCKED);
337 log(LOG_NOTICE,
"Accounting disabled\n");
351 struct timeval ut, st, tmp;
352 struct plimit *oldlim;
355 int t, ret, vfslocked;
386 if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp)
387 acct.ac_tty =
tty_udev(p->p_pgrp->pg_session->s_ttyp);
393 bcopy(p->p_comm, acct.ac_comm,
sizeof acct.ac_comm);
403 acct.ac_btime = tmp.tv_sec;
412 t = tmp.tv_sec *
hz + tmp.tv_usec /
tick;
414 acct.ac_mem =
encode_long((ru.ru_ixrss + ru.ru_idrss +
420 acct.ac_io =
encode_long(ru.ru_inblock + ru.ru_oublock);
423 acct.ac_uid = p->p_ucred->cr_ruid;
424 acct.ac_gid = p->p_ucred->cr_rgid;
427 acct.ac_flagx = p->p_acflag;
430 acct.ac_flagx |= ANVER;
433 acct.ac_len = acct.ac_len2 =
sizeof(acct);
446 vfslocked = VFS_LOCK_GIANT(
acct_vp->v_mount);
448 (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT,
acct_cred, NOCRED,
450 VFS_UNLOCK_GIANT(vfslocked);
460 #define MANT_MASK ((1 << (FLT_MANT_DIG - 1)) - 1)
491 if (tv.tv_sec == 0) {
501 log2_s = fls(tv.tv_sec) - 1;
504 val = 1000000 * tv.tv_sec + tv.tv_usec;
507 val = (
unsigned int)(((uint64_t)1000000 * tv.tv_sec +
512 norm_exp = fls(val) - 1;
515 printf(
"val=%d exp=%d shift=%d log2(val)=%d\n",
516 val, exp, shift, norm_exp);
518 ((shift > 0 ? (val << shift) : (val >> -shift)) &
MANT_MASK));
521 ((shift > 0 ? val << shift : val >> -shift) & MANT_MASK));
538 "encode_long: negative value %ld in accounting record\n",
542 norm_exp = fls(val) - 1;
545 printf(
"val=%d shift=%d log2(val)=%d\n",
546 val, shift, norm_exp);
548 ((shift > 0 ? (val << shift) : (val >> -shift)) &
MANT_MASK));
551 ((shift > 0 ? val << shift : val >> -shift) & MANT_MASK));
569 sx_assert(&
acct_sx, SX_XLOCKED);
585 vfslocked = VFS_LOCK_GIANT(
acct_vp->v_mount);
588 VFS_UNLOCK_GIANT(vfslocked);
597 if (VFS_STATFS(
acct_vp->v_mount, &sb) < 0) {
598 VFS_UNLOCK_GIANT(vfslocked);
601 VFS_UNLOCK_GIANT(vfslocked);
603 if (sb.f_bavail > (int64_t)(
acctresume * sb.f_blocks /
606 log(LOG_NOTICE,
"Accounting resumed\n");
609 if (sb.f_bavail <= (int64_t)(
acctsuspend * sb.f_blocks /
612 log(LOG_NOTICE,
"Accounting suspended\n");
628 thread_lock(curthread);
630 thread_unlock(curthread);
void sched_prio(struct thread *td, u_char prio)
void NDFREE(struct nameidata *ndp, const u_int flags)
static void acctwatch(void)
static void acct_thread(void *)
struct plimit * lim_alloc()
int sys_acct(struct thread *td, struct acct_args *uap)
void timevalsub(struct timeval *t1, const struct timeval *t2)
int priv_check(struct thread *td, int priv)
static uint32_t encode_timeval(struct timeval)
dev_t tty_udev(struct tty *tp)
SYSCTL_INT(_kern, OID_AUTO, acct_suspend, CTLFLAG_RW,&acctsuspend, 0,"percentage of free disk space below which accounting stops")
static struct plimit * acct_limit
void kproc_exit(int ecode)
static struct vnode * acct_vp
void rufetchcalc(struct proc *p, struct rusage *ru, struct timeval *up, struct timeval *sp)
int acct_process(struct thread *td)
static uint32_t encode_long(long)
void crfree(struct ucred *cr)
void timevaladd(struct timeval *t1, const struct timeval *t2)
struct plimit * lim_hold(struct plimit *limp)
static int sysctl_acct_chkfreq(SYSCTL_HANDLER_ARGS)
static int acct_suspended
int vn_rdwr(enum uio_rw rw, struct vnode *vp, void *base, int len, off_t offset, enum uio_seg segflg, int ioflg, struct ucred *active_cred, struct ucred *file_cred, ssize_t *aresid, struct thread *td)
void log(int level, const char *fmt,...)
static struct ucred * acct_cred
static int acct_configured
SYSCTL_PROC(_kern, OID_AUTO, acct_chkfreq, CTLTYPE_INT|CTLFLAG_RW,&acctchkfreq, 0, sysctl_acct_chkfreq,"I","frequency for checking the free space")
struct ucred * crhold(struct ucred *cr)
SX_SYSINIT(acct,&acct_sx,"acct_sx")
int printf(const char *fmt,...)
int vn_close(struct vnode *vp, int flags, struct ucred *file_cred, struct thread *td)
int kproc_create(void(*func)(void *), void *arg, struct proc **newpp, int flags, int pages, const char *fmt,...)
void microuptime(struct timeval *tvp)
int vn_open(struct nameidata *ndp, int *flagp, int cmode, struct file *fp)
void lim_free(struct plimit *limp)
static int acct_disable(struct thread *, int)