All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Beulich <jbeulich@suse.com>
To: Frediano Ziglio <freddy77@gmail.com>
Cc: "Frediano Ziglio" <frediano.ziglio@citrix.com>,
	"Andrew Cooper" <andrew.cooper3@citrix.com>,
	"Roger Pau Monné" <roger.pau@citrix.com>,
	"Teddy Astie" <teddy.astie@vates.tech>,
	"Anthony PERARD" <anthony.perard@vates.tech>,
	"Juergen Gross" <jgross@suse.com>,
	"Daniel P . Smith" <dpsmith@apertussolutions.com>,
	xen-devel@lists.xenproject.org
Subject: Re: [PATCH v6 12/16] xen: implement new foreign copy hypercall
Date: Mon, 22 Jun 2026 12:34:14 +0200	[thread overview]
Message-ID: <c5f00fa4-4d9e-4227-87a0-6e657fd523e9@suse.com> (raw)
In-Reply-To: <20260619130501.272832-13-frediano.ziglio@citrix.com>

On 19.06.2026 15:04, Frediano Ziglio wrote:
> --- a/xen/common/memory.c
> +++ b/xen/common/memory.c
> @@ -1545,6 +1545,139 @@ static int acquire_resource(
>      return rc;
>  }
>  
> +/*
> + * The "noinline" qualifier avoids the compiler to create a large function
> + * consuming quite a lot of stack.
> + */
> +static int noinline mem_foreigncopy(
> +    XEN_GUEST_HANDLE_PARAM(xen_foreigncopy_t) arg)
> +{
> +    struct domain *d, *const currd = current->domain;
> +    xen_foreigncopy_t copy;
> +    int rc, direction;
> +
> +    if ( copy_from_guest(&copy, arg, 1) )
> +        return -EFAULT;
> +
> +    if ( copy.flags & ~XENMEM_foreigncopy_direction )
> +        return -EINVAL;
> +
> +    direction = copy.flags & XENMEM_foreigncopy_direction;
> +
> +    rc = rcu_lock_remote_domain_by_id(copy.domid, &d);

Iirc I did ask before why this isn't ..._by_any_id().

> +    if ( rc )
> +        return rc;
> +
> +    if ( copy.nr_frames == 0 )
> +    {
> +        rcu_unlock_domain(d);
> +        return 0;
> +    }

Any reason this cannot also be "goto out"? The more that now that you have
moved this past the domid validity check, imo it should further move to ...

> +    /*
> +     * Check we are allowed to map and access these foreign pages.
> +     */
> +    rc = xsm_map_gmfn_foreign(XSM_TARGET, currd, d);
> +    if ( rc )
> +        goto out;

... below here. Perhaps simply as

    if ( rc || !copy.nr_frames )
        goto out;

> +    do {
> +        /*
> +         * Arbitrary size.  Not too much stack space, and a reasonable stride
> +         * for continuation checks.
> +         */
> +        xen_pfn_t gfn_list[32];
> +        unsigned int todo = MIN(ARRAY_SIZE(gfn_list), copy.nr_frames);
> +
> +        rc = -EFAULT;
> +        if ( copy_from_guest(gfn_list, copy.frame_list, todo) )
> +            goto out;
> +
> +        for ( unsigned int i = 0; i < todo; i++ )
> +        {
> +            struct page_info *foreign_page;
> +            mfn_t foreign_mfn;
> +            void *foreign;
> +            p2m_type_t p2mt;
> +            const unsigned long valid_mask =
> +#ifdef CONFIG_X86
> +                p2m_to_mask(p2m_ram_rw) | p2m_to_mask(p2m_ram_logdirty);
> +#else
> +                p2m_to_mask(p2m_ram_rw);
> +#endif

The set of permitted types didn't change, yet a justification for the resulting
limitation also didn't appear.

> +            foreign_page = get_page_from_gfn(d, gfn_list[i], &p2mt, P2M_ALLOC);
> +
> +            if ( unlikely(!(p2m_to_mask(p2mt) & valid_mask)) && foreign_page )
> +            {
> +                put_page(foreign_page);
> +                foreign_page = NULL;
> +            }
> +            if ( unlikely(!foreign_page) )
> +            {
> +                gdprintk(XENLOG_WARNING,
> +                         "Error accessing foreign gfn %" PRI_gfn "\n",
> +                         gfn_list[i]);
> +                rc = -EINVAL;
> +                copy.nr_frames -= i;
> +                guest_handle_add_offset(copy.frame_list, i);
> +                goto out;
> +            }
> +
> +            foreign_mfn = page_to_mfn(foreign_page);
> +
> +            /* A page is dirtied when it's being copied to. */
> +            if ( direction == XENMEM_foreigncopy_to )
> +                paging_mark_dirty(d, foreign_mfn);
> +
> +            foreign = map_domain_page(foreign_mfn);
> +            if ( direction == XENMEM_foreigncopy_from )
> +                rc = copy_to_guest(copy.buffer, foreign, PAGE_SIZE);
> +            else
> +                rc = copy_from_guest(foreign, copy.buffer, PAGE_SIZE);

You cannot validly write to the page without holding a PGT_writable ref.
Else you might overwrite a page table or a descriptor table in a PV guest.

Once again - can you please make sure you have addressed earlier review
comments, before sending a new version? I did point this out before.

> +            unmap_domain_page(foreign);
> +            put_page(foreign_page);
> +
> +            if ( unlikely(rc) )
> +            {
> +                gdprintk(XENLOG_WARNING,
> +                         "Error %d copying gfn %" PRI_gfn "\n",
> +                         -rc, gfn_list[i]);

Why "-rc"? (See other log messages including error codes.)

> +                copy.nr_frames -= i;
> +                guest_handle_add_offset(copy.frame_list, i);
> +                goto out;
> +            }
> +
> +            guest_handle_add_offset(copy.buffer, PAGE_SIZE);
> +        }
> +
> +        copy.nr_frames -= todo;
> +        guest_handle_add_offset(copy.frame_list, todo);

Don't you need to also update copy.buffer?

> @@ -2012,6 +2145,18 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
>              start_extent);
>          break;
>  
> +    case XENMEM_foreigncopy:
> +        /*
> +         * Instead of using "start_extent" we update the structure back,
> +         * we update it back in anyway to tell caller were the copy
> +         * stopped.
> +         */
> +        if ( unlikely(start_extent) )
> +            return -EINVAL;

As before - please be precise with comments like this. We update it back also
when encoding a continuation. Perhaps instead "..., to indicate the point of
failure to the caller as well as to encode continuations without being
constrained by MEMOP_EXTENT_SHIFT".

> --- a/xen/include/public/memory.h
> +++ b/xen/include/public/memory.h
> @@ -740,7 +740,49 @@ struct xen_vnuma_topology_info {
>  typedef struct xen_vnuma_topology_info xen_vnuma_topology_info_t;
>  DEFINE_XEN_GUEST_HANDLE(xen_vnuma_topology_info_t);
>  
> -/* Next available subop number is 29 */
> +/*
> + * Copy memory from/to a given domain.
> + * As this call requires target access and guest with target access won't be
> + * compat guests supported for compat guests this is not implemented.

As before - I question this. You simply can't know. (I'm also struggling with
wording / grammar.)

> + */
> +#define XENMEM_foreigncopy 29
> +struct xen_foreigncopy {
> +    /* IN - The domain whose memory is to be copied. */
> +    domid_t domid;
> +
> +    /* IN - Flags. */
> +#define XENMEM_foreigncopy_from 0
> +#define XENMEM_foreigncopy_to 1
> +#define XENMEM_foreigncopy_direction 1
> +    uint16_t flags;
> +
> +    /*
> +     * IN/OUT
> +     *
> +     * As an IN parameter number of frames of the domain to be copied.
> +     * On output on error updated number of frames left.
> +     */
> +    uint32_t nr_frames;
> +
> +    /*
> +     * IN/OUT
> +     *
> +     * Frames to be copied.
> +     * On output on error updated to point to first frame unhandled.

Is "on error" really correct / meaningful? The field can be updated at
any intermediate point, when a continuation is scheduled. Perhaps:

     * On output:
     *  - on error updated to point to first frame which couldn't be handled,
     *  - on success undefined.

Along these lines for nr_frames then as well (if needed at all, seeing
that it could as well be undefined in both cases, as the information is
redundant with the frame_list update).

> +     */
> +    XEN_GUEST_HANDLE(xen_pfn_t) frame_list;
> +
> +    /*
> +     * IN/OUT
> +     *
> +     * Userspace buffer to read/write from.

s/Userspace/Guest/ ?

Also still no mention of when / how this field is updated.

> +     */
> +    XEN_GUEST_HANDLE(uint8) buffer;
> +};

What was (again) left unaddressed is the question towards using GFNs on both
sides of the copy. This would eliminate the need for the flags field, taken
by a 2nd domid_t one then.

Jan


  reply	other threads:[~2026-06-22 10:34 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-19 13:04 [PATCH v6 00/16] xenguest optimisations Frediano Ziglio
2026-06-19 13:04 ` [PATCH v6 01/16] libs/guest: Reduce number of parts in write_split_record Frediano Ziglio
2026-06-30 16:35   ` Andrew Cooper
2026-07-08  9:07   ` Anthony PERARD
2026-06-19 13:04 ` [PATCH v6 02/16] libs/guest: Reduce number of I/O vectors in write_batch Frediano Ziglio
2026-06-30 16:40   ` Andrew Cooper
2026-07-02 12:31     ` Frediano Ziglio
2026-07-01 13:52   ` [PATCH v6 1.9/16] libs/guest: Allocate rec_pfns earlier in write_batch() Andrew Cooper
2026-07-08  9:08     ` Anthony PERARD
2026-07-01 13:57   ` [PATCH v6.1 02/16] libs/guest: Reduce number of iovecs " Andrew Cooper
2026-07-08  9:09     ` Anthony PERARD
2026-06-19 13:04 ` [PATCH v6 03/16] libs/guest: Reduce number of I/O vectors in write_batch Frediano Ziglio
2026-06-30 16:46   ` Andrew Cooper
2026-07-02 12:33     ` Frediano Ziglio
2026-07-08  9:34       ` Anthony PERARD
2026-06-19 13:04 ` [PATCH v6 04/16] libs/guest: Use a single write_exact in write_headers Frediano Ziglio
2026-06-30 16:47   ` Andrew Cooper
2026-07-08  9:35     ` Anthony PERARD
2026-06-19 13:04 ` [PATCH v6 05/16] libs/guest: allocate various migration arrays just once Frediano Ziglio
2026-07-01 11:34   ` Andrew Cooper
2026-06-19 13:04 ` [PATCH v6 06/16] libs/call: cache up to 4 pages in hypercall bounce buffers Frediano Ziglio
2026-07-07 13:51   ` Anthony PERARD
2026-07-07 14:05     ` Anthony PERARD
2026-07-07 14:47     ` Frediano Ziglio
2026-07-08 13:19       ` Anthony PERARD
2026-07-09  7:13         ` Frediano Ziglio
2026-06-19 13:04 ` [PATCH v6 07/16] libs/guest: avoids using 2 indexes Frediano Ziglio
2026-07-08 13:19   ` Anthony PERARD
2026-06-19 13:04 ` [PATCH v6 08/16] libs/guest: fill directly iov structure Frediano Ziglio
2026-07-01 11:47   ` Andrew Cooper
2026-06-19 13:04 ` [PATCH v6 09/16] libs/ctrl: Allows writev_exact to change iov array Frediano Ziglio
2026-06-30 17:08   ` Andrew Cooper
2026-06-19 13:04 ` [PATCH v6 10/16] libs/guest: add xg_foreignmemory_copy_{from,to} Frediano Ziglio
2026-07-08 13:32   ` Anthony PERARD
2026-07-09 10:07     ` Frediano Ziglio
2026-06-19 13:04 ` [PATCH v6 11/16] PoC: libs/guest: use foreign copy during migration Frediano Ziglio
2026-07-08 13:55   ` Anthony PERARD
2026-07-09  9:35     ` Frediano Ziglio
2026-06-19 13:04 ` [PATCH v6 12/16] xen: implement new foreign copy hypercall Frediano Ziglio
2026-06-22 10:34   ` Jan Beulich [this message]
2026-06-23 10:55     ` Frediano Ziglio
2026-06-23 13:21       ` Jan Beulich
2026-06-23 21:18         ` Frediano Ziglio
2026-06-24  6:44           ` Jan Beulich
2026-06-26 14:14             ` Frediano Ziglio
2026-06-29  6:59               ` Jan Beulich
2026-08-03 14:51                 ` Frediano Ziglio
2026-06-22 10:44   ` Jan Beulich
2026-06-23 20:37   ` Daniel P. Smith
2026-06-19 13:04 ` [PATCH v6 13/16] privcmd: Add definition for new Linux privcmd to access new Xen hypercall Frediano Ziglio
2026-07-08 13:59   ` Anthony PERARD
2026-07-09  9:37     ` Frediano Ziglio
2026-06-19 13:04 ` [PATCH v6 14/16] libs/guest: use new hypercall if available Frediano Ziglio
2026-06-19 13:05 ` [PATCH v6 15/16] libs/guest: finalize PoC Frediano Ziglio
2026-07-08 14:12   ` Anthony PERARD
2026-07-09  9:39     ` Frediano Ziglio
2026-06-19 13:05 ` [PATCH Linux v6 16/16] xen/privcmd: Add new ABI to allow copying foreign memory Frediano Ziglio
2026-07-09 10:53   ` Juergen Gross
2026-08-03 14:05   ` Juergen Gross
2026-08-03 14:23     ` Frediano Ziglio
2026-08-03 14:52       ` Juergen Gross

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=c5f00fa4-4d9e-4227-87a0-6e657fd523e9@suse.com \
    --to=jbeulich@suse.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=anthony.perard@vates.tech \
    --cc=dpsmith@apertussolutions.com \
    --cc=freddy77@gmail.com \
    --cc=frediano.ziglio@citrix.com \
    --cc=jgross@suse.com \
    --cc=roger.pau@citrix.com \
    --cc=teddy.astie@vates.tech \
    --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.