[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 3/4] libxc: stop migration in case of p2m list structural changes



On 11/12/15 16:20, Andrew Cooper wrote:
> On 11/12/15 11:31, Juergen Gross wrote:
>> With support of the virtual mapped linear p2m list for migration it is
>> now possible to detect structural changes of the p2m list which before
>> would either lead to a crashing or otherwise wrong behaving domU.
>>
>> A guest supporting the linear p2m list will increment the
>> p2m_generation counter located in the shared info page before and after
>> each modification of a mapping related to the p2m list. A change of
>> that counter can be detected by the tools and reacted upon.
>>
>> As such a change should occur only very rarely once the domU is up the
>> most simple reaction is to cancel migration in such an event.
>>
>> Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
>> ---
>>  tools/libxc/xc_sr_common.h       | 11 ++++++++++
>>  tools/libxc/xc_sr_save.c         |  4 ++++
>>  tools/libxc/xc_sr_save_x86_hvm.c |  7 +++++++
>>  tools/libxc/xc_sr_save_x86_pv.c  | 44 
>> ++++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 66 insertions(+)
>>
>> diff --git a/tools/libxc/xc_sr_common.h b/tools/libxc/xc_sr_common.h
>> index 9aecde2..bfb9602 100644
>> --- a/tools/libxc/xc_sr_common.h
>> +++ b/tools/libxc/xc_sr_common.h
>> @@ -83,6 +83,14 @@ struct xc_sr_save_ops
>>      int (*end_of_checkpoint)(struct xc_sr_context *ctx);
>>  
>>      /**
>> +     * Check whether new iteration can be started.  This is called before 
>> each
>> +     * iteration to check whether all criteria for the migration are still
>> +     * met.  If that's not the case either migration is cancelled via a bad 
>> rc
>> +     * or the situation is handled, e.g. by sending appropriate records.
>> +     */
>> +    int (*check_iteration)(struct xc_sr_context *ctx);
>> +
> 
> This is slightly ambiguous, especially with the not-so-different
> differences between live migration and remus checkpoints.
> 
> I would be tempted to name it check_vm_state() and document simply that
> it is called periodically, to allow for fixup (or abort) for guest state
> which may have changed while the VM was running.

Yes, this is better.

> On the remus side, it needs to be called between start_of_checkpoint()
> and send_memory_***() in save(), as the guest gets to run between the
> checkpoints.

Okay.

> 
>> +    /**
>>       * Clean up the local environment.  Will be called exactly once, either
>>       * after a successful save, or upon encountering an error.
>>       */
>> @@ -280,6 +288,9 @@ struct xc_sr_context
>>              /* Read-only mapping of guests shared info page */
>>              shared_info_any_t *shinfo;
>>  
>> +            /* p2m generation count for verifying validity of local p2m. */
>> +            uint64_t p2m_generation;
>> +
>>              union
>>              {
>>                  struct
>> diff --git a/tools/libxc/xc_sr_save.c b/tools/libxc/xc_sr_save.c
>> index cefcef5..c235706 100644
>> --- a/tools/libxc/xc_sr_save.c
>> +++ b/tools/libxc/xc_sr_save.c
>> @@ -370,6 +370,10 @@ static int send_dirty_pages(struct xc_sr_context *ctx,
>>      DECLARE_HYPERCALL_BUFFER_SHADOW(unsigned long, dirty_bitmap,
>>                                      &ctx->save.dirty_bitmap_hbuf);
>>  
>> +    rc = ctx->save.ops.check_iteration(ctx);
>> +    if ( rc )
>> +        return rc;
>> +
> 
> As there is now a call at each start of checkpoint, this call
> essentially becomes back-to-back.  I would suggest having it after the
> batch, rather than ahead.

Okay.

> 
>>      for ( p = 0, written = 0; p < ctx->save.p2m_size; ++p )
>>      {
>>          if ( !test_bit(p, dirty_bitmap) )
>> diff --git a/tools/libxc/xc_sr_save_x86_hvm.c 
>> b/tools/libxc/xc_sr_save_x86_hvm.c
>> index f3d6cee..aa24f90 100644
>> --- a/tools/libxc/xc_sr_save_x86_hvm.c
>> +++ b/tools/libxc/xc_sr_save_x86_hvm.c
>> @@ -175,6 +175,12 @@ static int x86_hvm_start_of_checkpoint(struct 
>> xc_sr_context *ctx)
>>      return 0;
>>  }
>>  
>> +static int x86_hvm_check_iteration(struct xc_sr_context *ctx)
>> +{
>> +    /* no-op */
>> +    return 0;
>> +}
>> +
>>  static int x86_hvm_end_of_checkpoint(struct xc_sr_context *ctx)
>>  {
>>      int rc;
>> @@ -221,6 +227,7 @@ struct xc_sr_save_ops save_ops_x86_hvm =
>>      .start_of_stream     = x86_hvm_start_of_stream,
>>      .start_of_checkpoint = x86_hvm_start_of_checkpoint,
>>      .end_of_checkpoint   = x86_hvm_end_of_checkpoint,
>> +    .check_iteration     = x86_hvm_check_iteration,
>>      .cleanup             = x86_hvm_cleanup,
>>  };
>>  
>> diff --git a/tools/libxc/xc_sr_save_x86_pv.c 
>> b/tools/libxc/xc_sr_save_x86_pv.c
>> index 0237378..3a58d0d 100644
>> --- a/tools/libxc/xc_sr_save_x86_pv.c
>> +++ b/tools/libxc/xc_sr_save_x86_pv.c
>> @@ -268,6 +268,39 @@ err:
>>  }
>>  
>>  /*
>> + * Get p2m_generation count.
>> + * Returns an error if the generation count has changed since the last call.
>> + */
>> +static int get_p2m_generation(struct xc_sr_context *ctx)
>> +{
>> +    uint64_t p2m_generation;
>> +    int rc;
>> +
>> +    p2m_generation = GET_FIELD(ctx->x86_pv.shinfo, arch.p2m_generation,
>> +                               ctx->x86_pv.width);
>> +
>> +    rc = (p2m_generation == ctx->x86_pv.p2m_generation) ? 0 : -1;
>> +    ctx->x86_pv.p2m_generation = p2m_generation;
>> +
>> +    return rc;
>> +}
>> +
>> +static int x86_pv_check_iteration_p2m_list(struct xc_sr_context *ctx)
>> +{
>> +    xc_interface *xch = ctx->xch;
>> +    int rc;
>> +
>> +    if ( !ctx->save.live )
>> +        return 0;
>> +
>> +    rc = get_p2m_generation(ctx);
>> +    if ( rc )
>> +        ERROR("p2m generation count changed. Migration aborted.");
>> +
>> +    return rc;
>> +}
>> +
>> +/*
>>   * Map the guest p2m frames specified via a cr3 value, a virtual address, 
>> and
>>   * the maximum pfn.
>>   */
>> @@ -281,6 +314,9 @@ static int map_p2m_list(struct xc_sr_context *ctx, 
>> uint64_t p2m_cr3)
>>      unsigned fpp, n_pages, level, shift, idx_start, idx_end, idx, saved_idx;
>>      int rc = -1;
>>  
>> +    /* Before each iteration check for local p2m list still valid. */
>> +    ctx->save.ops.check_iteration = x86_pv_check_iteration_p2m_list;
>> +
> 
> This is admittedly the first, but definitely not the only eventual thing
> needed for check iteration.  To avoid clobbering one check with another
> in the future, it would be cleaner to have a single
> x86_pv_check_iteration() which performs the get_p2m_generation() check
> iff linear p2m is in use.

Agreed.


Juergen


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.