diff mbox

[qemu,V3,2/2] kvmclock: reduce kvmclock difference on migration

Message ID 20161205151742.GD13060@thinpad.lan.raisama.net (mailing list archive)
State New, archived
Headers show

Commit Message

Eduardo Habkost Dec. 5, 2016, 3:17 p.m. UTC
On Fri, Dec 02, 2016 at 08:30:35PM -0200, Marcelo Tosatti wrote:
> On Fri, Dec 02, 2016 at 11:56:09AM -0200, Eduardo Habkost wrote:
> > On Thu, Dec 01, 2016 at 12:39:03PM -0200, Marcelo Tosatti wrote:
> > > On Wed, Nov 30, 2016 at 11:09:28AM -0200, Eduardo Habkost wrote:
> > > > On Tue, Nov 29, 2016 at 09:54:29PM -0200, Marcelo Tosatti wrote:
> > > > > On Tue, Nov 29, 2016 at 10:34:05AM -0200, Eduardo Habkost wrote:
> > > > > > On Tue, Nov 29, 2016 at 08:56:00AM -0200, Marcelo Tosatti wrote:
> > > > > > > On Mon, Nov 28, 2016 at 03:12:01PM -0200, Eduardo Habkost wrote:
> > > > > > > > On Mon, Nov 28, 2016 at 02:45:24PM -0200, Marcelo Tosatti wrote:
> > > > > > > > > On Mon, Nov 28, 2016 at 12:13:22PM -0200, Eduardo Habkost wrote:
> > > > > > > > > > Sorry for not noticing the following issues on the previous
> > > > > > > > > > reviews. I was only paying attention to the vmstate and machine
> > > > > > > > > > code:
> > > > > > > > > > 
> > > > > > > > > > On Mon, Nov 21, 2016 at 08:50:04AM -0200, Marcelo Tosatti wrote:
> > > > > > > > > > > Check for KVM_CAP_ADJUST_CLOCK capability KVM_CLOCK_TSC_STABLE, which
> > > > > > > > > > > indicates that KVM_GET_CLOCK returns a value as seen by the guest at
> > > > > > > > > > > that moment.
> > > > > > > > > > > 
> > > > > > > > > > > For new machine types, use this value rather than reading 
> > > > > > > > > > > from guest memory.
> > > > > > > > > > > 
> > > > > > > > > > > This reduces kvmclock difference on migration from 5s to 0.1s
> > > > > > > > > > > (when max_downtime == 5s).
> > > > > > > > > > > 
> > > > > > > > > > > Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> > > > > > > > > > > 
> > > > > > > > > > > ---
> > > > > > > > > > >  hw/i386/kvm/clock.c    |  107 ++++++++++++++++++++++++++++++++++++++++++-------
> > > > > > > > > > >  include/hw/i386/pc.h   |    5 ++
> > > > > > > > > > >  target-i386/kvm.c      |    7 +++
> > > > > > > > > > >  target-i386/kvm_i386.h |    1 
> > > > > > > > > > >  4 files changed, 106 insertions(+), 14 deletions(-)
> > > > > > > > > > > 
> > > > > > > > > > > v2: 
> > > > > > > > > > > - improve variable names (Juan)
> > > > > > > > > > > - consolidate code on kvm_get_clock function (Paolo)
> > > > > > > > > > > - return mach_use_reliable_get_clock from needed function (Paolo)
> > > > > > > > > > > v3: 
> > > > > > > > > > > - simplify check for src_use_reliable_get_clock (Eduardo)
> > > > > > > > > > > - move src_use_reliable_get_clock initialization to realize (Eduardo)
> > > > > > > > > > > 
> > > > > > > > > > > 
> > > > > > > > > > > Index: qemu-mig-advance-clock/hw/i386/kvm/clock.c
> > > > > > > > > > > ===================================================================
> > > > > > > > > > > --- qemu-mig-advance-clock.orig/hw/i386/kvm/clock.c	2016-11-17 15:07:11.220632761 -0200
> > > > > > > > > > > +++ qemu-mig-advance-clock/hw/i386/kvm/clock.c	2016-11-17 15:11:51.372048640 -0200
> > > > > > > > > > > @@ -36,6 +36,12 @@
> > > > > > > > > > >  
> > > > > > > > > > >      uint64_t clock;
> > > > > > > > > > >      bool clock_valid;
> > > > > > > > > > > +
> > > > > > > > > > > +    /* whether machine supports reliable KVM_GET_CLOCK */
> > > > > > > > > > > +    bool mach_use_reliable_get_clock;
> > > > > > > > > > > +
> > > > > > > > > > > +    /* whether source host supported reliable KVM_GET_CLOCK */
> > > > > > > > > > > +    bool src_use_reliable_get_clock;
> > > > > > > > > > >  } KVMClockState;
> > > > > > > > > > >  
> > > > > > > > > > >  struct pvclock_vcpu_time_info {
> > > > > > > > > > > @@ -81,6 +87,19 @@
> > > > > > > > > > >      return nsec + time.system_time;
> > > > > > > > > > >  }
> > > > > > > > > > >  
> > > > > > > > > > > +static uint64_t kvm_get_clock(void)
> > > > > > > > > > > +{
> > > > > > > > > > > +    struct kvm_clock_data data;
> > > > > > > > > > > +    int ret;
> > > > > > > > > > > +
> > > > > > > > > > > +    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
> > > > > > > > > > > +    if (ret < 0) {
> > > > > > > > > > > +        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
> > > > > > > > > > > +                abort();
> > > > > > > > > > > +    }
> > > > > > > > > > > +    return data.clock;
> > > > > > > > > > > +}
> > > > > > > > > > > +
> > > > > > > > > > >  static void kvmclock_vm_state_change(void *opaque, int running,
> > > > > > > > > > >                                       RunState state)
> > > > > > > > > > >  {
> > > > > > > > > > > @@ -91,15 +110,36 @@
> > > > > > > > > > 
> > > > > > > > > > Can you please use "diff -p" on your patches?
> > > > > > > > > > 
> > > > > > > > > > >  
> > > > > > > > > > >      if (running) {
> > > > > > > > > > >          struct kvm_clock_data data = {};
> > > > > > > > > > > -        uint64_t time_at_migration = kvmclock_current_nsec(s);
> > > > > > > > > > > +        uint64_t pvclock_via_mem = 0;
> > > > > > > > > > >  
> > > > > > > > > > > -        s->clock_valid = false;
> > > > > > > > > > > +        /* local (running VM) restore */
> > > > > > > > > > > +        if (s->clock_valid) {
> > > > > > > > > > > +            /*
> > > > > > > > > > > +             * if host does not support reliable KVM_GET_CLOCK,
> > > > > > > > > > > +             * read kvmclock value from memory
> > > > > > > > > > > +             */
> > > > > > > > > > > +            if (!kvm_has_adjust_clock_stable()) {
> > > > > > > > > > 
> > > > > > > > > > Why not use src_use_reliable_get_clock here, too? (Maybe rename
> > > > > > > > > > it to simply clock_is_reliable?)
> > > > > > > > > 
> > > > > > > > > Because you end up mixing two mental ideas (one: whether the source
> > > > > > > > > has KVM_GET_CLOCK, second: whether the destination has KVM_GET_CLOCK 
> > > > > > > > > into one variable). I find it more confusing than not.
> > > > > > > > > Maybe its just my limited brain but i find it
> > > > > > > > > confusing.
> > > > > > > > 
> > > > > > > > I find it simpler and easier to reason about.
> > > > > > > 
> > > > > > > I disagree, but i don't mind. Is this what you refer to:
> > > > > > > 
> > > > > > > Index: qemu-mig-advance-clock/hw/i386/kvm/clock.c
> > > > > > > ===================================================================
> > > > > > > --- qemu-mig-advance-clock.orig/hw/i386/kvm/clock.c	2016-11-17 15:11:51.372048640 -0200
> > > > > > > +++ qemu-mig-advance-clock/hw/i386/kvm/clock.c	2016-11-29 08:53:20.609817026 -0200
> > > > > > > @@ -37,11 +37,11 @@
> > > > > > >      uint64_t clock;
> > > > > > >      bool clock_valid;
> > > > > > >  
> > > > > > > -    /* whether machine supports reliable KVM_GET_CLOCK */
> > > > > > > +    /* whether machine type supports reliable get clock */
> > > > > > >      bool mach_use_reliable_get_clock;
> > > > > > >  
> > > > > > > -    /* whether source host supported reliable KVM_GET_CLOCK */
> > > > > > > -    bool src_use_reliable_get_clock;
> > > > > > > +    /* whether clock is reliable */
> > > > > > 
> > > > > > I would make the comment more explicit about its meaning:
> > > > > >   /* whether the 'clock' value was obtained in a host with
> > > > > >    * reliable KVM_GET_CLOCK */
> > > > > 
> > > > > Done.
> > > > > 
> > > > > > > +    bool clock_is_reliable;
> > > > > >
> > > > > >  } KVMClockState;
> > > > > > >  
> > > > > > >  struct pvclock_vcpu_time_info {
> > > > > > > @@ -112,25 +112,17 @@
> > > > > > >          struct kvm_clock_data data = {};
> > > > > > >          uint64_t pvclock_via_mem = 0;
> > > > > > >  
> > > > > > > -        /* local (running VM) restore */
> > > > > > > -        if (s->clock_valid) {
> > > > > > > -            /*
> > > > > > > -             * if host does not support reliable KVM_GET_CLOCK,
> > > > > > > -             * read kvmclock value from memory
> > > > > > > -             */
> > > > > > > -            if (!kvm_has_adjust_clock_stable()) {
> > > > > > > -                pvclock_via_mem = kvmclock_current_nsec(s);
> > > > > > > -            }
> > > > > > > -        /* migration/savevm/init restore */
> > > > > > > -        } else {
> > > > > > > -            /*
> > > > > > > -             * use s->clock in case machine uses reliable
> > > > > > > -             * get clock and source host supported
> > > > > > > -             * reliable get clock
> > > > > > > -             */
> > > > > > > -            if (!s->src_use_reliable_get_clock) {
> > > > > > > -                pvclock_via_mem = kvmclock_current_nsec(s);
> > > > > > > -            }
> > > > > > > +
> > > > > > 
> > > > > > A comment here would be welcome. Something like: "If the host
> > > > > > where s->clock was read did not support reliable KVM_GET_CLOCK,
> > > > > > read kvmclock value from memory".
> > > > > 
> > > > > Done.
> > > > > 
> > > > > > > +        if (!s->clock_is_reliable) {
> > > > > > > +            pvclock_via_mem = kvmclock_current_nsec(s);
> > > > > > > +        }
> > > > > > > +
> > > > > > > +        /* migration/savevm/init restore
> > > > > > > +         * update clock_is_reliable to match local
> > > > > > > +         * host capabilities.
> > > > > > > +         */
> > > > > > > +        if (s->clock_valid == false) {
> > > > > > 
> > > > > > Why the s->clock_valid check? It seems unnecessary.
> > > > > 
> > > > > Because if s->clock_valid == false (from migration),
> > > > > kvm_has_adjust_clock_stable() from the local host is irrelevant.
> > > > 
> > > > That's true, and that's why updating it on kvm_get_clock() looks
> > > > like a more logical place.
> > > 
> > > But the current patch updates
> > > s->clock_is_reliable at the "if (running)"
> > > case of kvmclock_vm_state_change().
> > > 
> > > There, both s->clock_is_reliable and s->clock are
> > > updated in sync:
> > > 
> > >         if (s->clock_valid == false) {
> > >             s->clock_is_reliable = kvm_has_adjust_clock_stable();
> > >         }
> > > 
> > >         /* We can't rely on the saved clock value, just discard it */
> > >         if (pvclock_via_mem) {
> > >             s->clock = pvclock_via_mem;
> > >         }
> > > 
> > 
> > Here s->clock is updated only to be used to set data.clock in the
> > next line (and never used again). I'm talking about every other
> > s->clock assignment in the code.
> > 
> > > However, there is no need to call kvm_get_clock() there.
> > 
> > I'm talking about the existing kvm_get_clock() calls.
> > 
> > > 
> > > kvm_get_clock() is called at the "} else {" case.
> > > 
> > > Are you suggesting to
> > > 
> > > * move s->clock_is_reliable assignment to kvm_get_clock()
> > > * move s->clock assignment to kvm_get_clock()
> > > * call kvm_get_clock() from the "if (running)" because
> > > the assignments are in that function now.
> > 
> > No.
> > 
> > > 
> > > But you don't need KVM_GET_CLOCK to be called there.
> > 
> > This is what I'm suggesting:
> > 
> > Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> > [ehabkost: simplified migration logic]
> > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> > ---
> >  hw/i386/kvm/clock.c    | 95 ++++++++++++++++++++++++++++++++++++++++++--------
> >  include/hw/i386/pc.h   |  5 +++
> >  target-i386/kvm.c      |  7 ++++
> >  target-i386/kvm_i386.h |  1 +
> >  4 files changed, 94 insertions(+), 14 deletions(-)
> > 
> > diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
> > index 0f75dd3..df07ec7 100644
> > --- a/hw/i386/kvm/clock.c
> > +++ b/hw/i386/kvm/clock.c
> > @@ -35,6 +35,13 @@ typedef struct KVMClockState {
> >      /*< public >*/
> >  
> >      uint64_t clock;
> > +    /* whether the value in 'clock' is reliable (i.e. was set by a host
> > +     * with reliable KVM_GET_CLOCK) */
> > +    bool clock_is_reliable;
> > +    /* Enable migration of clock_is_reliable. Some machine-types
> > +     * will disable it for compatibility with older QEMU versions.
> > +     */
> > +    bool migrate_reliable_flag;
> >      bool clock_valid;
> >  } KVMClockState;
> >  
> > @@ -81,6 +88,20 @@ static uint64_t kvmclock_current_nsec(KVMClockState *s)
> >      return nsec + time.system_time;
> >  }
> >  
> > +static void kvm_get_clock(KVMClockState *s)
> > +{
> > +    struct kvm_clock_data data;
> > +    int ret;
> > +
> > +    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
> > +    if (ret < 0) {
> > +        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
> > +        abort();
> > +    }
> > +    s->clock = data.clock;
> > +    s->clock_is_reliable = kvm_has_adjust_clock_stable();
> > +}
> > +
> 
> s->clock_is_reliable has to updated at migration, after 
> the first time KVM_SET_CLOCK is called. There is no other
> place where it should be updated.

I don't see why you claim that. We can simply update
s->clock_is_reliable the next time s->clock is updated. The only
code that reads s->clock checks s->clock_is_reliable first.
s->clock_is_reliable is a flag _about_ the value in s->clock. I
don't see why you want to update them at different times, if it
means more complex logic.

> This is the behaviour 
> desired, according to this table:
> 
> index:
> mig->c means use s->clock value from migration
> mig->m means read pvclock value from memory 
> (both at migration, only the first time kvmclock_change_vmstate
> is called).
> 
> runt->c means use KVM_GET_CLOCK/KVM_SET_CLOCK at runtime
> runt->m means read pvclock value from memory
> (both at runtime, after the first time kvmclock_change_vmstate
> is called).
> 
> SOURCE                DESTINATION             BEHAVIOUR
> get_clock_reliable    get_clock_reliable      mig->c,runt->c  1
> get_clock_reliable    ~get_clock_reliable     mig->c,runt->m  2
> ~get_clock_reliable   get_clock_reliable      mig->m,runt->c  3
> ~get_clock_reliable   ~get_clock_reliable     mig->m,runt->m  4
> 
> So looking at your patch below, and thinking of 
> kvm_get_clock() updating s->clock_is_reliable from 
> !running case (that is RUNNING -> ~RUNNING transition)
> makes no sense at all. That should not happen.

Why not?

> 
> s->clock_is_reliable should be updated after the first
> time ~RUNNING -> RUNNING migration is done, which 
> is my patch does.

I don't see why. All we need is that s->clock_is_reliable get
updated before any code try to read s->clock again.

> 
> I think your s->clock,s->clock_is_reliable should be in sync
> suggestion comes from a misunderstanding of how they are used.
> 
> s->clock is not read if s->clock_is_reliable is set.

Did you mean "s->clock is not read if s->clock_is_reliable is
false"? You are right (except when kvmclock_current_nsec()==0?).
But this also means that the only code that reads s->clock also
checks s->clock_is_reliable first.

> 
> Look at my attached patch below (still untested, will test and then
> resubmit) and check whether it matches the behaviour 
> described in the table above.

It seems to match. But I don't see why my patch doesn't match the
table above.

> 
> >  static void kvmclock_vm_state_change(void *opaque, int running,
> >                                       RunState state)
> >  {
> > @@ -91,16 +112,18 @@ static void kvmclock_vm_state_change(void *opaque, int running,
> >  
> >      if (running) {
> >          struct kvm_clock_data data = {};
> > -        uint64_t time_at_migration = kvmclock_current_nsec(s);
> >  
> >          s->clock_valid = false;
> >  
> > -        /* We can't rely on the migrated clock value, just discard it */
> > -        if (time_at_migration) {
> > -            s->clock = time_at_migration;
> > +        /* if host that set s->clock did not support reliable KVM_GET_CLOCK,
> > +         * read kvmclock value from memory
> > +         */
> > +        if (!s->clock_is_reliable) {
> > +            data.clock = kvmclock_current_nsec(s);
> > +        } else {
> > +            data.clock = s->clock;
> >          }
> >  
> > -        data.clock = s->clock;
> >          ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
> >          if (ret < 0) {
> >              fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(ret));
> > @@ -120,22 +143,23 @@ static void kvmclock_vm_state_change(void *opaque, int running,
> 
> >              }
> >          }
> >      } else {
> > -        struct kvm_clock_data data;
> > -        int ret;
> >  
> > +        /*FIXME: is this really possible to happen?
> > +         * Can kvmclock_vm_state_change(s, 0) be called twice without
> > +         * a kvmclock_vm_state_change(s, 1) call in between?
> > +         */
> 
> It can't: check the code where notifiers are called.

Yet another reason to simplify the code: if we don't need
different code paths for local stop/resume vs migration, we can
remove s->clock_valid completely.

> 
> >          if (s->clock_valid) {
> >              return;
> >          }
> >  
> >          kvm_synchronize_all_tsc();
> >  
> > -        ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
> > -        if (ret < 0) {
> > -            fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
> > -            abort();
> > -        }
> > -        s->clock = data.clock;
> > -
> > +        kvm_get_clock(s);
> > +        /* FIXME: the comment below doesn't match what is done at
> > +         * kvmclock_pre_save(). The comment must be updated, or
> > +         * kvmclock_pre_save() must be changed. I don't know what's
> > +         * the right thing to do.
> > +         */

We still need to address this comment. Your patch keeps the
comment that contradicts kvmclock_pre_save().

> 
> This fails for all cases (1,2,3,4) in the table above.

I can't see why it fails. The ordering of events from migration
followed by vm stop/resume should be:

    | Event                       | s->clock         | s->clock_is_reliable
src | kvmclock_vm_state_change(0) | -                | -
src |   kvm_get_clock()           | TIME-AT-VM-STOP  | CAP_ADJUST_CLOCK-on-SRC
src | kvmclock_pre_save()         | TIME-AT-VM-STOP  | CAP_ADJUST_CLOCK-on-SRC
src |   kvm_get_clock()           | TIME-AT-PRE-SAVE | CAP_ADJUST_CLOCK-on-SRC
--- | MIGRATION                   | TIME-AT-PRE-SAVE | CAP_ADJUST_CLOCK-on-SRC
dst | kvmclock_vm_state_change(1) | TIME-AT-PRE-SAVE | CAP_ADJUST_CLOCK-on-SRC
dst |   KVM_SET_CLOCK             | TIME-AT-PRE-SAVE | CAP_ADJUST_CLOCK-on-SRC
dst | kvmclock_vm_state_change(0) | TIME-AT-PRE-SAVE | CAP_ADJUST_CLOCK-on-SRC
dst |   kvm_get_clock()           | TIME-AT-VM-STOP  | CAP_ADJUST_CLOCK-on-DEST
dst | kvmclock_vm_state_change(1) | TIME-AT-VM-STOP  | CAP_ADJUST_CLOCK-on-DEST
dst |   KVM_SET_CLOCK             | TIME-AT-VM-STOP  | CAP_ADJUST_CLOCK-on-DEST

Specific cases from your table are below. See the KVM_SET_CLOCK
rows.

Case 1:

    | Event                       | s->clock         | s->clock_is_reliable
src | kvmclock_vm_state_change(0) | -                | -
src |   kvm_get_clock()           | TIME-AT-VM-STOP  | 1
src | kvmclock_pre_save()         | TIME-AT-VM-STOP  | 1
src |   kvm_get_clock()           | TIME-AT-PRE-SAVE | 1
--- | MIGRATION                   | TIME-AT-PRE-SAVE | 1
dst | kvmclock_vm_state_change(1) | TIME-AT-PRE-SAVE | 1
dst |   KVM_SET_CLOCK(s->clock)   | TIME-AT-PRE-SAVE | 1
dst | kvmclock_vm_state_change(0) | TIME-AT-PRE-SAVE | 1
dst |   kvm_get_clock()           | TIME-AT-VM-STOP  | 1
dst | kvmclock_vm_state_change(1) | TIME-AT-VM-STOP  | 1
dst |   KVM_SET_CLOCK(s->clock)   | TIME-AT-VM-STOP  | 1

Case 2:

    | Event                       | s->clock         | s->clock_is_reliable
src | kvmclock_vm_state_change(0) | -                | -
src |   kvm_get_clock()           | TIME-AT-VM-STOP  | 1
src | kvmclock_pre_save()         | TIME-AT-VM-STOP  | 1
src |   kvm_get_clock()           | TIME-AT-PRE-SAVE | 1
--- | MIGRATION                   | TIME-AT-PRE-SAVE | 1
dst | kvmclock_vm_state_change(1) | TIME-AT-PRE-SAVE | 1
dst |   KVM_SET_CLOCK(s->clock)   | TIME-AT-PRE-SAVE | 1
dst | kvmclock_vm_state_change(0) | TIME-AT-PRE-SAVE | 1
dst |   kvm_get_clock()           | TIME-AT-VM-STOP  | 0
dst | kvmclock_vm_state_change(1) | TIME-AT-VM-STOP  | 0
dst |   KVM_SET_CLOCK(from_mem)   | TIME-AT-VM-STOP  | 0

Case 3:

    | Event                       | s->clock         | s->clock_is_reliable
src | kvmclock_vm_state_change(0) | -                | -
src |   kvm_get_clock()           | TIME-AT-VM-STOP  | 0
src | kvmclock_pre_save()         | TIME-AT-VM-STOP  | 0
src |   kvm_get_clock()           | TIME-AT-PRE-SAVE | 0
--- | MIGRATION                   | TIME-AT-PRE-SAVE | 0
dst | kvmclock_vm_state_change(1) | TIME-AT-PRE-SAVE | 0
dst |   KVM_SET_CLOCK(from_mem)   | TIME-AT-PRE-SAVE | 0
dst | kvmclock_vm_state_change(0) | TIME-AT-PRE-SAVE | 0
dst |   kvm_get_clock()           | TIME-AT-VM-STOP  | 1
dst | kvmclock_vm_state_change(1) | TIME-AT-VM-STOP  | 1
dst |   KVM_SET_CLOCK(s->clock)   | TIME-AT-VM-STOP  | 1

Case 4:

    | Event                       | s->clock         | s->clock_is_reliable
src | kvmclock_vm_state_change(0) | -                | -
src |   kvm_get_clock()           | TIME-AT-VM-STOP  | 0
src | kvmclock_pre_save()         | TIME-AT-VM-STOP  | 0
src |   kvm_get_clock()           | TIME-AT-PRE-SAVE | 0
--- | MIGRATION                   | TIME-AT-PRE-SAVE | 0
dst | kvmclock_vm_state_change(1) | TIME-AT-PRE-SAVE | 0
dst |   KVM_SET_CLOCK(from_mem)   | TIME-AT-PRE-SAVE | 0
dst | kvmclock_vm_state_change(0) | TIME-AT-PRE-SAVE | 0
dst |   kvm_get_clock()           | TIME-AT-VM-STOP  | 0
dst | kvmclock_vm_state_change(1) | TIME-AT-VM-STOP  | 0
dst |   KVM_SET_CLOCK(from_mem)   | TIME-AT-VM-STOP  | 0



> 
> >          /*
> >           * If the VM is stopped, declare the clock state valid to
> >           * avoid re-reading it on next vmsave (which would return
> > @@ -152,22 +176,65 @@ static void kvmclock_realize(DeviceState *dev, Error **errp)
> >      qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
> >  }
> >  
> > +static bool kvmclock_src_use_reliable_get_clock(void *opaque)
> > +{
> > +    KVMClockState *s = opaque;
> > +
> > +    return s->migrate_reliable_flag;
> > +}
> > +
> > +static const VMStateDescription kvmclock_reliable_get_clock = {
> > +    .name = "kvmclock/clock_is_reliable",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .needed = kvmclock_src_use_reliable_get_clock,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_BOOL(clock_is_reliable, KVMClockState),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static void kvmclock_pre_save(void *opaque)
> > +{
> > +    KVMClockState *s = opaque;
> > +    /*TODO: add comment explaining why this is here:
> > +     * "re-read clock value here because [...]"" */
> > +
> > +    /*XXX: is it correct to call kvm_get_clock() here
> > +     * if s->clock_is_valid is true? (meaning the kvmclock was
> > +     * already stopped)
> > +     */
> > +    kvm_get_clock(s);
> > +}
> > +
> >  static const VMStateDescription kvmclock_vmsd = {
> >      .name = "kvmclock",
> >      .version_id = 1,
> >      .minimum_version_id = 1,
> > +    .pre_save = kvmclock_pre_save,
> >      .fields = (VMStateField[]) {
> >          VMSTATE_UINT64(clock, KVMClockState),
> >          VMSTATE_END_OF_LIST()
> > +    },
> > +    .subsections = (const VMStateDescription * []) {
> > +        &kvmclock_reliable_get_clock,
> > +        NULL
> >      }
> >  };
> >  
> > +static Property kvmclock_properties[] = {
> > +    DEFINE_PROP_BOOL("x-migrate-reliable-flag", KVMClockState,
> > +                      migrate_reliable_flag, true),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> >  static void kvmclock_class_init(ObjectClass *klass, void *data)
> >  {
> >      DeviceClass *dc = DEVICE_CLASS(klass);
> >  
> >      dc->realize = kvmclock_realize;
> >      dc->vmsd = &kvmclock_vmsd;
> > +    dc->props = kvmclock_properties;
> >  }
> >  
> >  static const TypeInfo kvmclock_info = {
> > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > index 4b74130..fb80d69 100644
> > --- a/include/hw/i386/pc.h
> > +++ b/include/hw/i386/pc.h
> > @@ -372,6 +372,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
> >  #define PC_COMPAT_2_7 \
> >      HW_COMPAT_2_7 \
> >      {\
> > +        .driver   = "kvmclock",\
> > +        .property = "x-migrate-reliable-flag",\
> > +        .value    = "off",\
> > +    },\
> > +    {\
> >          .driver   = TYPE_X86_CPU,\
> >          .property = "l3-cache",\
> >          .value    = "off",\
> > diff --git a/target-i386/kvm.c b/target-i386/kvm.c
> > index f62264a..10a9cd8 100644
> > --- a/target-i386/kvm.c
> > +++ b/target-i386/kvm.c
> > @@ -117,6 +117,13 @@ bool kvm_has_smm(void)
> >      return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM);
> >  }
> >  
> > +bool kvm_has_adjust_clock_stable(void)
> > +{
> > +    int ret = kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK);
> > +
> > +    return (ret == KVM_CLOCK_TSC_STABLE);
> > +}
> > +
> >  bool kvm_allows_irq0_override(void)
> >  {
> >      return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
> > diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h
> > index 7607929..bfce427 100644
> > --- a/target-i386/kvm_i386.h
> > +++ b/target-i386/kvm_i386.h
> > @@ -17,6 +17,7 @@
> >  
> >  bool kvm_allows_irq0_override(void);
> >  bool kvm_has_smm(void);
> > +bool kvm_has_adjust_clock_stable(void);
> >  void kvm_synchronize_all_tsc(void);
> >  void kvm_arch_reset_vcpu(X86CPU *cs);
> >  void kvm_arch_do_init_vcpu(X86CPU *cs);
> > -- 
> > 2.7.4
> > 
> > 
> > > 
> > > 
> > > > 
> > > > > 
> > > > > If s->clock_valid == true, kvm_has_adjust_clock_stable() is
> > > > > what decides whether to use KVM_GET_CLOCK or not.
> > > > > 
> > > > > > (If this is an optimization to avoid extra ioctl() calls, you can
> > > > > > cache it inside kvm_has_adjust_clock_stable()).
> > > > > 
> > > > > Its not.
> > > > > 
> > > > > > > +            s->clock_is_reliable = kvm_has_adjust_clock_stable();
> > > > > > >          }
> > > > > > 
> > > > > > This should go to kvm_get_clock(), so s->clock and
> > > > > > s->clock_is_reliable are guaranteed to be always in sync.
> > > > > 
> > > > > No: the point to change clock_is_reliable is the following: whether 
> > > > > its the first read of the clock (migration), or subsequent 
> > > > > reads (normal machine operation).
> > > > > 
> > > > > Now kvm_get_clock() just reads the clock, so i don't see it as
> > > > > the right place to change the variable.
> > > > > 
> > > > > Agreed?
> > > > 
> > > > I don't agree. clock_is_reliable is information about the current
> > > > value in s->clock, I don't see why we need to change s->clock and
> > > > s->clock_is_reliable at different places in the code.
> > > > 
> > > > Your code might work too, but I can't tell without reviewing very
> > > > carefully the state transitions KVMClockState could go through. I
> > > > don't see the point of making the state transitions in this code
> > > > even more complex, if we can simply stick to a simple "s->clock
> > > > and s->clock_is_reliable are always in sync" rule.
> > > 
> > > It is updating from the same place:
> > > 
> > >         /* migration/savevm/init restore
> > >          * update clock_is_reliable to match local
> > >          * host capabilities.
> > >          */
> > >         if (s->clock_valid == false) {
> > >             s->clock_is_reliable = kvm_has_adjust_clock_stable();
> > >         }
> > > 
> > >         /* We can't rely on the saved clock value, just discard it */
> > >         if (pvclock_via_mem) {
> > >             s->clock = pvclock_via_mem;
> > >         }
> > 
> > I'm talking about the other s->clock assignments. This one
> > doesn't even seem to be necessary.
> 
> It is necessary: this is how you read pvclock from memory.

It is not necessary if you set data.clock directly.

But this doesn't matter for this discussion. My new patch below
keeps that line, just to make the diff smaller.

> 
> > > 
> > > 
> > > > 
> > > > > 
> > > > > > >          /* We can't rely on the saved clock value, just discard it */
> > > > > > > @@ -181,20 +173,14 @@
> > > > > > >  {
> > > > > > >      KVMClockState *s = KVM_CLOCK(dev);
> > > > > > >  
> > > > > > > -    /*
> > > > > > > -     * On machine types that support reliable KVM_GET_CLOCK,
> > > > > > > -     * if host kernel does provide reliable KVM_GET_CLOCK,
> > > > > > > -     * set src_use_reliable_get_clock=true so that destination
> > > > > > > -     * avoids reading kvmclock from memory.
> > > > > > > -     */
> > > > > > > -    if (s->mach_use_reliable_get_clock && kvm_has_adjust_clock_stable()) {
> > > > > > > -        s->src_use_reliable_get_clock = true;
> > > > > > > +    if (kvm_has_adjust_clock_stable()) {
> > > > > > > +        s->clock_is_reliable = true;
> > > > > > >      }
> > > > > > >  
> > > > > > >      qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
> > > > > > >  }
> > > > > > >  
> > > > > > > -static bool kvmclock_src_use_reliable_get_clock(void *opaque)
> > > > > > > +static bool kvmclock_clock_is_reliable_needed(void *opaque)
> > > > > > >  {
> > > > > > >      KVMClockState *s = opaque;
> > > > > > >  
> > > > > > > @@ -202,12 +188,12 @@
> > > > > > >  }
> > > > > > >  
> > > > > > >  static const VMStateDescription kvmclock_reliable_get_clock = {
> > > > > > > -    .name = "kvmclock/src_use_reliable_get_clock",
> > > > > > > +    .name = "kvmclock/clock_is_reliable",
> > > > > > >      .version_id = 1,
> > > > > > >      .minimum_version_id = 1,
> > > > > > > -    .needed = kvmclock_src_use_reliable_get_clock,
> > > > > > > +    .needed = kvmclock_clock_is_reliable_needed,
> > > > > > >      .fields = (VMStateField[]) {
> > > > > > > -        VMSTATE_BOOL(src_use_reliable_get_clock, KVMClockState),
> > > > > > > +        VMSTATE_BOOL(clock_is_reliable, KVMClockState),
> > > > > > >          VMSTATE_END_OF_LIST()
> > > > > > >      }
> > > > > > >  };
> > > > > > 
> > > > > > -- 
> > > > > > Eduardo
> > > > 
> > > > -- 
> > > > Eduardo
> > 
> > -- 
> > Eduardo
> 
> 
> kvmclock: reduce kvmclock difference on migration
> 
> Check for KVM_CAP_ADJUST_CLOCK capability KVM_CLOCK_TSC_STABLE, which
> indicates that KVM_GET_CLOCK returns a value as seen by the guest at
> that moment.
> 
> For new machine types, use this value rather than reading 
> from guest memory.
> 
> This reduces kvmclock difference on migration from 5s to 0.1s
> (when max_downtime == 5s).
> 
> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> 
> ---
>  hw/i386/kvm/clock.c    |   97 +++++++++++++++++++++++++++++++++++++++++--------
>  include/hw/i386/pc.h   |    5 ++
>  target-i386/kvm.c      |    7 +++
>  target-i386/kvm_i386.h |    1 
>  4 files changed, 96 insertions(+), 14 deletions(-)
> 
> v2: 
> - improve variable names (Juan)
> - consolidate code on kvm_get_clock function (Paolo)
> - return mach_use_reliable_get_clock from needed function (Paolo)
> v3: 
> - simplify check for src_use_reliable_get_clock (Eduardo)
> - move src_use_reliable_get_clock initialization to realize (Eduardo)
> 
> 
> Index: qemu-mig-advance-clock/hw/i386/kvm/clock.c
> ===================================================================
> --- qemu-mig-advance-clock.orig/hw/i386/kvm/clock.c	2016-11-17 15:07:11.220632761 -0200
> +++ qemu-mig-advance-clock/hw/i386/kvm/clock.c	2016-12-01 12:43:18.606294830 -0200
> @@ -36,6 +36,13 @@
>  
>      uint64_t clock;
>      bool clock_valid;
> +
> +    /* whether machine type supports reliable get clock */
> +    bool mach_use_reliable_get_clock;
> +
> +    /* whether the 'clock' value was obtained in a host with
> +     * reliable KVM_GET_CLOCK */
> +    bool clock_is_reliable;
>  } KVMClockState;
>  
>  struct pvclock_vcpu_time_info {
> @@ -81,6 +88,19 @@
>      return nsec + time.system_time;
>  }
>  
> +static uint64_t kvm_get_clock(void)
> +{
> +    struct kvm_clock_data data;
> +    int ret;
> +
> +    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
> +    if (ret < 0) {
> +        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
> +                abort();
> +    }
> +    return data.clock;
> +}
> +
>  static void kvmclock_vm_state_change(void *opaque, int running,
>                                       RunState state)
>  {
> @@ -91,15 +111,31 @@
>  
>      if (running) {
>          struct kvm_clock_data data = {};
> -        uint64_t time_at_migration = kvmclock_current_nsec(s);
> +        uint64_t pvclock_via_mem = 0;
>  
> -        s->clock_valid = false;
> +        /*
> +         * If the host where s->clock was read did not support reliable
> +         * KVM_GET_CLOCK, read kvmclock value from memory.
> +         */
> +        if (!s->clock_is_reliable) {
> +            pvclock_via_mem = kvmclock_current_nsec(s);
> +        }
>  
> -        /* We can't rely on the migrated clock value, just discard it */
> -        if (time_at_migration) {
> -            s->clock = time_at_migration;
> +        /* migration/savevm/init restore
> +         * update clock_is_reliable to match local
> +         * host capabilities.
> +         */
> +        if (s->clock_valid == false) {
> +            s->clock_is_reliable = kvm_has_adjust_clock_stable();
>          }
>  

If we are reusing clock_valid for a different purpose, I suggest
we rename it to something clearer, like "clock_is_local" or
"clock_is_stopped".

But I still don't see the need for this convoluted logic, if we
can simply set s->clock_is_reliable and s->clock at the same
time. This even allow us to remove s->clock_valid completely.

> +        /* We can't rely on the saved clock value, just discard it */
> +        if (pvclock_via_mem) {
> +            s->clock = pvclock_via_mem;
> +        }
> +
> +        s->clock_valid = false;
> +

I suggest the following on top of your patch. It removes 27
unnecessary lines from the code.

But, really, I'm tired of this discussion. If you want to keep
the complex logic you suggest and others are happy with it, go
ahead. You just won't get my Reviewed-by.

But in addition to this discussion about migration_is_safe, I
have a question below about kvmclock_pre_save(), which seems to
be a real problem. See below.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 hw/i386/kvm/clock.c | 37 +++++--------------------------------
 1 file changed, 5 insertions(+), 32 deletions(-)



> +
>          data.clock = s->clock;
>          ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
>          if (ret < 0) {
> @@ -120,8 +156,6 @@
>              }
>          }
>      } else {
> -        struct kvm_clock_data data;
> -        int ret;
>  
>          if (s->clock_valid) {
>              return;
> @@ -129,13 +163,7 @@
>  
>          kvm_synchronize_all_tsc();
>  
> -        ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
> -        if (ret < 0) {
> -            fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
> -            abort();
> -        }
> -        s->clock = data.clock;
> -
> +        s->clock = kvm_get_clock();
>          /*
>           * If the VM is stopped, declare the clock state valid to
>           * avoid re-reading it on next vmsave (which would return
> @@ -149,25 +177,66 @@
>  {
>      KVMClockState *s = KVM_CLOCK(dev);
>  
> +    if (kvm_has_adjust_clock_stable()) {
> +        s->clock_is_reliable = true;
> +    }
> +
>      qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
>  }
>  
> +static bool kvmclock_clock_is_reliable_needed(void *opaque)
> +{
> +    KVMClockState *s = opaque;
> +
> +    return s->mach_use_reliable_get_clock;
> +}
> +
> +static const VMStateDescription kvmclock_reliable_get_clock = {
> +    .name = "kvmclock/clock_is_reliable",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = kvmclock_clock_is_reliable_needed,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_BOOL(clock_is_reliable, KVMClockState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void kvmclock_pre_save(void *opaque)
> +{
> +    KVMClockState *s = opaque;
> +

We still need a comment here explaining why we need to re-read
the clock on pre_save if s->clock was already set on
kvmclock_vm_state_change().

Also, what if we are migrating a VM that was already paused 10
minutes ago? Should we migrate the s->clock value from
10 minutes ago, or the one read at pre_save?

> +    s->clock = kvm_get_clock();
> +}
> +
>  static const VMStateDescription kvmclock_vmsd = {
>      .name = "kvmclock",
>      .version_id = 1,
>      .minimum_version_id = 1,
> +    .pre_save = kvmclock_pre_save,
>      .fields = (VMStateField[]) {
>          VMSTATE_UINT64(clock, KVMClockState),
>          VMSTATE_END_OF_LIST()
> +    },
> +    .subsections = (const VMStateDescription * []) {
> +        &kvmclock_reliable_get_clock,
> +        NULL
>      }
>  };
>  
> +static Property kvmclock_properties[] = {
> +    DEFINE_PROP_BOOL("x-mach-use-reliable-get-clock", KVMClockState,
> +                      mach_use_reliable_get_clock, true),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
>  static void kvmclock_class_init(ObjectClass *klass, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(klass);
>  
>      dc->realize = kvmclock_realize;
>      dc->vmsd = &kvmclock_vmsd;
> +    dc->props = kvmclock_properties;
>  }
>  
>  static const TypeInfo kvmclock_info = {
> Index: qemu-mig-advance-clock/include/hw/i386/pc.h
> ===================================================================
> --- qemu-mig-advance-clock.orig/include/hw/i386/pc.h	2016-11-17 15:07:11.220632761 -0200
> +++ qemu-mig-advance-clock/include/hw/i386/pc.h	2016-11-17 15:08:58.096791416 -0200
> @@ -370,6 +370,11 @@
>  #define PC_COMPAT_2_7 \
>      HW_COMPAT_2_7 \
>      {\
> +        .driver   = "kvmclock",\
> +        .property = "x-mach-use-reliable-get-clock",\
> +        .value    = "off",\
> +    },\
> +    {\
>          .driver   = TYPE_X86_CPU,\
>          .property = "l3-cache",\
>          .value    = "off",\
> Index: qemu-mig-advance-clock/target-i386/kvm.c
> ===================================================================
> --- qemu-mig-advance-clock.orig/target-i386/kvm.c	2016-11-17 15:07:11.221632762 -0200
> +++ qemu-mig-advance-clock/target-i386/kvm.c	2016-11-17 15:07:15.867639659 -0200
> @@ -117,6 +117,13 @@
>      return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM);
>  }
>  
> +bool kvm_has_adjust_clock_stable(void)
> +{
> +    int ret = kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK);
> +
> +    return (ret == KVM_CLOCK_TSC_STABLE);
> +}
> +
>  bool kvm_allows_irq0_override(void)
>  {
>      return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
> Index: qemu-mig-advance-clock/target-i386/kvm_i386.h
> ===================================================================
> --- qemu-mig-advance-clock.orig/target-i386/kvm_i386.h	2016-11-17 15:07:11.222632764 -0200
> +++ qemu-mig-advance-clock/target-i386/kvm_i386.h	2016-11-17 15:07:15.867639659 -0200
> @@ -17,6 +17,7 @@
>  
>  bool kvm_allows_irq0_override(void);
>  bool kvm_has_smm(void);
> +bool kvm_has_adjust_clock_stable(void);
>  void kvm_synchronize_all_tsc(void);
>  void kvm_arch_reset_vcpu(X86CPU *cs);
>  void kvm_arch_do_init_vcpu(X86CPU *cs);

Comments

Marcelo Tosatti Dec. 5, 2016, 5:20 p.m. UTC | #1
On Mon, Dec 05, 2016 at 01:17:42PM -0200, Eduardo Habkost wrote:
> On Fri, Dec 02, 2016 at 08:30:35PM -0200, Marcelo Tosatti wrote:
> > On Fri, Dec 02, 2016 at 11:56:09AM -0200, Eduardo Habkost wrote:
> > > On Thu, Dec 01, 2016 at 12:39:03PM -0200, Marcelo Tosatti wrote:
> > > > On Wed, Nov 30, 2016 at 11:09:28AM -0200, Eduardo Habkost wrote:
> > > > > On Tue, Nov 29, 2016 at 09:54:29PM -0200, Marcelo Tosatti wrote:
> > > > > > On Tue, Nov 29, 2016 at 10:34:05AM -0200, Eduardo Habkost wrote:
> > > > > > > On Tue, Nov 29, 2016 at 08:56:00AM -0200, Marcelo Tosatti wrote:
> > > > > > > > On Mon, Nov 28, 2016 at 03:12:01PM -0200, Eduardo Habkost wrote:
> > > > > > > > > On Mon, Nov 28, 2016 at 02:45:24PM -0200, Marcelo Tosatti wrote:
> > > > > > > > > > On Mon, Nov 28, 2016 at 12:13:22PM -0200, Eduardo Habkost wrote:
> > > > > > > > > > > Sorry for not noticing the following issues on the previous
> > > > > > > > > > > reviews. I was only paying attention to the vmstate and machine
> > > > > > > > > > > code:
> > > > > > > > > > > 
> > > > > > > > > > > On Mon, Nov 21, 2016 at 08:50:04AM -0200, Marcelo Tosatti wrote:
> > > > > > > > > > > > Check for KVM_CAP_ADJUST_CLOCK capability KVM_CLOCK_TSC_STABLE, which
> > > > > > > > > > > > indicates that KVM_GET_CLOCK returns a value as seen by the guest at
> > > > > > > > > > > > that moment.
> > > > > > > > > > > > 
> > > > > > > > > > > > For new machine types, use this value rather than reading 
> > > > > > > > > > > > from guest memory.
> > > > > > > > > > > > 
> > > > > > > > > > > > This reduces kvmclock difference on migration from 5s to 0.1s
> > > > > > > > > > > > (when max_downtime == 5s).
> > > > > > > > > > > > 
> > > > > > > > > > > > Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> > > > > > > > > > > > 
> > > > > > > > > > > > ---
> > > > > > > > > > > >  hw/i386/kvm/clock.c    |  107 ++++++++++++++++++++++++++++++++++++++++++-------
> > > > > > > > > > > >  include/hw/i386/pc.h   |    5 ++
> > > > > > > > > > > >  target-i386/kvm.c      |    7 +++
> > > > > > > > > > > >  target-i386/kvm_i386.h |    1 
> > > > > > > > > > > >  4 files changed, 106 insertions(+), 14 deletions(-)
> > > > > > > > > > > > 
> > > > > > > > > > > > v2: 
> > > > > > > > > > > > - improve variable names (Juan)
> > > > > > > > > > > > - consolidate code on kvm_get_clock function (Paolo)
> > > > > > > > > > > > - return mach_use_reliable_get_clock from needed function (Paolo)
> > > > > > > > > > > > v3: 
> > > > > > > > > > > > - simplify check for src_use_reliable_get_clock (Eduardo)
> > > > > > > > > > > > - move src_use_reliable_get_clock initialization to realize (Eduardo)
> > > > > > > > > > > > 
> > > > > > > > > > > > 
> > > > > > > > > > > > Index: qemu-mig-advance-clock/hw/i386/kvm/clock.c
> > > > > > > > > > > > ===================================================================
> > > > > > > > > > > > --- qemu-mig-advance-clock.orig/hw/i386/kvm/clock.c	2016-11-17 15:07:11.220632761 -0200
> > > > > > > > > > > > +++ qemu-mig-advance-clock/hw/i386/kvm/clock.c	2016-11-17 15:11:51.372048640 -0200
> > > > > > > > > > > > @@ -36,6 +36,12 @@
> > > > > > > > > > > >  
> > > > > > > > > > > >      uint64_t clock;
> > > > > > > > > > > >      bool clock_valid;
> > > > > > > > > > > > +
> > > > > > > > > > > > +    /* whether machine supports reliable KVM_GET_CLOCK */
> > > > > > > > > > > > +    bool mach_use_reliable_get_clock;
> > > > > > > > > > > > +
> > > > > > > > > > > > +    /* whether source host supported reliable KVM_GET_CLOCK */
> > > > > > > > > > > > +    bool src_use_reliable_get_clock;
> > > > > > > > > > > >  } KVMClockState;
> > > > > > > > > > > >  
> > > > > > > > > > > >  struct pvclock_vcpu_time_info {
> > > > > > > > > > > > @@ -81,6 +87,19 @@
> > > > > > > > > > > >      return nsec + time.system_time;
> > > > > > > > > > > >  }
> > > > > > > > > > > >  
> > > > > > > > > > > > +static uint64_t kvm_get_clock(void)
> > > > > > > > > > > > +{
> > > > > > > > > > > > +    struct kvm_clock_data data;
> > > > > > > > > > > > +    int ret;
> > > > > > > > > > > > +
> > > > > > > > > > > > +    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
> > > > > > > > > > > > +    if (ret < 0) {
> > > > > > > > > > > > +        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
> > > > > > > > > > > > +                abort();
> > > > > > > > > > > > +    }
> > > > > > > > > > > > +    return data.clock;
> > > > > > > > > > > > +}
> > > > > > > > > > > > +
> > > > > > > > > > > >  static void kvmclock_vm_state_change(void *opaque, int running,
> > > > > > > > > > > >                                       RunState state)
> > > > > > > > > > > >  {
> > > > > > > > > > > > @@ -91,15 +110,36 @@
> > > > > > > > > > > 
> > > > > > > > > > > Can you please use "diff -p" on your patches?
> > > > > > > > > > > 
> > > > > > > > > > > >  
> > > > > > > > > > > >      if (running) {
> > > > > > > > > > > >          struct kvm_clock_data data = {};
> > > > > > > > > > > > -        uint64_t time_at_migration = kvmclock_current_nsec(s);
> > > > > > > > > > > > +        uint64_t pvclock_via_mem = 0;
> > > > > > > > > > > >  
> > > > > > > > > > > > -        s->clock_valid = false;
> > > > > > > > > > > > +        /* local (running VM) restore */
> > > > > > > > > > > > +        if (s->clock_valid) {
> > > > > > > > > > > > +            /*
> > > > > > > > > > > > +             * if host does not support reliable KVM_GET_CLOCK,
> > > > > > > > > > > > +             * read kvmclock value from memory
> > > > > > > > > > > > +             */
> > > > > > > > > > > > +            if (!kvm_has_adjust_clock_stable()) {
> > > > > > > > > > > 
> > > > > > > > > > > Why not use src_use_reliable_get_clock here, too? (Maybe rename
> > > > > > > > > > > it to simply clock_is_reliable?)
> > > > > > > > > > 
> > > > > > > > > > Because you end up mixing two mental ideas (one: whether the source
> > > > > > > > > > has KVM_GET_CLOCK, second: whether the destination has KVM_GET_CLOCK 
> > > > > > > > > > into one variable). I find it more confusing than not.
> > > > > > > > > > Maybe its just my limited brain but i find it
> > > > > > > > > > confusing.
> > > > > > > > > 
> > > > > > > > > I find it simpler and easier to reason about.
> > > > > > > > 
> > > > > > > > I disagree, but i don't mind. Is this what you refer to:
> > > > > > > > 
> > > > > > > > Index: qemu-mig-advance-clock/hw/i386/kvm/clock.c
> > > > > > > > ===================================================================
> > > > > > > > --- qemu-mig-advance-clock.orig/hw/i386/kvm/clock.c	2016-11-17 15:11:51.372048640 -0200
> > > > > > > > +++ qemu-mig-advance-clock/hw/i386/kvm/clock.c	2016-11-29 08:53:20.609817026 -0200
> > > > > > > > @@ -37,11 +37,11 @@
> > > > > > > >      uint64_t clock;
> > > > > > > >      bool clock_valid;
> > > > > > > >  
> > > > > > > > -    /* whether machine supports reliable KVM_GET_CLOCK */
> > > > > > > > +    /* whether machine type supports reliable get clock */
> > > > > > > >      bool mach_use_reliable_get_clock;
> > > > > > > >  
> > > > > > > > -    /* whether source host supported reliable KVM_GET_CLOCK */
> > > > > > > > -    bool src_use_reliable_get_clock;
> > > > > > > > +    /* whether clock is reliable */
> > > > > > > 
> > > > > > > I would make the comment more explicit about its meaning:
> > > > > > >   /* whether the 'clock' value was obtained in a host with
> > > > > > >    * reliable KVM_GET_CLOCK */
> > > > > > 
> > > > > > Done.
> > > > > > 
> > > > > > > > +    bool clock_is_reliable;
> > > > > > >
> > > > > > >  } KVMClockState;
> > > > > > > >  
> > > > > > > >  struct pvclock_vcpu_time_info {
> > > > > > > > @@ -112,25 +112,17 @@
> > > > > > > >          struct kvm_clock_data data = {};
> > > > > > > >          uint64_t pvclock_via_mem = 0;
> > > > > > > >  
> > > > > > > > -        /* local (running VM) restore */
> > > > > > > > -        if (s->clock_valid) {
> > > > > > > > -            /*
> > > > > > > > -             * if host does not support reliable KVM_GET_CLOCK,
> > > > > > > > -             * read kvmclock value from memory
> > > > > > > > -             */
> > > > > > > > -            if (!kvm_has_adjust_clock_stable()) {
> > > > > > > > -                pvclock_via_mem = kvmclock_current_nsec(s);
> > > > > > > > -            }
> > > > > > > > -        /* migration/savevm/init restore */
> > > > > > > > -        } else {
> > > > > > > > -            /*
> > > > > > > > -             * use s->clock in case machine uses reliable
> > > > > > > > -             * get clock and source host supported
> > > > > > > > -             * reliable get clock
> > > > > > > > -             */
> > > > > > > > -            if (!s->src_use_reliable_get_clock) {
> > > > > > > > -                pvclock_via_mem = kvmclock_current_nsec(s);
> > > > > > > > -            }
> > > > > > > > +
> > > > > > > 
> > > > > > > A comment here would be welcome. Something like: "If the host
> > > > > > > where s->clock was read did not support reliable KVM_GET_CLOCK,
> > > > > > > read kvmclock value from memory".
> > > > > > 
> > > > > > Done.
> > > > > > 
> > > > > > > > +        if (!s->clock_is_reliable) {
> > > > > > > > +            pvclock_via_mem = kvmclock_current_nsec(s);
> > > > > > > > +        }
> > > > > > > > +
> > > > > > > > +        /* migration/savevm/init restore
> > > > > > > > +         * update clock_is_reliable to match local
> > > > > > > > +         * host capabilities.
> > > > > > > > +         */
> > > > > > > > +        if (s->clock_valid == false) {
> > > > > > > 
> > > > > > > Why the s->clock_valid check? It seems unnecessary.
> > > > > > 
> > > > > > Because if s->clock_valid == false (from migration),
> > > > > > kvm_has_adjust_clock_stable() from the local host is irrelevant.
> > > > > 
> > > > > That's true, and that's why updating it on kvm_get_clock() looks
> > > > > like a more logical place.
> > > > 
> > > > But the current patch updates
> > > > s->clock_is_reliable at the "if (running)"
> > > > case of kvmclock_vm_state_change().
> > > > 
> > > > There, both s->clock_is_reliable and s->clock are
> > > > updated in sync:
> > > > 
> > > >         if (s->clock_valid == false) {
> > > >             s->clock_is_reliable = kvm_has_adjust_clock_stable();
> > > >         }
> > > > 
> > > >         /* We can't rely on the saved clock value, just discard it */
> > > >         if (pvclock_via_mem) {
> > > >             s->clock = pvclock_via_mem;
> > > >         }
> > > > 
> > > 
> > > Here s->clock is updated only to be used to set data.clock in the
> > > next line (and never used again). I'm talking about every other
> > > s->clock assignment in the code.
> > > 
> > > > However, there is no need to call kvm_get_clock() there.
> > > 
> > > I'm talking about the existing kvm_get_clock() calls.
> > > 
> > > > 
> > > > kvm_get_clock() is called at the "} else {" case.
> > > > 
> > > > Are you suggesting to
> > > > 
> > > > * move s->clock_is_reliable assignment to kvm_get_clock()
> > > > * move s->clock assignment to kvm_get_clock()
> > > > * call kvm_get_clock() from the "if (running)" because
> > > > the assignments are in that function now.
> > > 
> > > No.
> > > 
> > > > 
> > > > But you don't need KVM_GET_CLOCK to be called there.
> > > 
> > > This is what I'm suggesting:
> > > 
> > > Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> > > [ehabkost: simplified migration logic]
> > > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> > > ---
> > >  hw/i386/kvm/clock.c    | 95 ++++++++++++++++++++++++++++++++++++++++++--------
> > >  include/hw/i386/pc.h   |  5 +++
> > >  target-i386/kvm.c      |  7 ++++
> > >  target-i386/kvm_i386.h |  1 +
> > >  4 files changed, 94 insertions(+), 14 deletions(-)
> > > 
> > > diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
> > > index 0f75dd3..df07ec7 100644
> > > --- a/hw/i386/kvm/clock.c
> > > +++ b/hw/i386/kvm/clock.c
> > > @@ -35,6 +35,13 @@ typedef struct KVMClockState {
> > >      /*< public >*/
> > >  
> > >      uint64_t clock;
> > > +    /* whether the value in 'clock' is reliable (i.e. was set by a host
> > > +     * with reliable KVM_GET_CLOCK) */
> > > +    bool clock_is_reliable;
> > > +    /* Enable migration of clock_is_reliable. Some machine-types
> > > +     * will disable it for compatibility with older QEMU versions.
> > > +     */
> > > +    bool migrate_reliable_flag;
> > >      bool clock_valid;
> > >  } KVMClockState;
> > >  
> > > @@ -81,6 +88,20 @@ static uint64_t kvmclock_current_nsec(KVMClockState *s)
> > >      return nsec + time.system_time;
> > >  }
> > >  
> > > +static void kvm_get_clock(KVMClockState *s)
> > > +{
> > > +    struct kvm_clock_data data;
> > > +    int ret;
> > > +
> > > +    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
> > > +    if (ret < 0) {
> > > +        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
> > > +        abort();
> > > +    }
> > > +    s->clock = data.clock;
> > > +    s->clock_is_reliable = kvm_has_adjust_clock_stable();
> > > +}
> > > +
> > 
> > s->clock_is_reliable has to updated at migration, after 
> > the first time KVM_SET_CLOCK is called. There is no other
> > place where it should be updated.
> 
> I don't see why you claim that. We can simply update
> s->clock_is_reliable the next time s->clock is updated. The only
> code that reads s->clock checks s->clock_is_reliable first.
> s->clock_is_reliable is a flag _about_ the value in s->clock. I
> don't see why you want to update them at different times, if it
> means more complex logic.

Because the table of (wanted) behaviour dictates that.

> > This is the behaviour 
> > desired, according to this table:
> > 
> > index:
> > mig->c means use s->clock value from migration
> > mig->m means read pvclock value from memory 
> > (both at migration, only the first time kvmclock_change_vmstate
> > is called).
> > 
> > runt->c means use KVM_GET_CLOCK/KVM_SET_CLOCK at runtime
> > runt->m means read pvclock value from memory
> > (both at runtime, after the first time kvmclock_change_vmstate
> > is called).
> > 
> > SOURCE                DESTINATION             BEHAVIOUR
> > get_clock_reliable    get_clock_reliable      mig->c,runt->c  1
> > get_clock_reliable    ~get_clock_reliable     mig->c,runt->m  2
> > ~get_clock_reliable   get_clock_reliable      mig->m,runt->c  3
> > ~get_clock_reliable   ~get_clock_reliable     mig->m,runt->m  4
> > 
> > So looking at your patch below, and thinking of 
> > kvm_get_clock() updating s->clock_is_reliable from 
> > !running case (that is RUNNING -> ~RUNNING transition)
> > makes no sense at all. That should not happen.
> 
> Why not?

Because we want the behaviour of the table above as follows:

First execution of ~RUNNING -> RUNNING transition:

* If source host supports reliable KVM_GET_CLOCK, then 
its not necessary to read from guest memory (because there
is no danger of KVM_GET_CLOCK returning a value which will cause 
the guest to crash).

* If source host does NOT support reliable KVM_GET_CLOCK, then 
it is necessary to read from guest memory (because there
is danger of KVM_GET_CLOCK returning a value which will cause 
the guest to crash).

Second and subsequent executions of ~RUNNING -> RUNNING transition:
(say if you pause the guest and continue it):

* If host supports reliable KVM_GET_CLOCK, then 
its not necessary to read from guest memory (because there
is no danger of KVM_GET_CLOCK returning a value which will cause 
the guest to crash).

* If  host does NOT support reliable KVM_GET_CLOCK, then 
it is necessary to read from guest memory (because there
is danger of KVM_GET_CLOCK returning a value which will cause 
the guest to crash).

Does that make sense?

> > s->clock_is_reliable should be updated after the first
> > time ~RUNNING -> RUNNING migration is done, which 
> > is my patch does.
> 
> I don't see why. All we need is that s->clock_is_reliable get
> updated before any code try to read s->clock again.

> > I think your s->clock,s->clock_is_reliable should be in sync
> > suggestion comes from a misunderstanding of how they are used.
> > 
> > s->clock is not read if s->clock_is_reliable is set.
> 
> Did you mean "s->clock is not read if s->clock_is_reliable is
> false"? You are right (except when kvmclock_current_nsec()==0?).
> But this also means that the only code that reads s->clock also
> checks s->clock_is_reliable first.
> 
> > 
> > Look at my attached patch below (still untested, will test and then
> > resubmit) and check whether it matches the behaviour 
> > described in the table above.
> 
> It seems to match. But I don't see why my patch doesn't match the
> table above.

Its just fragile Eduardo: if anyone comes and changes the
code as follows.

Source: Does not support reliable KVM_GET_CLOCK.
Destination: Does support reliable KVM_GET_CLOCK.

* Migration from remote host that does not support
  reliable KVM_GET_CLOCK, to a host that supports it.

* Some modification is done so that:

    1) Incoming migration sets s->clock_is_reliable=false from source.
    2) _Before_ vm_start(), new code decides to issue kvm_get_clock().

Your code sets s->clock_reliable = true (because local host supports
it), and failure. Do you see the problem?

(*)

> > >  static void kvmclock_vm_state_change(void *opaque, int running,
> > >                                       RunState state)
> > >  {
> > > @@ -91,16 +112,18 @@ static void kvmclock_vm_state_change(void *opaque, int running,
> > >  
> > >      if (running) {
> > >          struct kvm_clock_data data = {};
> > > -        uint64_t time_at_migration = kvmclock_current_nsec(s);
> > >  
> > >          s->clock_valid = false;
> > >  
> > > -        /* We can't rely on the migrated clock value, just discard it */
> > > -        if (time_at_migration) {
> > > -            s->clock = time_at_migration;
> > > +        /* if host that set s->clock did not support reliable KVM_GET_CLOCK,
> > > +         * read kvmclock value from memory
> > > +         */
> > > +        if (!s->clock_is_reliable) {
> > > +            data.clock = kvmclock_current_nsec(s);
> > > +        } else {
> > > +            data.clock = s->clock;
> > >          }
> > >  
> > > -        data.clock = s->clock;
> > >          ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
> > >          if (ret < 0) {
> > >              fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(ret));
> > > @@ -120,22 +143,23 @@ static void kvmclock_vm_state_change(void *opaque, int running,
> > 
> > >              }
> > >          }
> > >      } else {
> > > -        struct kvm_clock_data data;
> > > -        int ret;
> > >  
> > > +        /*FIXME: is this really possible to happen?
> > > +         * Can kvmclock_vm_state_change(s, 0) be called twice without
> > > +         * a kvmclock_vm_state_change(s, 1) call in between?
> > > +         */
> > 
> > It can't: check the code where notifiers are called.
> 
> Yet another reason to simplify the code: if we don't need
> different code paths for local stop/resume vs migration, we can
> remove s->clock_valid completely.

Yes it can be removed... But i'm just trying to fix a bug, not rewrite
code while at it.

> > >          if (s->clock_valid) {
> > >              return;
> > >          }
> > >  
> > >          kvm_synchronize_all_tsc();
> > >  
> > > -        ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
> > > -        if (ret < 0) {
> > > -            fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
> > > -            abort();
> > > -        }
> > > -        s->clock = data.clock;
> > > -
> > > +        kvm_get_clock(s);
> > > +        /* FIXME: the comment below doesn't match what is done at
> > > +         * kvmclock_pre_save(). The comment must be updated, or
> > > +         * kvmclock_pre_save() must be changed. I don't know what's
> > > +         * the right thing to do.
> > > +         */
> 
> We still need to address this comment. Your patch keeps the
> comment that contradicts kvmclock_pre_save().

The comment refers to the fact that you should not do:

    Event stop_vm()
       saved_clock1 = KVM_GET_CLOCK.

    Then again with the VM stopped, overwrite saved_clock:
        saved_clock2 = KVM_GET_CLOCK.

    You should always use saved_clock1. Thats what its about.

Updated it.

> 
> > 
> > This fails for all cases (1,2,3,4) in the table above.
> 
> I can't see why it fails. The ordering of events from migration
> followed by vm stop/resume should be:
> 
>     | Event                       | s->clock         | s->clock_is_reliable
> src | kvmclock_vm_state_change(0) | -                | -
> src |   kvm_get_clock()           | TIME-AT-VM-STOP  | CAP_ADJUST_CLOCK-on-SRC
> src | kvmclock_pre_save()         | TIME-AT-VM-STOP  | CAP_ADJUST_CLOCK-on-SRC
> src |   kvm_get_clock()           | TIME-AT-PRE-SAVE | CAP_ADJUST_CLOCK-on-SRC
> --- | MIGRATION                   | TIME-AT-PRE-SAVE | CAP_ADJUST_CLOCK-on-SRC
> dst | kvmclock_vm_state_change(1) | TIME-AT-PRE-SAVE | CAP_ADJUST_CLOCK-on-SRC
> dst |   KVM_SET_CLOCK             | TIME-AT-PRE-SAVE | CAP_ADJUST_CLOCK-on-SRC
> dst | kvmclock_vm_state_change(0) | TIME-AT-PRE-SAVE | CAP_ADJUST_CLOCK-on-SRC
> dst |   kvm_get_clock()           | TIME-AT-VM-STOP  | CAP_ADJUST_CLOCK-on-DEST
> dst | kvmclock_vm_state_change(1) | TIME-AT-VM-STOP  | CAP_ADJUST_CLOCK-on-DEST
> dst |   KVM_SET_CLOCK             | TIME-AT-VM-STOP  | CAP_ADJUST_CLOCK-on-DEST
> 
> Specific cases from your table are below. See the KVM_SET_CLOCK
> rows.
> 
> Case 1:
> 
>     | Event                       | s->clock         | s->clock_is_reliable
> src | kvmclock_vm_state_change(0) | -                | -
> src |   kvm_get_clock()           | TIME-AT-VM-STOP  | 1
> src | kvmclock_pre_save()         | TIME-AT-VM-STOP  | 1
> src |   kvm_get_clock()           | TIME-AT-PRE-SAVE | 1
> --- | MIGRATION                   | TIME-AT-PRE-SAVE | 1
> dst | kvmclock_vm_state_change(1) | TIME-AT-PRE-SAVE | 1
> dst |   KVM_SET_CLOCK(s->clock)   | TIME-AT-PRE-SAVE | 1
> dst | kvmclock_vm_state_change(0) | TIME-AT-PRE-SAVE | 1
> dst |   kvm_get_clock()           | TIME-AT-VM-STOP  | 1
> dst | kvmclock_vm_state_change(1) | TIME-AT-VM-STOP  | 1
> dst |   KVM_SET_CLOCK(s->clock)   | TIME-AT-VM-STOP  | 1
> 
> Case 2:
> 
>     | Event                       | s->clock         | s->clock_is_reliable
> src | kvmclock_vm_state_change(0) | -                | -
> src |   kvm_get_clock()           | TIME-AT-VM-STOP  | 1
> src | kvmclock_pre_save()         | TIME-AT-VM-STOP  | 1
> src |   kvm_get_clock()           | TIME-AT-PRE-SAVE | 1
> --- | MIGRATION                   | TIME-AT-PRE-SAVE | 1
> dst | kvmclock_vm_state_change(1) | TIME-AT-PRE-SAVE | 1
> dst |   KVM_SET_CLOCK(s->clock)   | TIME-AT-PRE-SAVE | 1
> dst | kvmclock_vm_state_change(0) | TIME-AT-PRE-SAVE | 1
> dst |   kvm_get_clock()           | TIME-AT-VM-STOP  | 0
> dst | kvmclock_vm_state_change(1) | TIME-AT-VM-STOP  | 0
> dst |   KVM_SET_CLOCK(from_mem)   | TIME-AT-VM-STOP  | 0
> 
> Case 3:
> 
>     | Event                       | s->clock         | s->clock_is_reliable
> src | kvmclock_vm_state_change(0) | -                | -
> src |   kvm_get_clock()           | TIME-AT-VM-STOP  | 0
> src | kvmclock_pre_save()         | TIME-AT-VM-STOP  | 0
> src |   kvm_get_clock()           | TIME-AT-PRE-SAVE | 0
> --- | MIGRATION                   | TIME-AT-PRE-SAVE | 0
> dst | kvmclock_vm_state_change(1) | TIME-AT-PRE-SAVE | 0
> dst |   KVM_SET_CLOCK(from_mem)   | TIME-AT-PRE-SAVE | 0
> dst | kvmclock_vm_state_change(0) | TIME-AT-PRE-SAVE | 0
> dst |   kvm_get_clock()           | TIME-AT-VM-STOP  | 1
> dst | kvmclock_vm_state_change(1) | TIME-AT-VM-STOP  | 1
> dst |   KVM_SET_CLOCK(s->clock)   | TIME-AT-VM-STOP  | 1
> 
> Case 4:
> 
>     | Event                       | s->clock         | s->clock_is_reliable
> src | kvmclock_vm_state_change(0) | -                | -
> src |   kvm_get_clock()           | TIME-AT-VM-STOP  | 0
> src | kvmclock_pre_save()         | TIME-AT-VM-STOP  | 0
> src |   kvm_get_clock()           | TIME-AT-PRE-SAVE | 0
> --- | MIGRATION                   | TIME-AT-PRE-SAVE | 0
> dst | kvmclock_vm_state_change(1) | TIME-AT-PRE-SAVE | 0
> dst |   KVM_SET_CLOCK(from_mem)   | TIME-AT-PRE-SAVE | 0
> dst | kvmclock_vm_state_change(0) | TIME-AT-PRE-SAVE | 0
> dst |   kvm_get_clock()           | TIME-AT-VM-STOP  | 0
> dst | kvmclock_vm_state_change(1) | TIME-AT-VM-STOP  | 0
> dst |   KVM_SET_CLOCK(from_mem)   | TIME-AT-VM-STOP  | 0
> 
> 
> 
> > 
> > >          /*
> > >           * If the VM is stopped, declare the clock state valid to
> > >           * avoid re-reading it on next vmsave (which would return
> > > @@ -152,22 +176,65 @@ static void kvmclock_realize(DeviceState *dev, Error **errp)
> > >      qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
> > >  }
> > >  
> > > +static bool kvmclock_src_use_reliable_get_clock(void *opaque)
> > > +{
> > > +    KVMClockState *s = opaque;
> > > +
> > > +    return s->migrate_reliable_flag;
> > > +}
> > > +
> > > +static const VMStateDescription kvmclock_reliable_get_clock = {
> > > +    .name = "kvmclock/clock_is_reliable",
> > > +    .version_id = 1,
> > > +    .minimum_version_id = 1,
> > > +    .needed = kvmclock_src_use_reliable_get_clock,
> > > +    .fields = (VMStateField[]) {
> > > +        VMSTATE_BOOL(clock_is_reliable, KVMClockState),
> > > +        VMSTATE_END_OF_LIST()
> > > +    }
> > > +};
> > > +
> > > +static void kvmclock_pre_save(void *opaque)
> > > +{
> > > +    KVMClockState *s = opaque;
> > > +    /*TODO: add comment explaining why this is here:
> > > +     * "re-read clock value here because [...]"" */
> > > +
> > > +    /*XXX: is it correct to call kvm_get_clock() here
> > > +     * if s->clock_is_valid is true? (meaning the kvmclock was
> > > +     * already stopped)
> > > +     */
> > > +    kvm_get_clock(s);
> > > +}
> > > +
> > >  static const VMStateDescription kvmclock_vmsd = {
> > >      .name = "kvmclock",
> > >      .version_id = 1,
> > >      .minimum_version_id = 1,
> > > +    .pre_save = kvmclock_pre_save,
> > >      .fields = (VMStateField[]) {
> > >          VMSTATE_UINT64(clock, KVMClockState),
> > >          VMSTATE_END_OF_LIST()
> > > +    },
> > > +    .subsections = (const VMStateDescription * []) {
> > > +        &kvmclock_reliable_get_clock,
> > > +        NULL
> > >      }
> > >  };
> > >  
> > > +static Property kvmclock_properties[] = {
> > > +    DEFINE_PROP_BOOL("x-migrate-reliable-flag", KVMClockState,
> > > +                      migrate_reliable_flag, true),
> > > +    DEFINE_PROP_END_OF_LIST(),
> > > +};
> > > +
> > >  static void kvmclock_class_init(ObjectClass *klass, void *data)
> > >  {
> > >      DeviceClass *dc = DEVICE_CLASS(klass);
> > >  
> > >      dc->realize = kvmclock_realize;
> > >      dc->vmsd = &kvmclock_vmsd;
> > > +    dc->props = kvmclock_properties;
> > >  }
> > >  
> > >  static const TypeInfo kvmclock_info = {
> > > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > > index 4b74130..fb80d69 100644
> > > --- a/include/hw/i386/pc.h
> > > +++ b/include/hw/i386/pc.h
> > > @@ -372,6 +372,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
> > >  #define PC_COMPAT_2_7 \
> > >      HW_COMPAT_2_7 \
> > >      {\
> > > +        .driver   = "kvmclock",\
> > > +        .property = "x-migrate-reliable-flag",\
> > > +        .value    = "off",\
> > > +    },\
> > > +    {\
> > >          .driver   = TYPE_X86_CPU,\
> > >          .property = "l3-cache",\
> > >          .value    = "off",\
> > > diff --git a/target-i386/kvm.c b/target-i386/kvm.c
> > > index f62264a..10a9cd8 100644
> > > --- a/target-i386/kvm.c
> > > +++ b/target-i386/kvm.c
> > > @@ -117,6 +117,13 @@ bool kvm_has_smm(void)
> > >      return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM);
> > >  }
> > >  
> > > +bool kvm_has_adjust_clock_stable(void)
> > > +{
> > > +    int ret = kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK);
> > > +
> > > +    return (ret == KVM_CLOCK_TSC_STABLE);
> > > +}
> > > +
> > >  bool kvm_allows_irq0_override(void)
> > >  {
> > >      return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
> > > diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h
> > > index 7607929..bfce427 100644
> > > --- a/target-i386/kvm_i386.h
> > > +++ b/target-i386/kvm_i386.h
> > > @@ -17,6 +17,7 @@
> > >  
> > >  bool kvm_allows_irq0_override(void);
> > >  bool kvm_has_smm(void);
> > > +bool kvm_has_adjust_clock_stable(void);
> > >  void kvm_synchronize_all_tsc(void);
> > >  void kvm_arch_reset_vcpu(X86CPU *cs);
> > >  void kvm_arch_do_init_vcpu(X86CPU *cs);
> > > -- 
> > > 2.7.4
> > > 
> > > 
> > > > 
> > > > 
> > > > > 
> > > > > > 
> > > > > > If s->clock_valid == true, kvm_has_adjust_clock_stable() is
> > > > > > what decides whether to use KVM_GET_CLOCK or not.
> > > > > > 
> > > > > > > (If this is an optimization to avoid extra ioctl() calls, you can
> > > > > > > cache it inside kvm_has_adjust_clock_stable()).
> > > > > > 
> > > > > > Its not.
> > > > > > 
> > > > > > > > +            s->clock_is_reliable = kvm_has_adjust_clock_stable();
> > > > > > > >          }
> > > > > > > 
> > > > > > > This should go to kvm_get_clock(), so s->clock and
> > > > > > > s->clock_is_reliable are guaranteed to be always in sync.
> > > > > > 
> > > > > > No: the point to change clock_is_reliable is the following: whether 
> > > > > > its the first read of the clock (migration), or subsequent 
> > > > > > reads (normal machine operation).
> > > > > > 
> > > > > > Now kvm_get_clock() just reads the clock, so i don't see it as
> > > > > > the right place to change the variable.
> > > > > > 
> > > > > > Agreed?
> > > > > 
> > > > > I don't agree. clock_is_reliable is information about the current
> > > > > value in s->clock, I don't see why we need to change s->clock and
> > > > > s->clock_is_reliable at different places in the code.
> > > > > 
> > > > > Your code might work too, but I can't tell without reviewing very
> > > > > carefully the state transitions KVMClockState could go through. I
> > > > > don't see the point of making the state transitions in this code
> > > > > even more complex, if we can simply stick to a simple "s->clock
> > > > > and s->clock_is_reliable are always in sync" rule.
> > > > 
> > > > It is updating from the same place:
> > > > 
> > > >         /* migration/savevm/init restore
> > > >          * update clock_is_reliable to match local
> > > >          * host capabilities.
> > > >          */
> > > >         if (s->clock_valid == false) {
> > > >             s->clock_is_reliable = kvm_has_adjust_clock_stable();
> > > >         }
> > > > 
> > > >         /* We can't rely on the saved clock value, just discard it */
> > > >         if (pvclock_via_mem) {
> > > >             s->clock = pvclock_via_mem;
> > > >         }
> > > 
> > > I'm talking about the other s->clock assignments. This one
> > > doesn't even seem to be necessary.
> > 
> > It is necessary: this is how you read pvclock from memory.
> 
> It is not necessary if you set data.clock directly.
> 
> But this doesn't matter for this discussion. My new patch below
> keeps that line, just to make the diff smaller.
> 
> > 
> > > > 
> > > > 
> > > > > 
> > > > > > 
> > > > > > > >          /* We can't rely on the saved clock value, just discard it */
> > > > > > > > @@ -181,20 +173,14 @@
> > > > > > > >  {
> > > > > > > >      KVMClockState *s = KVM_CLOCK(dev);
> > > > > > > >  
> > > > > > > > -    /*
> > > > > > > > -     * On machine types that support reliable KVM_GET_CLOCK,
> > > > > > > > -     * if host kernel does provide reliable KVM_GET_CLOCK,
> > > > > > > > -     * set src_use_reliable_get_clock=true so that destination
> > > > > > > > -     * avoids reading kvmclock from memory.
> > > > > > > > -     */
> > > > > > > > -    if (s->mach_use_reliable_get_clock && kvm_has_adjust_clock_stable()) {
> > > > > > > > -        s->src_use_reliable_get_clock = true;
> > > > > > > > +    if (kvm_has_adjust_clock_stable()) {
> > > > > > > > +        s->clock_is_reliable = true;
> > > > > > > >      }
> > > > > > > >  
> > > > > > > >      qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
> > > > > > > >  }
> > > > > > > >  
> > > > > > > > -static bool kvmclock_src_use_reliable_get_clock(void *opaque)
> > > > > > > > +static bool kvmclock_clock_is_reliable_needed(void *opaque)
> > > > > > > >  {
> > > > > > > >      KVMClockState *s = opaque;
> > > > > > > >  
> > > > > > > > @@ -202,12 +188,12 @@
> > > > > > > >  }
> > > > > > > >  
> > > > > > > >  static const VMStateDescription kvmclock_reliable_get_clock = {
> > > > > > > > -    .name = "kvmclock/src_use_reliable_get_clock",
> > > > > > > > +    .name = "kvmclock/clock_is_reliable",
> > > > > > > >      .version_id = 1,
> > > > > > > >      .minimum_version_id = 1,
> > > > > > > > -    .needed = kvmclock_src_use_reliable_get_clock,
> > > > > > > > +    .needed = kvmclock_clock_is_reliable_needed,
> > > > > > > >      .fields = (VMStateField[]) {
> > > > > > > > -        VMSTATE_BOOL(src_use_reliable_get_clock, KVMClockState),
> > > > > > > > +        VMSTATE_BOOL(clock_is_reliable, KVMClockState),
> > > > > > > >          VMSTATE_END_OF_LIST()
> > > > > > > >      }
> > > > > > > >  };
> > > > > > > 
> > > > > > > -- 
> > > > > > > Eduardo
> > > > > 
> > > > > -- 
> > > > > Eduardo
> > > 
> > > -- 
> > > Eduardo
> > 
> > 
> > kvmclock: reduce kvmclock difference on migration
> > 
> > Check for KVM_CAP_ADJUST_CLOCK capability KVM_CLOCK_TSC_STABLE, which
> > indicates that KVM_GET_CLOCK returns a value as seen by the guest at
> > that moment.
> > 
> > For new machine types, use this value rather than reading 
> > from guest memory.
> > 
> > This reduces kvmclock difference on migration from 5s to 0.1s
> > (when max_downtime == 5s).
> > 
> > Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> > 
> > ---
> >  hw/i386/kvm/clock.c    |   97 +++++++++++++++++++++++++++++++++++++++++--------
> >  include/hw/i386/pc.h   |    5 ++
> >  target-i386/kvm.c      |    7 +++
> >  target-i386/kvm_i386.h |    1 
> >  4 files changed, 96 insertions(+), 14 deletions(-)
> > 
> > v2: 
> > - improve variable names (Juan)
> > - consolidate code on kvm_get_clock function (Paolo)
> > - return mach_use_reliable_get_clock from needed function (Paolo)
> > v3: 
> > - simplify check for src_use_reliable_get_clock (Eduardo)
> > - move src_use_reliable_get_clock initialization to realize (Eduardo)
> > 
> > 
> > Index: qemu-mig-advance-clock/hw/i386/kvm/clock.c
> > ===================================================================
> > --- qemu-mig-advance-clock.orig/hw/i386/kvm/clock.c	2016-11-17 15:07:11.220632761 -0200
> > +++ qemu-mig-advance-clock/hw/i386/kvm/clock.c	2016-12-01 12:43:18.606294830 -0200
> > @@ -36,6 +36,13 @@
> >  
> >      uint64_t clock;
> >      bool clock_valid;
> > +
> > +    /* whether machine type supports reliable get clock */
> > +    bool mach_use_reliable_get_clock;
> > +
> > +    /* whether the 'clock' value was obtained in a host with
> > +     * reliable KVM_GET_CLOCK */
> > +    bool clock_is_reliable;
> >  } KVMClockState;
> >  
> >  struct pvclock_vcpu_time_info {
> > @@ -81,6 +88,19 @@
> >      return nsec + time.system_time;
> >  }
> >  
> > +static uint64_t kvm_get_clock(void)
> > +{
> > +    struct kvm_clock_data data;
> > +    int ret;
> > +
> > +    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
> > +    if (ret < 0) {
> > +        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
> > +                abort();
> > +    }
> > +    return data.clock;
> > +}
> > +
> >  static void kvmclock_vm_state_change(void *opaque, int running,
> >                                       RunState state)
> >  {
> > @@ -91,15 +111,31 @@
> >  
> >      if (running) {
> >          struct kvm_clock_data data = {};
> > -        uint64_t time_at_migration = kvmclock_current_nsec(s);
> > +        uint64_t pvclock_via_mem = 0;
> >  
> > -        s->clock_valid = false;
> > +        /*
> > +         * If the host where s->clock was read did not support reliable
> > +         * KVM_GET_CLOCK, read kvmclock value from memory.
> > +         */
> > +        if (!s->clock_is_reliable) {
> > +            pvclock_via_mem = kvmclock_current_nsec(s);
> > +        }
> >  
> > -        /* We can't rely on the migrated clock value, just discard it */
> > -        if (time_at_migration) {
> > -            s->clock = time_at_migration;
> > +        /* migration/savevm/init restore
> > +         * update clock_is_reliable to match local
> > +         * host capabilities.
> > +         */
> > +        if (s->clock_valid == false) {
> > +            s->clock_is_reliable = kvm_has_adjust_clock_stable();
> >          }
> >  
> 
> If we are reusing clock_valid for a different purpose, I suggest
> we rename it to something clearer, like "clock_is_local" or
> "clock_is_stopped".
> 
> But I still don't see the need for this convoluted logic, if we
> can simply set s->clock_is_reliable and s->clock at the same
> time. This even allow us to remove s->clock_valid completely.
> 
> > +        /* We can't rely on the saved clock value, just discard it */
> > +        if (pvclock_via_mem) {
> > +            s->clock = pvclock_via_mem;
> > +        }
> > +
> > +        s->clock_valid = false;
> > +
> 
> I suggest the following on top of your patch. It removes 27
> unnecessary lines from the code.
> 
> But, really, I'm tired of this discussion. If you want to keep
> the complex logic you suggest and others are happy with it, go
> ahead. You just won't get my Reviewed-by.

I have been addressing all the comments you made so far Eduardo, 
and have a point at (*) which seems valid to me.
This is the reason the patch is the way it is now.

But sure, i will include your next patch in the series, test 
it, and if someone does kvm_get_clock() in between those two
points in the code, then it'll break. I'll add a
comment to that effect to warn users.

> But in addition to this discussion about migration_is_safe, I
> have a question below about kvmclock_pre_save(), which seems to
> be a real problem. See below.
> 
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> ---
>  hw/i386/kvm/clock.c | 37 +++++--------------------------------
>  1 file changed, 5 insertions(+), 32 deletions(-)
> 
> diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
> index e179862..359abce 100644
> --- a/hw/i386/kvm/clock.c
> +++ b/hw/i386/kvm/clock.c
> @@ -35,8 +35,6 @@ typedef struct KVMClockState {
>      /*< public >*/
>  
>      uint64_t clock;
> -    bool clock_valid;
> -
>      /* whether machine type supports reliable get clock */
>      bool mach_use_reliable_get_clock;
>  
> @@ -88,7 +86,7 @@ static uint64_t kvmclock_current_nsec(KVMClockState *s)
>      return nsec + time.system_time;
>  }
>  
> -static uint64_t kvm_get_clock(void)
> +static void kvm_get_clock(KVMClockState *s)
>  {
>      struct kvm_clock_data data;
>      int ret;
> @@ -98,7 +96,8 @@ static uint64_t kvm_get_clock(void)
>          fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
>                  abort();
>      }
> -    return data.clock;
> +    s->clock = data.clock;
> +    s->clock_is_reliable = kvm_has_adjust_clock_stable();
>  }
>  
>  static void kvmclock_vm_state_change(void *opaque, int running,
> @@ -121,21 +120,11 @@ static void kvmclock_vm_state_change(void *opaque, int running,
>              pvclock_via_mem = kvmclock_current_nsec(s);
>          }
>  
> -        /* migration/savevm/init restore
> -         * update clock_is_reliable to match local
> -         * host capabilities.
> -         */
> -        if (s->clock_valid == false) {
> -            s->clock_is_reliable = kvm_has_adjust_clock_stable();
> -        }
>          /* We can't rely on the saved clock value, just discard it */
>          if (pvclock_via_mem) {
>              s->clock = pvclock_via_mem;
>          }
>  
> -        s->clock_valid = false;
> -
>          data.clock = s->clock;
>          ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
>          if (ret < 0) {
> @@ -156,20 +145,8 @@ static void kvmclock_vm_state_change(void *opaque, int running,
>              }
>          }
>      } else {
> -
> -        if (s->clock_valid) {
> -            return;
> -        }
> -
>          kvm_synchronize_all_tsc();
> -
> -        s->clock = kvm_get_clock();
> -        /*
> -         * If the VM is stopped, declare the clock state valid to
> -         * avoid re-reading it on next vmsave (which would return
> -         * a different value). Will be reset when the VM is continued.
> -         */
> -        s->clock_valid = true;
> +        kvm_get_clock(s);
>      }
>  }
>  
> @@ -177,10 +154,6 @@ static void kvmclock_realize(DeviceState *dev, Error **errp)
>  {
>      KVMClockState *s = KVM_CLOCK(dev);
>  
> -    if (kvm_has_adjust_clock_stable()) {
> -        s->clock_is_reliable = true;
> -    }
> -
>      qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
>  }
>  
> @@ -206,7 +179,7 @@ static void kvmclock_pre_save(void *opaque)
>  {
>      KVMClockState *s = opaque;
>  
> -    s->clock = kvm_get_clock();
> +    kvm_get_clock(s);
>  }
>  
>  static const VMStateDescription kvmclock_vmsd = {
> 
> 
> > +
> >          data.clock = s->clock;
> >          ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
> >          if (ret < 0) {
> > @@ -120,8 +156,6 @@
> >              }
> >          }
> >      } else {
> > -        struct kvm_clock_data data;
> > -        int ret;
> >  
> >          if (s->clock_valid) {
> >              return;
> > @@ -129,13 +163,7 @@
> >  
> >          kvm_synchronize_all_tsc();
> >  
> > -        ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
> > -        if (ret < 0) {
> > -            fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
> > -            abort();
> > -        }
> > -        s->clock = data.clock;
> > -
> > +        s->clock = kvm_get_clock();
> >          /*
> >           * If the VM is stopped, declare the clock state valid to
> >           * avoid re-reading it on next vmsave (which would return
> > @@ -149,25 +177,66 @@
> >  {
> >      KVMClockState *s = KVM_CLOCK(dev);
> >  
> > +    if (kvm_has_adjust_clock_stable()) {
> > +        s->clock_is_reliable = true;
> > +    }
> > +
> >      qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
> >  }
> >  
> > +static bool kvmclock_clock_is_reliable_needed(void *opaque)
> > +{
> > +    KVMClockState *s = opaque;
> > +
> > +    return s->mach_use_reliable_get_clock;
> > +}
> > +
> > +static const VMStateDescription kvmclock_reliable_get_clock = {
> > +    .name = "kvmclock/clock_is_reliable",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .needed = kvmclock_clock_is_reliable_needed,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_BOOL(clock_is_reliable, KVMClockState),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static void kvmclock_pre_save(void *opaque)
> > +{
> > +    KVMClockState *s = opaque;
> > +
> 
> We still need a comment here explaining why we need to re-read
> the clock on pre_save if s->clock was already set on
> kvmclock_vm_state_change().

OK.

> Also, what if we are migrating a VM that was already paused 10
> minutes ago? Should we migrate the s->clock value from
> 10 minutes ago, or the one read at pre_save?

The one read at pre_save. I'll add a comment.

> > +    s->clock = kvm_get_clock();
> > +}
> > +
> >  static const VMStateDescription kvmclock_vmsd = {
> >      .name = "kvmclock",
> >      .version_id = 1,
> >      .minimum_version_id = 1,
> > +    .pre_save = kvmclock_pre_save,
> >      .fields = (VMStateField[]) {
> >          VMSTATE_UINT64(clock, KVMClockState),
> >          VMSTATE_END_OF_LIST()
> > +    },
> > +    .subsections = (const VMStateDescription * []) {
> > +        &kvmclock_reliable_get_clock,
> > +        NULL
> >      }
> >  };
> >  
> > +static Property kvmclock_properties[] = {
> > +    DEFINE_PROP_BOOL("x-mach-use-reliable-get-clock", KVMClockState,
> > +                      mach_use_reliable_get_clock, true),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> >  static void kvmclock_class_init(ObjectClass *klass, void *data)
> >  {
> >      DeviceClass *dc = DEVICE_CLASS(klass);
> >  
> >      dc->realize = kvmclock_realize;
> >      dc->vmsd = &kvmclock_vmsd;
> > +    dc->props = kvmclock_properties;
> >  }
> >  
> >  static const TypeInfo kvmclock_info = {
> > Index: qemu-mig-advance-clock/include/hw/i386/pc.h
> > ===================================================================
> > --- qemu-mig-advance-clock.orig/include/hw/i386/pc.h	2016-11-17 15:07:11.220632761 -0200
> > +++ qemu-mig-advance-clock/include/hw/i386/pc.h	2016-11-17 15:08:58.096791416 -0200
> > @@ -370,6 +370,11 @@
> >  #define PC_COMPAT_2_7 \
> >      HW_COMPAT_2_7 \
> >      {\
> > +        .driver   = "kvmclock",\
> > +        .property = "x-mach-use-reliable-get-clock",\
> > +        .value    = "off",\
> > +    },\
> > +    {\
> >          .driver   = TYPE_X86_CPU,\
> >          .property = "l3-cache",\
> >          .value    = "off",\
> > Index: qemu-mig-advance-clock/target-i386/kvm.c
> > ===================================================================
> > --- qemu-mig-advance-clock.orig/target-i386/kvm.c	2016-11-17 15:07:11.221632762 -0200
> > +++ qemu-mig-advance-clock/target-i386/kvm.c	2016-11-17 15:07:15.867639659 -0200
> > @@ -117,6 +117,13 @@
> >      return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM);
> >  }
> >  
> > +bool kvm_has_adjust_clock_stable(void)
> > +{
> > +    int ret = kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK);
> > +
> > +    return (ret == KVM_CLOCK_TSC_STABLE);
> > +}
> > +
> >  bool kvm_allows_irq0_override(void)
> >  {
> >      return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
> > Index: qemu-mig-advance-clock/target-i386/kvm_i386.h
> > ===================================================================
> > --- qemu-mig-advance-clock.orig/target-i386/kvm_i386.h	2016-11-17 15:07:11.222632764 -0200
> > +++ qemu-mig-advance-clock/target-i386/kvm_i386.h	2016-11-17 15:07:15.867639659 -0200
> > @@ -17,6 +17,7 @@
> >  
> >  bool kvm_allows_irq0_override(void);
> >  bool kvm_has_smm(void);
> > +bool kvm_has_adjust_clock_stable(void);
> >  void kvm_synchronize_all_tsc(void);
> >  void kvm_arch_reset_vcpu(X86CPU *cs);
> >  void kvm_arch_do_init_vcpu(X86CPU *cs);
> 
> -- 
> Eduardo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
index e179862..359abce 100644
--- a/hw/i386/kvm/clock.c
+++ b/hw/i386/kvm/clock.c
@@ -35,8 +35,6 @@  typedef struct KVMClockState {
     /*< public >*/
 
     uint64_t clock;
-    bool clock_valid;
-
     /* whether machine type supports reliable get clock */
     bool mach_use_reliable_get_clock;
 
@@ -88,7 +86,7 @@  static uint64_t kvmclock_current_nsec(KVMClockState *s)
     return nsec + time.system_time;
 }
 
-static uint64_t kvm_get_clock(void)
+static void kvm_get_clock(KVMClockState *s)
 {
     struct kvm_clock_data data;
     int ret;
@@ -98,7 +96,8 @@  static uint64_t kvm_get_clock(void)
         fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
                 abort();
     }
-    return data.clock;
+    s->clock = data.clock;
+    s->clock_is_reliable = kvm_has_adjust_clock_stable();
 }
 
 static void kvmclock_vm_state_change(void *opaque, int running,
@@ -121,21 +120,11 @@  static void kvmclock_vm_state_change(void *opaque, int running,
             pvclock_via_mem = kvmclock_current_nsec(s);
         }
 
-        /* migration/savevm/init restore
-         * update clock_is_reliable to match local
-         * host capabilities.
-         */
-        if (s->clock_valid == false) {
-            s->clock_is_reliable = kvm_has_adjust_clock_stable();
-        }
-
         /* We can't rely on the saved clock value, just discard it */
         if (pvclock_via_mem) {
             s->clock = pvclock_via_mem;
         }
 
-        s->clock_valid = false;
-
         data.clock = s->clock;
         ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
         if (ret < 0) {
@@ -156,20 +145,8 @@  static void kvmclock_vm_state_change(void *opaque, int running,
             }
         }
     } else {
-
-        if (s->clock_valid) {
-            return;
-        }
-
         kvm_synchronize_all_tsc();
-
-        s->clock = kvm_get_clock();
-        /*
-         * If the VM is stopped, declare the clock state valid to
-         * avoid re-reading it on next vmsave (which would return
-         * a different value). Will be reset when the VM is continued.
-         */
-        s->clock_valid = true;
+        kvm_get_clock(s);
     }
 }
 
@@ -177,10 +154,6 @@  static void kvmclock_realize(DeviceState *dev, Error **errp)
 {
     KVMClockState *s = KVM_CLOCK(dev);
 
-    if (kvm_has_adjust_clock_stable()) {
-        s->clock_is_reliable = true;
-    }
-
     qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
 }
 
@@ -206,7 +179,7 @@  static void kvmclock_pre_save(void *opaque)
 {
     KVMClockState *s = opaque;
 
-    s->clock = kvm_get_clock();
+    kvm_get_clock(s);
 }
 
 static const VMStateDescription kvmclock_vmsd = {