Avoid taking lock in libvirt debug dump

As pointed out, locking the buffer from the signal handler
cannot been guaranteed to be safe, so to avoid any hazard
we prefer the trade off of dumping logs possibly messed up
by concurrent logging activity rather than risk a daemon
crash.

* src/util/logging.c: change virLogEmergencyDumpAll() to not
  take any lock on the log buffer but reset buffer content variables
  to an empty set before starting the actual dump.
This commit is contained in:
Daniel Veillard 2011-03-15 16:10:03 +08:00
parent 9741f3461b
commit 10598dd568

View File

@ -389,8 +389,8 @@ static void virLogDumpAllFD(const char *msg, int len) {
void void
virLogEmergencyDumpAll(int signum) { virLogEmergencyDumpAll(int signum) {
int len; int len;
int oldLogStart, oldLogLen, oldLogEnd;
virLogLock();
switch (signum) { switch (signum) {
#ifdef SIGFPE #ifdef SIGFPE
case SIGFPE: case SIGFPE:
@ -428,27 +428,43 @@ virLogEmergencyDumpAll(int signum) {
} }
if ((virLogBuffer == NULL) || (virLogSize <= 0)) { if ((virLogBuffer == NULL) || (virLogSize <= 0)) {
virLogDumpAllFD(" internal log buffer deactivated\n", -1); virLogDumpAllFD(" internal log buffer deactivated\n", -1);
goto done; return;
} }
virLogDumpAllFD(" dumping internal log buffer:\n", -1); virLogDumpAllFD(" dumping internal log buffer:\n", -1);
virLogDumpAllFD("\n\n ====== start of log =====\n\n", -1); virLogDumpAllFD("\n\n ====== start of log =====\n\n", -1);
while (virLogLen > 0) {
if (virLogStart + virLogLen < virLogSize) { /*
virLogBuffer[virLogStart + virLogLen] = 0; * Since we can't lock the buffer safely from a signal handler
virLogDumpAllFD(&virLogBuffer[virLogStart], virLogLen); * we mark it as empty in case of concurrent access, and proceed
virLogStart += virLogLen; * with the data, at worse we will output something a bit weird
* if another thread start logging messages at the same time.
* Note that virLogStr() uses virLogEnd for the computations and
* writes to the buffer and only then updates virLogLen and virLogStart
* so it's best to reset it first.
*/
oldLogStart = virLogStart;
oldLogEnd = virLogEnd;
oldLogLen = virLogLen;
virLogEnd = 0;
virLogLen = 0; virLogLen = 0;
} else {
len = virLogSize - virLogStart;
virLogBuffer[virLogSize] = 0;
virLogDumpAllFD(&virLogBuffer[virLogStart], len);
virLogLen -= len;
virLogStart = 0; virLogStart = 0;
while (oldLogLen > 0) {
if (oldLogStart + oldLogLen < virLogSize) {
virLogBuffer[oldLogStart + oldLogLen] = 0;
virLogDumpAllFD(&virLogBuffer[oldLogStart], oldLogLen);
oldLogStart += oldLogLen;
oldLogLen = 0;
} else {
len = virLogSize - oldLogStart;
virLogBuffer[virLogSize] = 0;
virLogDumpAllFD(&virLogBuffer[oldLogStart], len);
oldLogLen -= len;
oldLogStart = 0;
} }
} }
virLogDumpAllFD("\n\n ====== end of log =====\n\n", -1); virLogDumpAllFD("\n\n ====== end of log =====\n\n", -1);
done:
virLogUnlock();
} }
/** /**