AUDIT: Fix livelock in audit_serial().
The tricks with atomic_t were bizarre. Just do it sensibly instead.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
diff --git a/kernel/audit.c b/kernel/audit.c
index 518a833..27ffcf36 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -610,26 +610,25 @@
* (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;
- do {
- a = atomic_read(&serial);
- if (atomic_dec_and_test(&serial))
- atomic_set(&serial, 0xffffff);
- b = atomic_read(&serial);
- } while (b != a - 1);
+ unsigned long flags;
+ unsigned int ret;
- return 0xffffff - b;
+ spin_lock_irqsave(&serial_lock, flags);
+ ret = serial++;
+ spin_unlock_irqrestore(&serial_lock, flags);
+
+ return ret;
}
static inline void audit_get_stamp(struct audit_context *ctx,