Re: [PATCH v6 1/3] ioreq: switch ioreq page allocation to vmap
Julian Vetter <[email protected]>
| Newsgroups | gmane.comp.emulators.xen.devel |
|---|---|
| Message-ID | <1787667597.8631fc262581453bbf619ec5b2062170.1a0394ac7f2000c4f3@vates.tech> |
On 8/18/26 3:06 PM, Jan Beulich wrote: > On 20.04.2026 11:38, Julian Vetter wrote: >> Switch the Xen-side ioreq page mapping from prepare_ring_for_helper() / >> map_domain_page_global() to explicit vmap(), to ensure vmap_to_page() >> can recover the struct page_info * uniformly during teardown. > > What's after the comma isn't really the main reason for this patch, is it? > Describing this aspect ... > >> This is a prerequisite for multi-page ioreq support: the non-buf ioreq >> region will need to span multiple pages for domains with more vCPUs than >> fit in a single page, and vmap() is the natural interface for contiguous >> multi-page Xen VA mappings. >> >> In non-debug builds map_domain_page_global() uses the directmap for low >> MFNs rather than vmap(), so this change has a small overhead in the >> common case. Debug builds already used vmap() indirectly. >> >> With both paths using vmap(), vmap_to_page() can recover the struct >> page_info * uniformly, so drop the 'page' field from struct ioreq_page >> and update all callers accordingly. > > ... here (at the bottom) is fully sufficient. > >> Signed-off-by: Julian Vetter <[email protected]> >> --- >> Changes in v6: >> - Updated commit message to clearly specify why these changes are made >> - Added comment to say that this is {prepare,destroy}_ring_for_helper() >> just using vmap_to_page() + v{map,unmap}() >> - Kept proper ordering in ioreq_server_free_mfn(), first clearing the va >> pointer before unmapping > > Yet then you didn't extend the same consideration ... > >> @@ -128,8 +129,13 @@ static void hvm_unmap_ioreq_gfn(struct ioreq_server *s, bool buf) >> if ( gfn_eq(iorp->gfn, INVALID_GFN) ) >> return; >> >> - destroy_ring_for_helper(&iorp->va, iorp->page); >> - iorp->page = NULL; >> + /* Equivalent to destroy_ring_for_helper(), using vmap_to_page(). */ >> + if ( iorp->va ) >> + { >> + put_page_and_type(vmap_to_page(iorp->va)); >> + vunmap(iorp->va); >> + iorp->va = NULL; >> + } > > ... to here. (Really we should perhaps introduce VUNMAP(), much like we > have XFREE(), XVFREE(), etc.) > > Further the ordering doesn't match destroy_ring_for_helper(), which unmaps > first and only then drops the page refs. > >> @@ -162,12 +171,40 @@ static int hvm_map_ioreq_gfn(struct ioreq_server *s, bool buf) >> if ( gfn_eq(iorp->gfn, INVALID_GFN) ) >> return -ENOMEM; >> >> - rc = prepare_ring_for_helper(d, gfn_x(iorp->gfn), &iorp->page, >> - &iorp->va); >> - >> + /* >> + * Equivalent to prepare_ring_for_helper() using vmap(). Using vmap() >> + * rather than map_domain_page_global() ensures vmap_to_page() can >> + * recover the struct page_info * uniformly at teardown, which is >> + * needed to support multi-page ioreq mappings (see nr_ioreq_pages()). >> + */ > > "is needed" is too strong, I think - surely there would be a way to handle > that without vmap_to_page(), by tracking all struct page_info * separately. > >> @@ -309,15 +310,16 @@ static int ioreq_server_alloc_mfn(struct ioreq_server *s, bool buf) >> static void ioreq_server_free_mfn(struct ioreq_server *s, bool buf) >> { >> struct ioreq_page *iorp = buf ? &s->bufioreq : &s->ioreq; >> - struct page_info *page = iorp->page; >> + struct page_info *page; >> + void *va; >> >> - if ( !page ) >> + if ( !iorp->va ) >> return; >> >> - iorp->page = NULL; >> - >> - unmap_domain_page_global(iorp->va); >> + va = iorp->va; > > Please can this be the initializer of the variable, for the if() above to > then use that local var? > >> @@ -333,7 +335,8 @@ bool is_ioreq_server_page(struct domain *d, const struct page_info *page) >> >> FOR_EACH_IOREQ_SERVER(d, id, s) >> { >> - if ( (s->ioreq.page == page) || (s->bufioreq.page == page) ) >> + if ( (s->ioreq.va && vmap_to_page(s->ioreq.va) == page) || >> + (s->bufioreq.va && vmap_to_page(s->bufioreq.va) == page) ) >> { >> found = true; >> break; > > You mention in the description that some extra overhead is introduced. The > (generally) two page walks done here are particularly concerning. Since we > have a valid struct page_info * available here, I wonder if we shouldn't > aid this lookup by recording the VA in one of struct page_info's fields. > Afaics vmap() doesn't use any of the fields, so it should be relatively > easy to determine a field to use for this purpose. The more involved part > would then be to make sure the field (in other struct page_info instances) > is also properly different from any VA vmap() may return. Hello Jan, Thank you again for your feedback! I will wait then for Anthony's decision regarding whether the multi-page ioreq support and the ioreq_t growth should be combined into a single effort, before I proceed further with a v7. I just wanted to clarify one thing regarding the overhead I mentioned in the first patch's commit message ("this change has a small overhead in the common case"). Here, I was referring to vmap()/vunmap() replacing map_domain_page_global(). Where map_domain_page_global() has a directmap fast path. I didn't mean the overhead of the added vmap_to_page(). I should maybe clarify this better in my next iteration's commit message. On your suggestion to cache the VA in struct page_info to speed up the vmap_to_page() lookups in is_ioreq_server_page(): I looked through the tree, and that function currently has only one caller sh_remove_all_mappings() (in xen/arch/x86/mm/shadow/common.c) and is only reached in a failure case. Given that, and given how widely shared and size-critical struct page_info is, I'm wondering whether it's really worth touching it for the gain of not having to do the 2 lookups. What do you think? Thanks, Julian > > Jan -- | Vates XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech