]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common/LogClient: assign seq and queue atomically
authorSage Weil <sage@redhat.com>
Fri, 4 Aug 2017 17:58:17 +0000 (13:58 -0400)
committerAbhishek Lekshmanan <abhishek@suse.com>
Wed, 23 Aug 2017 13:46:44 +0000 (15:46 +0200)
The _get_mon_log_message() assumes that log_last and log_queue
are in sync, but it was previously possible to increment log_last
setting e.seq in do_log(), and only later queue it.  If a racing
thread ran get_mon_log_message() in the meantime it would fail
an assertion.

Fix by assigning the seq and queueing it atomically.  If the
cluster log is not enabled, use the get_next_seq() helper so that
graylog or syslog messages still have a seq assigned.

Fixes: http://tracker.ceph.com/issues/18209
Signed-off-by: Sage Weil <sage@redhat.com>
(cherry picked from commit 1f8f58becf1ec53c729b0befeb1f19c601588c4a)

src/common/LogClient.cc

index 07c53e80d9ff7201c4af5b52381fc7cadef1e76d..5e0715aac9ff160fc2ee8fb79f655d8046affddc 100644 (file)
@@ -224,11 +224,17 @@ void LogChannel::do_log(clog_type prio, const std::string& s)
   // seq and who should be set for syslog/graylog/log_to_mon
   e.who = parent->get_myinst();
   e.name = parent->get_myname();
-  e.seq = parent->get_next_seq();
   e.prio = prio;
   e.msg = s;
   e.channel = get_log_channel();
 
+  // log to monitor?
+  if (log_to_monitors) {
+    e.seq = parent->queue(e);
+  } else {
+    e.seq = parent->get_next_seq();
+  }
+
   // log to syslog?
   if (do_log_to_syslog()) {
     ldout(cct,0) << __func__ << " log to syslog"  << dendl;
@@ -240,11 +246,6 @@ void LogChannel::do_log(clog_type prio, const std::string& s)
     ldout(cct,0) << __func__ << " log to graylog"  << dendl;
     graylog->log_log_entry(&e);
   }
-
-  // log to monitor?
-  if (log_to_monitors) {
-    parent->queue(e);
-  }
 }
 
 Message *LogClient::get_mon_log_message(bool flush)
@@ -324,6 +325,7 @@ void LogClient::_send_to_mon()
 version_t LogClient::queue(LogEntry &entry)
 {
   Mutex::Locker l(log_lock);
+  entry.seq = ++last_log;
   log_queue.push_back(entry);
 
   if (is_mon) {