PERFORCE change 91247 for review

Robert Watson rwatson at FreeBSD.org
Mon Feb 6 18:25:46 GMT 2006


http://perforce.freebsd.org/chv.cgi?CH=91247

Change 91247 by rwatson at 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);
 }
 
 /*
To Unsubscribe: send mail to majordomo at trustedbsd.org
with "unsubscribe trustedbsd-cvs" in the body of the message



More information about the trustedbsd-cvs mailing list