diff options
author | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-15 12:56:03 +0100 |
---|---|---|
committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-15 12:56:03 +0100 |
commit | d5b454f2c40c9efd0cc113bc3220ebcb66b7c022 (patch) | |
tree | a8aaa30e003c9dcc07840c217760f92e4fab430a /kernel | |
parent | 351bb722590b2329ac5e72c4b824b8b6ce6e3082 (diff) |
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>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/audit.c | 21 |
1 files changed, 10 insertions, 11 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index 518a833b676a..27ffcf363f8d 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -610,26 +610,25 @@ 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; - do { - a = atomic_read(&serial); - if (atomic_dec_and_test(&serial)) - atomic_set(&serial, 0xffffff); - b = atomic_read(&serial); - } while (b != a - 1); + spin_lock_irqsave(&serial_lock, flags); + ret = serial++; + spin_unlock_irqrestore(&serial_lock, flags); - return 0xffffff - b; + return ret; } static inline void audit_get_stamp(struct audit_context *ctx, |