Author: rwatson
Date: Wed Feb 25 13:17:46 2009
New Revision: 189034
URL: http://svn.freebsd.org/changeset/base/189034

Log:
  Merge r184534 from head to stable/7:
  
    Allow a single read(2) system call on an audit pipe to retrieve data from
    more than one audit record at a time in order to improve efficiency.
  
    Sponsored by: Apple, Inc.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/ath/ath_hal/   (props changed)
  stable/7/sys/dev/cxgb/   (props changed)
  stable/7/sys/security/audit/audit_pipe.c

Modified: stable/7/sys/security/audit/audit_pipe.c
==============================================================================
--- stable/7/sys/security/audit/audit_pipe.c    Wed Feb 25 12:32:15 2009        
(r189033)
+++ stable/7/sys/security/audit/audit_pipe.c    Wed Feb 25 13:17:46 2009        
(r189034)
@@ -934,19 +934,8 @@ audit_pipe_ioctl(struct cdev *dev, u_lon
 }
 
 /*
- * Audit pipe read.  Pull one record off the queue and copy to user space.
- * On error, the record is dropped.
- *
- * Providing more sophisticated behavior, such as partial reads, is tricky
- * due to the potential for parallel I/O.  If partial read support is
- * required, it will require a per-pipe "current record being read" along
- * with an offset into that trecord which has already been read.  Threads
- * performing partial reads will need to allocate per-thread copies of the
- * data so that if another thread completes the read of the record, it can be
- * freed without adding reference count logic.  If this is added, a flag to
- * indicate that only atomic record reads are desired would be useful, as if
- * different threads are all waiting for records on the pipe, they will want
- * independent record reads, which is currently the behavior.
+ * Audit pipe read.  Read one or more partial or complete records to user
+ * memory.
  */
 static int
 audit_pipe_read(struct cdev *dev, struct uio *uio, int flag)
@@ -982,40 +971,43 @@ audit_pipe_read(struct cdev *dev, struct
 
        /*
         * Copy as many remaining bytes from the current record to userspace
-        * as we can.
+        * as we can.  Keep processing records until we run out of records in
+        * the queue, or until the user buffer runs out of space.
         *
         * Note: we rely on the SX lock to maintain ape's stability here.
         */
        ap->ap_reads++;
-       ape = TAILQ_FIRST(&ap->ap_queue);
-       toread = MIN(ape->ape_record_len - ape->ape_record_offset,
-           uio->uio_resid);
-       AUDIT_PIPE_UNLOCK(ap);
-       error = uiomove((char *)ape->ape_record + ape->ape_record_offset,
-           toread, uio);
-       if (error) {
-               AUDIT_PIPE_SX_XUNLOCK(ap);
-               return (error);
-       }
+       while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL &&
+           uio->uio_resid > 0) {
+               AUDIT_PIPE_LOCK_ASSERT(ap);
 
-       /*
-        * If the copy succeeded, update book-keeping, and if no bytes remain
-        * in the current record, free it.
-        */
-       AUDIT_PIPE_LOCK(ap);
-       KASSERT(TAILQ_FIRST(&ap->ap_queue) == ape,
-           ("audit_pipe_read: queue out of sync after uiomove"));
-       ape->ape_record_offset += toread;
-       if (ape->ape_record_offset == ape->ape_record_len) {
-               TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue);
-               ap->ap_qlen--;
-       } else
-               ape = NULL;
+               toread = MIN(ape->ape_record_len - ape->ape_record_offset,
+                   uio->uio_resid);
+               AUDIT_PIPE_UNLOCK(ap);
+               error = uiomove((char *)ape->ape_record +
+                   ape->ape_record_offset, toread, uio);
+               if (error) {
+                       AUDIT_PIPE_SX_XUNLOCK(ap);
+                       return (error);
+               }
+
+               /*
+                * If the copy succeeded, update book-keeping, and if no
+                * bytes remain in the current record, free it.
+                */
+               AUDIT_PIPE_LOCK(ap);
+               KASSERT(TAILQ_FIRST(&ap->ap_queue) == ape,
+                   ("audit_pipe_read: queue out of sync after uiomove"));
+               ape->ape_record_offset += toread;
+               if (ape->ape_record_offset == ape->ape_record_len) {
+                       TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue);
+                       audit_pipe_entry_free(ape);
+                       ap->ap_qlen--;
+               }
+       }
        AUDIT_PIPE_UNLOCK(ap);
        AUDIT_PIPE_SX_XUNLOCK(ap);
-       if (ape != NULL)
-               audit_pipe_entry_free(ape);
-       return (error);
+       return (0);
 }
 
 /*
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to