Date: Mon, 6 Feb 2006 18:25:46 GMT From: Robert Watson <rwatson@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 91247 for review Message-ID: <200602061825.k16IPk6f075908@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=91247 Change 91247 by rwatson@rwatson_zoo on 2006/02/06 18:25:03 Add support for asynchronous I/O (sigio), non-blocking I/O, and select()/poll() to the audit pipe psuedo-device. Rename the audit pipe entry memory type so it is a bit shorter and aligns more nicely in vmstat -m output. Don't need to use audit_pipe_mtx to protect dev->si_drv1 references while the device is open, only during open, close, and when accessing fields in struct audit_pipe. Affected files ... .. //depot/projects/trustedbsd/audit3/sys/security/audit/audit_pipe.c#5 edit Differences ... ==== //depot/projects/trustedbsd/audit3/sys/security/audit/audit_pipe.c#5 (text+ko) ==== @@ -32,11 +32,18 @@ #include <sys/condvar.h> #include <sys/conf.h> #include <sys/eventhandler.h> +#include <sys/filio.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> +#include <sys/poll.h> +#include <sys/proc.h> #include <sys/queue.h> +#include <sys/selinfo.h> +#include <sys/sigio.h> +#include <sys/signal.h> +#include <sys/signalvar.h> #include <sys/systm.h> #include <sys/uio.h> @@ -54,7 +61,7 @@ * Memory types. */ static MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes"); -static MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipe_entry", +static MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent", "Audit pipe entries and buffers"); /* @@ -76,8 +83,14 @@ * Description of an individual audit_pipe. Consists largely of a bounded * length queue. */ +#define AUDIT_PIPE_ASYNC 0x00000001 +#define AUDIT_PIPE_NBIO 0x00000002 struct audit_pipe { int ap_open; /* Device open? */ + u_int ap_flags; + + struct selinfo ap_selinfo; + struct sigio *ap_sigio; u_int ap_qlen; u_int ap_qlimit; @@ -192,6 +205,9 @@ TAILQ_INSERT_TAIL(&ap->ap_queue, ape, ape_queue); ap->ap_inserts++; ap->ap_qlen++; + selwakeuppri(&ap->ap_selinfo, PSOCK); + if (ap->ap_flags & AUDIT_PIPE_ASYNC) + pgsigio(&ap->ap_sigio, SIGIO, 0); } /* @@ -314,8 +330,6 @@ * Audit pipe open method. Explicit suser check isn't used as this allows * file permissions on the special device to be used to grant audit review * access. - * - * XXXRW: SIGIO/select/etc support? */ static int audit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td) @@ -331,12 +345,14 @@ return (ENOMEM); } dev->si_drv1 = ap; - } else if (ap->ap_open) { + } else { + KASSERT(ap->ap_open, ("audit_pipe_open: ap && !ap_open")); mtx_unlock(&audit_pipe_mtx); return (EBUSY); } - ap->ap_open++; + ap->ap_open = 1; mtx_unlock(&audit_pipe_mtx); + fsetown(td->td_proc->p_pid, &ap->ap_sigio); return (0); } @@ -348,12 +364,12 @@ { struct audit_pipe *ap; - mtx_lock(&audit_pipe_mtx); ap = dev->si_drv1; KASSERT(ap != NULL, ("audit_pipe_close: ap == NULL")); KASSERT(ap->ap_open, ("audit_pipe_close: !ap_open")); - ap->ap_open--; - KASSERT(ap->ap_open == 0, ("audit_pipe_close: ap_open")); + funsetown(&ap->ap_sigio); + mtx_lock(&audit_pipe_mtx); + ap->ap_open = 0; audit_pipe_free(ap); dev->si_drv1 = NULL; mtx_unlock(&audit_pipe_mtx); @@ -366,27 +382,65 @@ * * Would be desirable to support filtering, although perhaps something simple * like an event mask, as opposed to something complicated like BPF. - * - * XXXRW: SIGIO/select/etc support? */ static int audit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { struct audit_pipe *ap; + int error; - mtx_lock(&audit_pipe_mtx); ap = dev->si_drv1; KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL")); - mtx_unlock(&audit_pipe_mtx); - return (ENOTTY); + switch (cmd) { + case FIONBIO: + mtx_lock(&audit_pipe_mtx); + if (*(int *)data) + ap->ap_flags |= AUDIT_PIPE_NBIO; + else + ap->ap_flags &= ~AUDIT_PIPE_NBIO; + mtx_unlock(&audit_pipe_mtx); + error = 0; + break; + + case FIONREAD: + mtx_lock(&audit_pipe_mtx); + if (TAILQ_FIRST(&ap->ap_queue) != NULL) + *(int *)data = + TAILQ_FIRST(&ap->ap_queue)->ape_record_len; + else + *(int *)data = 0; + mtx_unlock(&audit_pipe_mtx); + error = 0; + break; + + case FIOASYNC: + mtx_lock(&audit_pipe_mtx); + if (*(int *)data) + ap->ap_flags |= AUDIT_PIPE_ASYNC; + else + ap->ap_flags &= ~AUDIT_PIPE_ASYNC; + mtx_unlock(&audit_pipe_mtx); + error = 0; + break; + + case FIOSETOWN: + error = fsetown(*(int *)data, &ap->ap_sigio); + break; + + case FIOGETOWN: + *(int *)data = fgetown(&ap->ap_sigio); + error = 0; + + default: + error = ENOTTY; + } + return (error); } /* * Audit pipe read. Pull one record off the queue and copy to user space. * On error, the record is dropped. - * - * XXXRW: SIGIO/select/etc support? */ static int audit_pipe_read(struct cdev *dev, struct uio *uio, int flag) @@ -395,10 +449,9 @@ struct audit_pipe *ap; int error; - mtx_lock(&audit_pipe_mtx); ap = dev->si_drv1; KASSERT(ap != NULL, ("audit_pipe_read: ap == NULL")); - ape = audit_pipe_pop(ap); + mtx_lock(&audit_pipe_mtx); do { /* * Wait for a record that fits into the read buffer, dropping @@ -407,6 +460,10 @@ * interface. */ while ((ape = audit_pipe_pop(ap)) == NULL) { + if (ap->ap_flags & AUDIT_PIPE_NBIO) { + mtx_unlock(&audit_pipe_mtx); + return (EAGAIN); + } error = cv_wait_sig(&audit_pipe_cv, &audit_pipe_mtx); if (error) { mtx_unlock(&audit_pipe_mtx); @@ -425,22 +482,32 @@ * we abandon the remainder of the record, supporting only discreet * record reads. */ - if (ape != NULL) { - error = uiomove(ape->ape_record, ape->ape_record_len, uio); - audit_pipe_entry_free(ape); - } else - error = 0; + error = uiomove(ape->ape_record, ape->ape_record_len, uio); + audit_pipe_entry_free(ape); return (error); } /* - * Audit pipe poll. Not currently supported. + * Audit pipe poll. */ static int audit_pipe_poll(struct cdev *dev, int events, struct thread *td) { + struct audit_pipe *ap; + int revents; - return (EOPNOTSUPP); + revents = 0; + ap = dev->si_drv1; + KASSERT(ap != NULL, ("audit_pipe_poll: ap == NULL")); + if (events & (POLLIN | POLLRDNORM)) { + mtx_lock(&audit_pipe_mtx); + if (TAILQ_FIRST(&ap->ap_queue) != NULL) + revents |= events & (POLLIN | POLLRDNORM); + else + selrecord(td, &ap->ap_selinfo); + mtx_unlock(&audit_pipe_mtx); + } + return (revents); } /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200602061825.k16IPk6f075908>