|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 04/12] libxenguest: avoid allocating unused deferred-pages bitmap
On 25/06/2021 14:19, Jan Beulich wrote:
> Like for the dirty bitmap, it is unnecessary to allocate the deferred-
> pages bitmap when all that's ever going to happen is a single all-dirty
> run.
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
> ---
> The clearing of the bitmap at the end of suspend_and_send_dirty() also
> looks unnecessary - am I overlooking anything?
Yes. Remus and COLO. You don't want accumulate successfully-sent
deferred pages over checkpoints, otherwise you'll eventually be sending
the entire VM every checkpoint.
Answering out of patch order...
> @@ -791,24 +797,31 @@ static int setup(struct xc_sr_context *c
> {
> xc_interface *xch = ctx->xch;
> int rc;
> - DECLARE_HYPERCALL_BUFFER_SHADOW(unsigned long, dirty_bitmap,
> - &ctx->save.dirty_bitmap_hbuf);
>
> rc = ctx->save.ops.setup(ctx);
> if ( rc )
> goto err;
>
> - dirty_bitmap = ctx->save.live || ctx->stream_type != XC_STREAM_PLAIN
> - ? xc_hypercall_buffer_alloc_pages(
> - xch, dirty_bitmap, NRPAGES(bitmap_size(ctx->save.p2m_size)))
> - : (void *)-1L;
> + if ( ctx->save.live || ctx->stream_type != XC_STREAM_PLAIN )
> + {
> + DECLARE_HYPERCALL_BUFFER_SHADOW(unsigned long, dirty_bitmap,
> + &ctx->save.dirty_bitmap_hbuf);
> +
> + dirty_bitmap =
> + xc_hypercall_buffer_alloc_pages(
> + xch, dirty_bitmap, NRPAGES(bitmap_size(ctx->save.p2m_size)));
> + ctx->save.deferred_pages = bitmap_alloc(ctx->save.p2m_size);
> +
> + if ( !dirty_bitmap || !ctx->save.deferred_pages )
> + goto enomem;
> + }
So this is better than the previous patch. At least we've got a clean
NULL pointer now.
I could in principle get on board with the optimisation, except its not
safe (see below).
> --- a/tools/libs/guest/xg_sr_save.c
> +++ b/tools/libs/guest/xg_sr_save.c
> @@ -130,7 +130,7 @@ static int write_batch(struct xc_sr_cont
>
> ctx->save.batch_pfns[i]);
>
> /* Likely a ballooned page. */
> - if ( mfns[i] == INVALID_MFN )
> + if ( mfns[i] == INVALID_MFN && ctx->save.deferred_pages )
> {
> set_bit(ctx->save.batch_pfns[i], ctx->save.deferred_pages);
> ++ctx->save.nr_deferred_pages;
> @@ -196,8 +196,12 @@ static int write_batch(struct xc_sr_cont
> {
> if ( rc == -1 && errno == EAGAIN )
> {
> - set_bit(ctx->save.batch_pfns[i],
> ctx->save.deferred_pages);
> - ++ctx->save.nr_deferred_pages;
> + if ( ctx->save.deferred_pages )
> + {
> + set_bit(ctx->save.batch_pfns[i],
> + ctx->save.deferred_pages);
> + ++ctx->save.nr_deferred_pages;
> + }
These two blocks are the only two which modify deferred_pages.
It occurs to me that this means deferred_pages is PV-only, because of
the stub implementations of x86_hvm_pfn_to_gfn() and
x86_hvm_normalise_page(). Furthermore, this is likely to be true for
any HVM-like domains even on other architectures.
If these instead were hard errors when !deferred_pages, then that at
least get the logic into an acceptable state.
However, the first hunk demonstrates that deferred_pages gets used even
in the non-live case. In particular, it is sensitive to errors with the
guests' handling of its own P2M. Also, I can't obviously spot anything
which will correctly fail migration if deferred pages survive the final
iteration.
~Andrew
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |