All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Wei Liu <wei.liu2@citrix.com>,
	Xen-devel <xen-devel@lists.xenproject.org>
Cc: Ian Jackson <Ian.Jackson@eu.citrix.com>,
	Ian Campbell <ian.campbell@citrix.com>
Subject: Re: [PATCH for 4.6 5/5] libxc: de-duplicate gpfns in populate_pfns
Date: Fri, 4 Sep 2015 22:56:42 +0100	[thread overview]
Message-ID: <55EA139A.7080808@citrix.com> (raw)
In-Reply-To: <1441391531-30004-6-git-send-email-wei.liu2@citrix.com>

     On 04/09/15 19:32, Wei Liu wrote:
> The original implementation didn't consider there can be same gpfns
> present multiple times in the passed in array. The mechanism to prevent
> populating same gpfn multiple times only works if the same gpfn appear
> in different batch.
>
> This bug is discovered by save / restore Linux 4.1 32 bit kernel, which
> has several PTEs pointing to same gpfn. And gpfn pointed to by those
> PTEs are populated in one batch by libxc.  When libxc calls
> x86_pv_localise_page, the original implementation failed to detect
> duplications in one batch.
>
> The fix is to de-duplicate gpfns in populate_pfns.
>
> Signed-off-by: Wei Liu <wei.liu2@citrix.com>

The original version of populate_pfns() synchronously populated pfns 
when they were found referenced in PTEs ahead of the appropriate 
PAGE_DATA record arriving, but this proved to be very inefficient 
depends on the pagetable layout of the guest.

I agree that this is a bug.

> ---
>   tools/libxc/xc_sr_restore.c | 19 ++++++++++++++++---
>   1 file changed, 16 insertions(+), 3 deletions(-)
>
> diff --git a/tools/libxc/xc_sr_restore.c b/tools/libxc/xc_sr_restore.c
> index adb48da..09fe4c0 100644
> --- a/tools/libxc/xc_sr_restore.c
> +++ b/tools/libxc/xc_sr_restore.c
> @@ -198,7 +198,7 @@ int populate_pfns(struct xc_sr_context *ctx, unsigned count,
>       xc_interface *xch = ctx->xch;
>       xen_pfn_t *mfns = malloc(count * sizeof(*mfns)),
>           *pfns = malloc(count * sizeof(*pfns));
> -    unsigned i, nr_pfns = 0;
> +    unsigned i, j, nr_pfns = 0;
>       int rc = -1;
>   
>       if ( !mfns || !pfns )
> @@ -209,14 +209,27 @@ int populate_pfns(struct xc_sr_context *ctx, unsigned count,
>       }
>   
>       for ( i = 0; i < count; ++i )
> +        pfns[i] = mfns[i] = INVALID_MFN;
> +
> +    for ( i = 0; i < count; ++i )
>       {
>           if ( (!types || (types &&
>                            (types[i] != XEN_DOMCTL_PFINFO_XTAB &&
>                             types[i] != XEN_DOMCTL_PFINFO_BROKEN))) &&
>                !pfn_is_populated(ctx, original_pfns[i]) )
>           {
> -            pfns[nr_pfns] = mfns[nr_pfns] = original_pfns[i];
> -            ++nr_pfns;
> +            bool present = false;
> +
> +            /* De-duplicate gpfns to avoid populating the same one twice */

Just pfns to match the rest of the code.  (I notice some other memory 
terminology needing cleaning up - I will formulate some patches when I 
am next in a position to do so.)

> +            for ( j = 0; j < nr_pfns; ++j )
> +                if ( pfns[j] == original_pfns[i] )
> +                    present = true;

Adding this nested loop introduces O(N^2) behavior on what is typically 
1024-length inputs.

I recommend moving the pfn_set_populated() call from the subsequent loop 
into this loop, which will cause the pfn_is_populated() call in this 
loop condition to catch repeat populations even in the same batch.

The only way pfn_set_populated() can fail is out of memory, and any 
error anywhere in this function is fatal to migration, so there is no 
chance of proceeding with migration with a pfn marked as populated, but 
set to INVALID_MFN in the p2m.

~Andrew

> +
> +            if ( !present )
> +            {
> +                pfns[nr_pfns] = mfns[nr_pfns] = original_pfns[i];
> +                ++nr_pfns;
> +            }
>           }
>       }
>   

      reply	other threads:[~2015-09-04 21:56 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-04 18:32 [PATCH for 4.6 0/5] Migration v2 fix Wei Liu
2015-09-04 18:32 ` [PATCH for 4.6 1/5] libxc: clearer migration v2 debug message Wei Liu
2015-09-04 20:39   ` Andrew Cooper
2015-09-04 18:32 ` [PATCH for 4.6 2/5] libxc: migration v2 prefix Memory -> Memory (P2M) Wei Liu
2015-09-04 20:40   ` Andrew Cooper
2015-09-04 20:50     ` Wei Liu
2015-09-04 18:32 ` [PATCH for 4.6 3/5] libxc: fix indentation Wei Liu
2015-09-04 20:41   ` Andrew Cooper
2015-09-04 18:32 ` [PATCH for 4.6 4/5] libxc: add assertion to avoid setting same bit more than once Wei Liu
2015-09-04 20:43   ` Andrew Cooper
2015-09-04 20:49     ` Wei Liu
2015-09-04 18:32 ` [PATCH for 4.6 5/5] libxc: de-duplicate gpfns in populate_pfns Wei Liu
2015-09-04 21:56   ` Andrew Cooper [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55EA139A.7080808@citrix.com \
    --to=andrew.cooper3@citrix.com \
    --cc=Ian.Jackson@eu.citrix.com \
    --cc=ian.campbell@citrix.com \
    --cc=wei.liu2@citrix.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.