|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH 3/3] remus: adjust x86 pv restore to support remus
On 09/07/14 08:47, Yang Hongyang wrote:
> cache vcpu context when restore, and set context when stream
> complete.
Can you explain why this is needed? I can't see why it should be required.
>
> Signed-off-by: Yang Hongyang <yanghy@xxxxxxxxxxxxxx>
> ---
> tools/libxc/saverestore/common.h | 6 +++
> tools/libxc/saverestore/restore_x86_pv.c | 67
> ++++++++++++++++++++++----------
> 2 files changed, 53 insertions(+), 20 deletions(-)
>
> diff --git a/tools/libxc/saverestore/common.h
> b/tools/libxc/saverestore/common.h
> index 1dd9f51..ba54f83 100644
> --- a/tools/libxc/saverestore/common.h
> +++ b/tools/libxc/saverestore/common.h
> @@ -235,6 +235,12 @@ struct xc_sr_context
>
> /* Read-only mapping of guests shared info page */
> shared_info_any_t *shinfo;
> +
> + /*
> + * We need to cache vcpu context when doing checkpointed
> + * restore, otherwise restore will fail
> + */
> + vcpu_guest_context_any_t *vcpu;
"vcpus" seems more appropriate.
> } x86_pv;
> };
> };
> diff --git a/tools/libxc/saverestore/restore_x86_pv.c
> b/tools/libxc/saverestore/restore_x86_pv.c
> index 14fc020..7a54047 100644
> --- a/tools/libxc/saverestore/restore_x86_pv.c
> +++ b/tools/libxc/saverestore/restore_x86_pv.c
> @@ -428,8 +428,8 @@ static int handle_x86_pv_vcpu_basic(struct xc_sr_context
> *ctx, struct xc_sr_reco
> {
> xc_interface *xch = ctx->xch;
> struct xc_sr_rec_x86_pv_vcpu_hdr *vhdr = rec->data;
> - vcpu_guest_context_any_t vcpu;
> - size_t vcpusz = ctx->x86_pv.width == 8 ? sizeof(vcpu.x64) :
> sizeof(vcpu.x32);
> + vcpu_guest_context_any_t *vcpu;
> + size_t vcpusz = ctx->x86_pv.width == 8 ? sizeof(vcpu->x64) :
> sizeof(vcpu->x32);
Constructs like this are used in several places. A
static inline size_t pv_vcpu_size(const struct xc_sr_context *ctx)
helper in common_x86.h would be a neat improvement.
> xen_pfn_t pfn, mfn;
> unsigned long tmp;
> unsigned i;
> @@ -455,22 +455,23 @@ static int handle_x86_pv_vcpu_basic(struct
> xc_sr_context *ctx, struct xc_sr_reco
> goto err;
> }
>
> - memcpy(&vcpu, &vhdr->context, vcpusz);
> + vcpu = (void *)ctx->x86_pv.vcpu + vcpusz * vhdr->vcpu_id;
vhdr->vcpu_id is essentially untrusted input at this point. It needs to
be validated against dominfo.max_vcpu_id if it is to be used like this.
It was safe before as the first place it was used was with the set
hypercall which would validate in Xen.
> + memcpy(vcpu, &vhdr->context, vcpusz);
If you are caching the context, the rest of this function can also be
deferred until the end, so it is run once rather than N times.
>
> /* Vcpu 0 is special: Convert the suspend record to an mfn. */
> if ( vhdr->vcpu_id == 0 )
> {
> - rc = process_start_info(ctx, &vcpu);
> + rc = process_start_info(ctx, vcpu);
> if ( rc )
> return rc;
> rc = -1;
> }
>
> - SET_FIELD(&vcpu, flags,
> - GET_FIELD(&vcpu, flags, ctx->x86_pv.width) | VGCF_online,
> + SET_FIELD(vcpu, flags,
> + GET_FIELD(vcpu, flags, ctx->x86_pv.width) | VGCF_online,
> ctx->x86_pv.width);
>
> - tmp = GET_FIELD(&vcpu, gdt_ents, ctx->x86_pv.width);
> + tmp = GET_FIELD(vcpu, gdt_ents, ctx->x86_pv.width);
> if ( tmp > 8192 )
> {
> ERROR("GDT entry count (%lu) out of range", tmp);
> @@ -481,7 +482,7 @@ static int handle_x86_pv_vcpu_basic(struct xc_sr_context
> *ctx, struct xc_sr_reco
> /* Convert GDT frames to mfns. */
> for ( i = 0; (i * 512) < tmp; ++i )
> {
> - pfn = GET_FIELD(&vcpu, gdt_frames[i], ctx->x86_pv.width);
> + pfn = GET_FIELD(vcpu, gdt_frames[i], ctx->x86_pv.width);
> if ( pfn > ctx->x86_pv.max_pfn )
> {
> ERROR("GDT frame %u (pfn %#lx) out of range", i, pfn);
> @@ -502,11 +503,11 @@ static int handle_x86_pv_vcpu_basic(struct
> xc_sr_context *ctx, struct xc_sr_reco
> goto err;
> }
>
> - SET_FIELD(&vcpu, gdt_frames[i], mfn, ctx->x86_pv.width);
> + SET_FIELD(vcpu, gdt_frames[i], mfn, ctx->x86_pv.width);
> }
>
> /* Convert CR3 to an mfn. */
> - pfn = cr3_to_mfn(ctx, GET_FIELD(&vcpu, ctrlreg[3], ctx->x86_pv.width));
> + pfn = cr3_to_mfn(ctx, GET_FIELD(vcpu, ctrlreg[3], ctx->x86_pv.width));
> if ( pfn > ctx->x86_pv.max_pfn )
> {
> ERROR("cr3 (pfn %#lx) out of range", pfn);
> @@ -529,12 +530,12 @@ static int handle_x86_pv_vcpu_basic(struct
> xc_sr_context *ctx, struct xc_sr_reco
> goto err;
> }
>
> - SET_FIELD(&vcpu, ctrlreg[3], mfn_to_cr3(ctx, mfn), ctx->x86_pv.width);
> + SET_FIELD(vcpu, ctrlreg[3], mfn_to_cr3(ctx, mfn), ctx->x86_pv.width);
>
> /* 64bit guests: Convert CR1 (guest pagetables) to mfn. */
> - if ( ctx->x86_pv.levels == 4 && (vcpu.x64.ctrlreg[1] & 1) )
> + if ( ctx->x86_pv.levels == 4 && (vcpu->x64.ctrlreg[1] & 1) )
> {
> - pfn = vcpu.x64.ctrlreg[1] >> PAGE_SHIFT;
> + pfn = vcpu->x64.ctrlreg[1] >> PAGE_SHIFT;
>
> if ( pfn > ctx->x86_pv.max_pfn )
> {
> @@ -558,13 +559,7 @@ static int handle_x86_pv_vcpu_basic(struct xc_sr_context
> *ctx, struct xc_sr_reco
> goto err;
> }
>
> - vcpu.x64.ctrlreg[1] = (uint64_t)mfn << PAGE_SHIFT;
> - }
> -
> - if ( xc_vcpu_setcontext(xch, ctx->domid, vhdr->vcpu_id, &vcpu) )
> - {
> - PERROR("Failed to set vcpu%u's basic info", vhdr->vcpu_id);
> - goto err;
> + vcpu->x64.ctrlreg[1] = (uint64_t)mfn << PAGE_SHIFT;
> }
>
> rc = 0;
> @@ -881,6 +876,7 @@ static int x86_pv_localise_page(struct xc_sr_context
> *ctx, uint32_t type, void *
> static int x86_pv_setup(struct xc_sr_context *ctx)
> {
> xc_interface *xch = ctx->xch;
> + size_t vcpusz;
> int rc;
>
> if ( ctx->restore.guest_type != DHDR_TYPE_X86_PV )
> @@ -904,6 +900,9 @@ static int x86_pv_setup(struct xc_sr_context *ctx)
> if ( rc )
> return rc;
>
> + vcpusz = ctx->x86_pv.width == 8 ?
> + sizeof(ctx->x86_pv.vcpu->x64) : sizeof(ctx->x86_pv.vcpu->x32);
> + ctx->x86_pv.vcpu = calloc((ctx->dominfo.max_vcpu_id + 1) , vcpusz);
Extraneous brackets and space.
> return rc;
> }
>
> @@ -946,6 +945,29 @@ static int x86_pv_process_record(struct xc_sr_context
> *ctx, struct xc_sr_record
> }
> }
>
> +static int update_vcpu_context(struct xc_sr_context *ctx)
> +{
> + xc_interface *xch = ctx->xch;
> + vcpu_guest_context_any_t *vcpu;
> + uint32_t vcpu_id;
> + size_t vcpusz = ctx->x86_pv.width == 8 ? sizeof(vcpu->x64) :
> sizeof(vcpu->x32);
> +
> + for ( vcpu_id = 0; vcpu_id <= ctx->dominfo.max_vcpu_id; vcpu_id++ )
> + {
> + vcpu = (void *)ctx->x86_pv.vcpu + vcpu_id * vcpusz;
> + if ( !vcpu )
> + continue;
This check can never fail.
> +
> + if ( xc_vcpu_setcontext(xch, ctx->domid, vcpu_id, vcpu) )
There is a latent bug introduced here. If X86_PV_VCPU_BASIC records
have not been seen for all vcpus, this code will attempt to set a
context of a block of zeroes, and fail because of a bad cr3.
~Andrew
> + {
> + PERROR("Failed to set vcpu%u's basic info", vcpu_id);
> + return -1;
> + }
> + }
> +
> + return 0;
> +}
> +
> /*
> * restore_ops function. Pin the pagetables, rewrite the p2m and seed the
> * grant table.
> @@ -963,6 +985,10 @@ static int x86_pv_stream_complete(struct xc_sr_context
> *ctx)
> if ( rc )
> return rc;
>
> + rc = update_vcpu_context(ctx);
> + if ( rc )
> + return rc;
> +
> rc = xc_dom_gnttab_seed(xch, ctx->domid,
> ctx->restore.console_mfn,
> ctx->restore.xenstore_mfn,
> @@ -985,6 +1011,7 @@ static int x86_pv_cleanup(struct xc_sr_context *ctx)
> free(ctx->x86_pv.p2m);
> free(ctx->x86_pv.p2m_pfns);
> free(ctx->x86_pv.pfn_types);
> + free(ctx->x86_pv.vcpu);
>
> if ( ctx->x86_pv.m2p )
> munmap(ctx->x86_pv.m2p, ctx->x86_pv.nr_m2p_frames * PAGE_SIZE);
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |