From 7e166ebd8c7bade39002b0a81a1795775af21dde Mon Sep 17 00:00:00 2001 From: Artem Pisarenko Date: Thu, 18 Oct 2018 13:12:53 +0600 Subject: vl: refactor -rtc option references Improve code readability and prepare for fixing bug #1797033 Signed-off-by: Artem Pisarenko Message-Id: <9330a48899f997431a34460014886d118a7c0960.1539846575.git.artem.k.pisarenko@gmail.com> Signed-off-by: Paolo Bonzini --- vl.c | 84 +++++++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 33 deletions(-) (limited to 'vl.c') diff --git a/vl.c b/vl.c index 4e25c78..d15e086 100644 --- a/vl.c +++ b/vl.c @@ -147,8 +147,13 @@ bool enable_cpu_pm = false; int nb_nics; NICInfo nd_table[MAX_NICS]; int autostart; -static int rtc_utc = 1; -static int rtc_date_offset = -1; /* -1 means no change */ +static enum { + RTC_BASE_UTC, + RTC_BASE_LOCALTIME, + RTC_BASE_DATETIME, +} rtc_base_type = RTC_BASE_UTC; +static int rtc_host_datetime_offset = -1; /* valid only for host rtc_clock and + rtc_base_type=RTC_BASE_DATETIME */ QEMUClockType rtc_clock; int vga_interface_type = VGA_NONE; static DisplayOptions dpy; @@ -782,26 +787,30 @@ void qemu_system_vmstop_request(RunState state) /***********************************************************/ /* real time host monotonic timer */ -static time_t qemu_time(void) +static time_t qemu_timedate(void) { return qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000; } /***********************************************************/ -/* host time/date access */ +/* RTC reference time/date access */ void qemu_get_timedate(struct tm *tm, int offset) { - time_t ti = qemu_time(); + time_t ti = qemu_timedate(); ti += offset; - if (rtc_date_offset == -1) { - if (rtc_utc) - gmtime_r(&ti, tm); - else - localtime_r(&ti, tm); - } else { - ti -= rtc_date_offset; + + switch (rtc_base_type) { + case RTC_BASE_UTC: gmtime_r(&ti, tm); + break; + case RTC_BASE_LOCALTIME: + localtime_r(&ti, tm); + break; + case RTC_BASE_DATETIME: + ti -= rtc_host_datetime_offset; + gmtime_r(&ti, tm); + break; } } @@ -809,23 +818,30 @@ int qemu_timedate_diff(struct tm *tm) { time_t seconds; - if (rtc_date_offset == -1) - if (rtc_utc) - seconds = mktimegm(tm); - else { - struct tm tmp = *tm; - tmp.tm_isdst = -1; /* use timezone to figure it out */ - seconds = mktime(&tmp); - } - else - seconds = mktimegm(tm) + rtc_date_offset; - - return seconds - qemu_time(); + switch (rtc_base_type) { + case RTC_BASE_UTC: + seconds = mktimegm(tm); + break; + case RTC_BASE_LOCALTIME: + { + struct tm tmp = *tm; + tmp.tm_isdst = -1; /* use timezone to figure it out */ + seconds = mktime(&tmp); + break; + } + case RTC_BASE_DATETIME: + seconds = mktimegm(tm) + rtc_host_datetime_offset; + break; + default: + abort(); + } + + return seconds - qemu_timedate(); } -static void configure_rtc_date_offset(const char *startdate) +static void configure_rtc_host_datetime_offset(const char *startdate) { - time_t rtc_start_date; + time_t rtc_start_datetime; struct tm tm; if (sscanf(startdate, "%d-%d-%dT%d:%d:%d", &tm.tm_year, &tm.tm_mon, @@ -841,15 +857,16 @@ static void configure_rtc_date_offset(const char *startdate) } tm.tm_year -= 1900; tm.tm_mon--; - rtc_start_date = mktimegm(&tm); - if (rtc_start_date == -1) { + rtc_start_datetime = mktimegm(&tm); + if (rtc_start_datetime == -1) { date_fail: - error_report("invalid date format"); + error_report("invalid datetime format"); error_printf("valid formats: " "'2006-06-17T16:01:21' or '2006-06-17'\n"); exit(1); } - rtc_date_offset = qemu_time() - rtc_start_date; + rtc_host_datetime_offset = (qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000) + - rtc_start_datetime; } static void configure_rtc(QemuOpts *opts) @@ -859,15 +876,16 @@ static void configure_rtc(QemuOpts *opts) value = qemu_opt_get(opts, "base"); if (value) { if (!strcmp(value, "utc")) { - rtc_utc = 1; + rtc_base_type = RTC_BASE_UTC; } else if (!strcmp(value, "localtime")) { Error *blocker = NULL; - rtc_utc = 0; + rtc_base_type = RTC_BASE_LOCALTIME; error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, "-rtc base=localtime"); replay_add_blocker(blocker); } else { - configure_rtc_date_offset(value); + rtc_base_type = RTC_BASE_DATETIME; + configure_rtc_host_datetime_offset(value); } } value = qemu_opt_get(opts, "clock"); -- cgit v1.1 From eb6a52099160f1a6e66d7ee042bbf7fb5dba67d6 Mon Sep 17 00:00:00 2001 From: Artem Pisarenko Date: Thu, 18 Oct 2018 13:12:54 +0600 Subject: Fixes RTC bug with base datetime shifts in clock=vm This makes all current "-rtc" option parameters combinations produce fixed/unambiguous RTC timedate reference for hardware emulation frontends. It restores determinism of guest execution when used with clock=vm and specified base value. Buglink: https://bugs.launchpad.net/qemu/+bug/1797033 Signed-off-by: Artem Pisarenko Message-Id: <1d963c3e013dfedafa1f6edb9fb219b7e49e39da.1539846575.git.artem.k.pisarenko@gmail.com> Signed-off-by: Paolo Bonzini --- vl.c | 62 +++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 23 deletions(-) (limited to 'vl.c') diff --git a/vl.c b/vl.c index d15e086..5bb53f7 100644 --- a/vl.c +++ b/vl.c @@ -152,8 +152,10 @@ static enum { RTC_BASE_LOCALTIME, RTC_BASE_DATETIME, } rtc_base_type = RTC_BASE_UTC; -static int rtc_host_datetime_offset = -1; /* valid only for host rtc_clock and - rtc_base_type=RTC_BASE_DATETIME */ +static time_t rtc_ref_start_datetime; +static int rtc_realtime_clock_offset; /* used only with QEMU_CLOCK_REALTIME */ +static int rtc_host_datetime_offset = -1; /* valid & used only with + RTC_BASE_DATETIME */ QEMUClockType rtc_clock; int vga_interface_type = VGA_NONE; static DisplayOptions dpy; @@ -247,6 +249,7 @@ static struct { static QemuOptsList qemu_rtc_opts = { .name = "rtc", .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head), + .merge_lists = true, .desc = { { .name = "base", @@ -785,32 +788,42 @@ void qemu_system_vmstop_request(RunState state) } /***********************************************************/ -/* real time host monotonic timer */ - -static time_t qemu_timedate(void) +/* RTC reference time/date access */ +static time_t qemu_ref_timedate(void) { - return qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000; + time_t value = qemu_clock_get_ms(rtc_clock) / 1000; + switch (rtc_clock) { + case QEMU_CLOCK_REALTIME: + value -= rtc_realtime_clock_offset; + /* no break */ + case QEMU_CLOCK_VIRTUAL: + value += rtc_ref_start_datetime; + break; + case QEMU_CLOCK_HOST: + if (rtc_base_type == RTC_BASE_DATETIME) { + value -= rtc_host_datetime_offset; + } + break; + default: + assert(0); + } + return value; } -/***********************************************************/ -/* RTC reference time/date access */ void qemu_get_timedate(struct tm *tm, int offset) { - time_t ti = qemu_timedate(); + time_t ti = qemu_ref_timedate(); ti += offset; switch (rtc_base_type) { + case RTC_BASE_DATETIME: case RTC_BASE_UTC: gmtime_r(&ti, tm); break; case RTC_BASE_LOCALTIME: localtime_r(&ti, tm); break; - case RTC_BASE_DATETIME: - ti -= rtc_host_datetime_offset; - gmtime_r(&ti, tm); - break; } } @@ -819,6 +832,7 @@ int qemu_timedate_diff(struct tm *tm) time_t seconds; switch (rtc_base_type) { + case RTC_BASE_DATETIME: case RTC_BASE_UTC: seconds = mktimegm(tm); break; @@ -829,17 +843,14 @@ int qemu_timedate_diff(struct tm *tm) seconds = mktime(&tmp); break; } - case RTC_BASE_DATETIME: - seconds = mktimegm(tm) + rtc_host_datetime_offset; - break; default: abort(); } - return seconds - qemu_timedate(); + return seconds - qemu_ref_timedate(); } -static void configure_rtc_host_datetime_offset(const char *startdate) +static void configure_rtc_base_datetime(const char *startdate) { time_t rtc_start_datetime; struct tm tm; @@ -865,14 +876,19 @@ static void configure_rtc_host_datetime_offset(const char *startdate) "'2006-06-17T16:01:21' or '2006-06-17'\n"); exit(1); } - rtc_host_datetime_offset = (qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000) - - rtc_start_datetime; + rtc_host_datetime_offset = rtc_ref_start_datetime - rtc_start_datetime; + rtc_ref_start_datetime = rtc_start_datetime; } static void configure_rtc(QemuOpts *opts) { const char *value; + /* Set defaults */ + rtc_clock = QEMU_CLOCK_HOST; + rtc_ref_start_datetime = qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000; + rtc_realtime_clock_offset = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000; + value = qemu_opt_get(opts, "base"); if (value) { if (!strcmp(value, "utc")) { @@ -885,7 +901,7 @@ static void configure_rtc(QemuOpts *opts) replay_add_blocker(blocker); } else { rtc_base_type = RTC_BASE_DATETIME; - configure_rtc_host_datetime_offset(value); + configure_rtc_base_datetime(value); } } value = qemu_opt_get(opts, "clock"); @@ -3035,7 +3051,6 @@ int main(int argc, char **argv, char **envp) error_reportf_err(err, "cannot initialize crypto: "); exit(1); } - rtc_clock = QEMU_CLOCK_HOST; QLIST_INIT (&vm_change_state_head); os_setup_early_signal_handling(); @@ -3755,7 +3770,6 @@ int main(int argc, char **argv, char **envp) if (!opts) { exit(1); } - configure_rtc(opts); break; case QEMU_OPTION_tb_size: #ifndef CONFIG_TCG @@ -3973,6 +3987,8 @@ int main(int argc, char **argv, char **envp) exit(EXIT_FAILURE); } + configure_rtc(qemu_find_opts_singleton("rtc")); + machine_class = select_machine(); set_memory_options(&ram_slots, &maxram_size, machine_class); -- cgit v1.1 From ac0989f53dd08ba7831130396f794b3e3bdf2d1a Mon Sep 17 00:00:00 2001 From: Artem Pisarenko Date: Thu, 18 Oct 2018 13:12:55 +0600 Subject: vl, qapi: offset calculation in RTC_CHANGE event reverted Return value of qemu_timedate_diff(), used for calculation offset in QAPI 'RTC_CHANGE' event, restored to keep compatibility. Since it wasn't documented that difference is relative to host clock advancement, this change also adds important note to 'RTC_CHANGE' event description to highlight established implementation specifics. Signed-off-by: Artem Pisarenko Message-Id: <1fc12c77e8b7115d3842919a8b586d9cbe4efca6.1539846575.git.artem.k.pisarenko@gmail.com> Signed-off-by: Paolo Bonzini --- vl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'vl.c') diff --git a/vl.c b/vl.c index 5bb53f7..c5fffa3 100644 --- a/vl.c +++ b/vl.c @@ -789,10 +789,10 @@ void qemu_system_vmstop_request(RunState state) /***********************************************************/ /* RTC reference time/date access */ -static time_t qemu_ref_timedate(void) +static time_t qemu_ref_timedate(QEMUClockType clock) { - time_t value = qemu_clock_get_ms(rtc_clock) / 1000; - switch (rtc_clock) { + time_t value = qemu_clock_get_ms(clock) / 1000; + switch (clock) { case QEMU_CLOCK_REALTIME: value -= rtc_realtime_clock_offset; /* no break */ @@ -812,7 +812,7 @@ static time_t qemu_ref_timedate(void) void qemu_get_timedate(struct tm *tm, int offset) { - time_t ti = qemu_ref_timedate(); + time_t ti = qemu_ref_timedate(rtc_clock); ti += offset; @@ -847,7 +847,7 @@ int qemu_timedate_diff(struct tm *tm) abort(); } - return seconds - qemu_ref_timedate(); + return seconds - qemu_ref_timedate(QEMU_CLOCK_HOST); } static void configure_rtc_base_datetime(const char *startdate) -- cgit v1.1