ae23c9
From cb9a84154c755daf0c9361346302ad41a1804ecc Mon Sep 17 00:00:00 2001
ae23c9
From: Peter Xu <peterx@redhat.com>
ae23c9
Date: Thu, 8 Nov 2018 06:29:32 +0000
ae23c9
Subject: [PATCH 04/35] qemu-error: introduce {error|warn}_report_once
ae23c9
MIME-Version: 1.0
ae23c9
Content-Type: text/plain; charset=UTF-8
ae23c9
Content-Transfer-Encoding: 8bit
ae23c9
ae23c9
RH-Author: Peter Xu <peterx@redhat.com>
ae23c9
Message-id: <20181108062938.21143-2-peterx@redhat.com>
ae23c9
Patchwork-id: 82959
ae23c9
O-Subject: [RHEL-8 qemu-kvm PATCH 1/7] qemu-error: introduce {error|warn}_report_once
ae23c9
Bugzilla: 1625173
ae23c9
RH-Acked-by: Auger Eric <eric.auger@redhat.com>
ae23c9
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
ae23c9
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
ae23c9
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
ae23c9
ae23c9
Bugzilla: 1625173
ae23c9
ae23c9
There are many error_report()s that can be used in frequently called
ae23c9
functions, especially on IO paths.  That can be unideal in that
ae23c9
malicious guest can try to trigger the error tons of time which might
ae23c9
use up the log space on the host (e.g., libvirt can capture the stderr
ae23c9
of QEMU and put it persistently onto disk).  In VT-d emulation code, we
ae23c9
have trace_vtd_error() tracer.  AFAIU all those places can be replaced
ae23c9
by something like error_report() but trace points are mostly used to
ae23c9
avoid the DDOS attack that mentioned above.  However using trace points
ae23c9
mean that errors are not dumped if trace not enabled.
ae23c9
ae23c9
It's not a big deal in most modern server managements since we have
ae23c9
things like logrotate to maintain the logs and make sure the quota is
ae23c9
expected.  However it'll still be nice that we just provide another way
ae23c9
to restrict message generations.  In most cases, this kind of
ae23c9
error_report()s will only provide valid information on the first message
ae23c9
sent, and all the rest of similar messages will be mostly talking about
ae23c9
the same thing.  This patch introduces *_report_once() helpers to allow
ae23c9
a message to be dumped only once during one QEMU process's life cycle.
ae23c9
It will make sure: (1) it's on by deffault, so we can even get something
ae23c9
without turning the trace on and reproducing, and (2) it won't be
ae23c9
affected by DDOS attack.
ae23c9
ae23c9
To implement it, I stole the printk_once() macro from Linux.
ae23c9
ae23c9
CC: Eric Blake <eblake@redhat.com>
ae23c9
CC: Markus Armbruster <armbru@redhat.com>
ae23c9
Signed-off-by: Peter Xu <peterx@redhat.com>
ae23c9
Message-Id: <20180815095328.32414-2-peterx@redhat.com>
ae23c9
Reviewed-by: Markus Armbruster <armbru@redhat.com>
ae23c9
[Whitespace adjusted, comments improved]
ae23c9
Signed-off-by: Markus Armbruster <armbru@redhat.com>
ae23c9
(cherry picked from commit bc6a69dd4bfa41ae56235dcbb9a28a56e12a7dc6)
ae23c9
Signed-off-by: Peter Xu <peterx@redhat.com>
ae23c9
ae23c9
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ae23c9
---
ae23c9
 include/qemu/error-report.h | 32 ++++++++++++++++++++++++++++++++
ae23c9
 1 file changed, 32 insertions(+)
ae23c9
ae23c9
diff --git a/include/qemu/error-report.h b/include/qemu/error-report.h
ae23c9
index e1c8ae1..72fab2b 100644
ae23c9
--- a/include/qemu/error-report.h
ae23c9
+++ b/include/qemu/error-report.h
ae23c9
@@ -44,6 +44,38 @@ void error_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
ae23c9
 void warn_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
ae23c9
 void info_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
ae23c9
 
ae23c9
+/*
ae23c9
+ * Similar to error_report(), except it prints the message just once.
ae23c9
+ * Return true when it prints, false otherwise.
ae23c9
+ */
ae23c9
+#define error_report_once(fmt, ...)             \
ae23c9
+    ({                                          \
ae23c9
+        static bool print_once_;                \
ae23c9
+        bool ret_print_once_ = !print_once_;    \
ae23c9
+                                                \
ae23c9
+        if (!print_once_) {                     \
ae23c9
+            print_once_ = true;                 \
ae23c9
+            error_report(fmt, ##__VA_ARGS__);   \
ae23c9
+        }                                       \
ae23c9
+        unlikely(ret_print_once_);              \
ae23c9
+    })
ae23c9
+
ae23c9
+/*
ae23c9
+ * Similar to warn_report(), except it prints the message just once.
ae23c9
+ * Return true when it prints, false otherwise.
ae23c9
+ */
ae23c9
+#define warn_report_once(fmt, ...)              \
ae23c9
+    ({                                          \
ae23c9
+        static bool print_once_;                \
ae23c9
+        bool ret_print_once_ = !print_once_;    \
ae23c9
+                                                \
ae23c9
+        if (!print_once_) {                     \
ae23c9
+            print_once_ = true;                 \
ae23c9
+            warn_report(fmt, ##__VA_ARGS__);    \
ae23c9
+        }                                       \
ae23c9
+        unlikely(ret_print_once_);              \
ae23c9
+    })
ae23c9
+
ae23c9
 const char *error_get_progname(void);
ae23c9
 extern bool enable_timestamp_msg;
ae23c9
 
ae23c9
-- 
ae23c9
1.8.3.1
ae23c9