deadlock/hang
David Woodhouse
dwmw2 at infradead.org
Thu Jun 30 17:08:32 UTC 2005
On Wed, 2005-06-29 at 16:07 -0400, Steve Grubb wrote:
> So, my guess is that there is something in the draining of the backlog that
> causes this problem. The audit logs from .62 shows that recvfrom() for auditd
> is being audited over and over.
>
> I also wonder if this is related to the problem Debbie & Denise were
> reporting? It seems similar - system hung, no visible indicators that it hit
> the backlog draining.
I've cleaned up the backlog waiting, and made sure that it will _stop_
waiting once it's called audit_panic() once. That'll avoid the illusion
of a hung system if auditd isn't making progress. We should probably
allow auditctl to set both the audit_backlog_wait_time and
audit_backlog_wait_overflow variables, but you weren't about on IRC to
discuss the necessary changes to the AUDIT_SET layout, so this'll do for
now.
--- linux-2.6.9/kernel/audit.c~ 2005-06-24 15:13:54.000000000 +0100
+++ linux-2.6.9/kernel/audit.c 2005-06-30 17:45:22.000000000 +0100
@@ -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;
@@ -723,6 +725,7 @@ struct audit_buffer *audit_log_start(str
struct timespec t;
unsigned int serial;
int reserve;
+ unsigned long timeout_start = jiffies;
if (!audit_initialized)
return NULL;
@@ -735,8 +738,9 @@ struct audit_buffer *audit_log_start(str
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);
@@ -744,12 +748,11 @@ struct audit_buffer *audit_log_start(str
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
@@ -758,6 +761,8 @@ struct audit_buffer *audit_log_start(str
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;
}
--
dwmw2
More information about the Linux-audit
mailing list