]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
Fix the deadlock of vsyslog() call.
authorKen'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>
Fri, 15 May 2009 08:30:24 +0000 (17:30 +0900)
committerDhaval Giani <dhaval@linux.vnet.ibm.com>
Fri, 22 May 2009 09:16:21 +0000 (14:46 +0530)
Hi,

I found the deadlock problem that a cgrulesengd daemon stalls if
service "cgred" is reloaded while many UID events happen.
The following is the gdb output by attaching the stalling daemon:

 (gdb) bt
 #0  0x0000003b298dd918 in __lll_mutex_lock_wait () from /lib64/libc.so.6
 #1  0x0000003b298ce847 in _L_lock_646 () from /lib64/libc.so.6
 #2  0x0000003b298ce2da in __vsyslog_chk () from /lib64/libc.so.6
 #3  0x0000000000401533 in flog (level=5, format=0x402778 "Reloading rules configuration.") at cgrule sengd.c:130
 #4  0x00000000004015d1 in cgre_flash_rules (signum=<value optimized out>) at cgrulesengd.c:644
 #5  <signal handler called>
 #6  0x0000003b298d27b5 in send () from /lib64/libc.so.6
 #7  0x0000003b298ce3a0 in __vsyslog_chk () from /lib64/libc.so.6
 #8  0x0000000000401533 in flog (level=4, format=0x402b82 "Failed to open %s") at cgrulesengd.c:130
 #9  0x0000000000401cc7 in cgre_process_event (ev=0x7fff8ad11cc4, type=4) at cgrulesengd.c:161
 #10 0x0000000000401fd5 in cgre_create_netlink_socket_process_msg () at cgrulesengd.c:486
 #11 0x00000000004023ca in main (argc=1, argv=<value optimized out>) at cgrulesengd.c:878
 (gdb)

We can see __vsyslog_chk() is called twice, because the daemon
recieved a SIGUSR2 signal in __vsyslog_chk(). In __vsyslog_chk(),
"syslog_lock" is locked by __libc_lock_lock(syslog_lock).
So I think vsyslog() should be protected by blocking the signal,
and this patch fixes the problem by doing it.

Thanks
Ken'ichi Ohmichi

Signed-off-by: Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>
Signed-off-by: Dhaval Giani <dhaval@linux.vnet.ibm.com>
src/daemon/cgrulesengd.c

index c025862177161d3d60f66e07efe70140b13e82aa..1a61476253ebf8452f669e032375ab6e1ec54b04 100644 (file)
@@ -126,9 +126,17 @@ void flog(int level, const char *format, ...)
        }
 
        if (logfacility) {
+               sigset_t sigset;
+
+               sigemptyset(&sigset);
+               sigaddset(&sigset, SIGUSR2);
+               sigprocmask(SIG_BLOCK, &sigset, NULL);
+
                va_start(ap, format);
                vsyslog(LOG_MAKEPRI(logfacility, level), format, ap);
                va_end(ap);
+
+               sigprocmask(SIG_UNBLOCK, &sigset, NULL);
        }
 }