[PATCH] posix-timers: fix cleanup_timers() and run_posix_cpu_timers() races
[pandora-kernel.git] / kernel / audit.c
index 2617d05..aefa73a 100644 (file)
@@ -79,6 +79,8 @@ static int    audit_rate_limit;
 
 /* Number of outstanding audit_buffers allowed. */
 static int     audit_backlog_limit = 64;
+static int     audit_backlog_wait_time = 60 * HZ;
+static int     audit_backlog_wait_overflow = 0;
 
 /* The identity of the user shutting down the audit system. */
 uid_t          audit_sig_uid = -1;
@@ -140,11 +142,6 @@ static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
        nlh->nlmsg_pid = pid;
 }
 
-struct audit_entry {
-       struct list_head  list;
-       struct audit_rule rule;
-};
-
 static void audit_panic(const char *message)
 {
        switch (audit_failure)
@@ -516,7 +513,8 @@ static int __init audit_init(void)
 {
        printk(KERN_INFO "audit: initializing netlink socket (%s)\n",
               audit_default ? "enabled" : "disabled");
-       audit_sock = netlink_kernel_create(NETLINK_AUDIT, audit_receive);
+       audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive,
+                                          THIS_MODULE);
        if (!audit_sock)
                audit_panic("cannot initialize netlink socket");
 
@@ -562,7 +560,7 @@ static void audit_buffer_free(struct audit_buffer *ab)
 }
 
 static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx,
-                                               int gfp_mask, int type)
+                                               gfp_t gfp_mask, int type)
 {
        unsigned long flags;
        struct audit_buffer *ab = NULL;
@@ -608,26 +606,27 @@ err:
  * (timestamp,serial) tuple is unique for each syscall and is live from
  * syscall entry to syscall exit.
  *
- * Atomic values are only guaranteed to be 24-bit, so we count down.
- *
  * NOTE: Another possibility is to store the formatted records off the
  * audit context (for those records that have a context), and emit them
  * all at syscall exit.  However, this could delay the reporting of
  * significant errors until syscall exit (or never, if the system
  * halts). */
+
 unsigned int audit_serial(void)
 {
-       static atomic_t serial = ATOMIC_INIT(0xffffff);
-       unsigned int a, b;
+       static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
+       static unsigned int serial = 0;
 
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&serial_lock, flags);
        do {
-               a = atomic_read(&serial);
-               if (atomic_dec_and_test(&serial))
-                       atomic_set(&serial, 0xffffff);
-               b = atomic_read(&serial);
-       } while (b != a - 1);
+               ret = ++serial;
+       } while (unlikely(!ret));
+       spin_unlock_irqrestore(&serial_lock, flags);
 
-       return 0xffffff - b;
+       return ret;
 }
 
 static inline void audit_get_stamp(struct audit_context *ctx, 
@@ -655,6 +654,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask,
        struct timespec         t;
        unsigned int            serial;
        int reserve;
+       unsigned long timeout_start = jiffies;
 
        if (!audit_initialized)
                return NULL;
@@ -667,8 +667,9 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask,
 
        while (audit_backlog_limit
               && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) {
-               if (gfp_mask & __GFP_WAIT) {
-                       int ret = 1;
+               if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time
+                   && time_before(jiffies, timeout_start + audit_backlog_wait_time)) {
+
                        /* Wait for auditd to drain the queue a little */
                        DECLARE_WAITQUEUE(wait, current);
                        set_current_state(TASK_INTERRUPTIBLE);
@@ -676,12 +677,11 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask,
 
                        if (audit_backlog_limit &&
                            skb_queue_len(&audit_skb_queue) > audit_backlog_limit)
-                               ret = schedule_timeout(HZ * 60);
+                               schedule_timeout(timeout_start + audit_backlog_wait_time - jiffies);
 
                        __set_current_state(TASK_RUNNING);
                        remove_wait_queue(&audit_backlog_wait, &wait);
-                       if (ret)
-                               continue;
+                       continue;
                }
                if (audit_rate_check())
                        printk(KERN_WARNING
@@ -690,6 +690,8 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask,
                               skb_queue_len(&audit_skb_queue),
                               audit_backlog_limit);
                audit_log_lost("backlog limit exceeded");
+               audit_backlog_wait_time = audit_backlog_wait_overflow;
+               wake_up(&audit_backlog_wait);
                return NULL;
        }