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