[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v3 13/20] xen/riscv: Implement p2m_free_subtree() and related helpers
On 31.07.2025 17:58, Oleksii Kurochko wrote: > --- a/xen/arch/riscv/include/asm/p2m.h > +++ b/xen/arch/riscv/include/asm/p2m.h > @@ -79,10 +79,20 @@ typedef enum { > p2m_ext_storage, /* Following types'll be stored outsude PTE bits: */ > p2m_grant_map_rw, /* Read/write grant mapping */ > p2m_grant_map_ro, /* Read-only grant mapping */ > + p2m_map_foreign_rw, /* Read/write RAM pages from foreign domain */ > + p2m_map_foreign_ro, /* Read-only RAM pages from foreign domain */ > } p2m_type_t; > > #define p2m_mmio_direct p2m_mmio_direct_io > > +/* > + * Bits 8 and 9 are reserved for use by supervisor software; > + * the implementation shall ignore this field. > + * We are going to use to save in these bits frequently used types to avoid > + * get/set of a type from radix tree. > + */ > +#define P2M_TYPE_PTE_BITS_MASK 0x300 > + > /* We use bitmaps and mask to handle groups of types */ > #define p2m_to_mask(t_) BIT(t_, UL) > > @@ -93,10 +103,16 @@ typedef enum { > #define P2M_GRANT_TYPES (p2m_to_mask(p2m_grant_map_rw) | \ > p2m_to_mask(p2m_grant_map_ro)) > > + /* Foreign mappings types */ Nit: Why so far to the right? > --- a/xen/arch/riscv/p2m.c > +++ b/xen/arch/riscv/p2m.c > @@ -197,6 +197,16 @@ static pte_t *p2m_get_root_pointer(struct p2m_domain > *p2m, gfn_t gfn) > return __map_domain_page(p2m->root + root_table_indx); > } > > +static p2m_type_t p2m_get_type(const pte_t pte) > +{ > + p2m_type_t type = MASK_EXTR(pte.pte, P2M_TYPE_PTE_BITS_MASK); > + > + if ( type == p2m_ext_storage ) > + panic("unimplemented\n"); That is, as per p2m.h additions you pretend to add support for foreign types here, but then you don't? > @@ -248,11 +258,136 @@ static int p2m_next_level(struct p2m_domain *p2m, bool > alloc_tbl, > return P2M_TABLE_MAP_NONE; > } > > +static void p2m_put_foreign_page(struct page_info *pg) > +{ > + /* > + * It’s safe to call put_page() here because arch_flush_tlb_mask() > + * will be invoked if the page is reallocated before the end of > + * this loop, which will trigger a flush of the guest TLBs. > + */ > + put_page(pg); > +} How can one know the comment is true? arch_flush_tlb_mask() still lives in stubs.c, and hence what it is eventually going to do (something like Arm's vs more like x86'es) is entirely unknown right now. > +/* Put any references on the single 4K page referenced by mfn. */ > +static void p2m_put_4k_page(mfn_t mfn, p2m_type_t type) > +{ > + /* TODO: Handle other p2m types */ > + > + if ( p2m_is_foreign(type) ) > + { > + ASSERT(mfn_valid(mfn)); > + p2m_put_foreign_page(mfn_to_page(mfn)); > + } > + > + /* > + * Detect the xenheap page and mark the stored GFN as invalid. > + * We don't free the underlying page until the guest requested to do so. > + * So we only need to tell the page is not mapped anymore in the P2M by > + * marking the stored GFN as invalid. > + */ > + if ( p2m_is_ram(type) && is_xen_heap_mfn(mfn) ) > + page_set_xenheap_gfn(mfn_to_page(mfn), INVALID_GFN); Isn't this for grants? p2m_is_ram() doesn't cover p2m_grant_map_*. > +} > + > +/* Put any references on the superpage referenced by mfn. */ > +static void p2m_put_2m_superpage(mfn_t mfn, p2m_type_t type) > +{ > + struct page_info *pg; > + unsigned int i; > + > + ASSERT(mfn_valid(mfn)); > + > + pg = mfn_to_page(mfn); > + > + for ( i = 0; i < XEN_PT_ENTRIES; i++, pg++ ) > + p2m_put_foreign_page(pg); > +} In p2m_put_4k_page() you check the type, whereas here you don't. > +/* Put any references on the page referenced by pte. */ > +static void p2m_put_page(const pte_t pte, unsigned int level) > +{ > + mfn_t mfn = pte_get_mfn(pte); > + p2m_type_t p2m_type = p2m_get_type(pte); > + > + ASSERT(pte_is_valid(pte)); > + > + /* > + * TODO: Currently we don't handle level 2 super-page, Xen is not > + * preemptible and therefore some work is needed to handle such > + * superpages, for which at some point Xen might end up freeing memory > + * and therefore for such a big mapping it could end up in a very long > + * operation. > + */ > + switch ( level ) > + { > + case 1: > + return p2m_put_2m_superpage(mfn, p2m_type); > + > + case 0: > + return p2m_put_4k_page(mfn, p2m_type); > + } Yet despite the comment not even an assertion for level 2 and up? > /* Free pte sub-tree behind an entry */ > static void p2m_free_subtree(struct p2m_domain *p2m, > pte_t entry, unsigned int level) > { > - panic("%s: hasn't been implemented yet\n", __func__); > + unsigned int i; > + pte_t *table; > + mfn_t mfn; > + struct page_info *pg; > + > + /* Nothing to do if the entry is invalid. */ > + if ( !pte_is_valid(entry) ) > + return; > + > + if ( pte_is_superpage(entry, level) || (level == 0) ) Perhaps swap the two conditions around? > + { > +#ifdef CONFIG_IOREQ_SERVER > + /* > + * If this gets called then either the entry was replaced by an entry > + * with a different base (valid case) or the shattering of a > superpage > + * has failed (error case). > + * So, at worst, the spurious mapcache invalidation might be sent. > + */ > + if ( p2m_is_ram(p2m_get_type(p2m, entry)) && > + domain_has_ioreq_server(p2m->domain) ) > + ioreq_request_mapcache_invalidate(p2m->domain); > +#endif > + > + p2m_put_page(entry, level); > + > + return; > + } > + > + table = map_domain_page(pte_get_mfn(entry)); > + for ( i = 0; i < XEN_PT_ENTRIES; i++ ) > + p2m_free_subtree(p2m, table[i], level - 1); In p2m_put_page() you comment towards concerns for level >= 2; no similar concerns for the resulting recursion here? > + unmap_domain_page(table); > + > + /* > + * Make sure all the references in the TLB have been removed before > + * freing the intermediate page table. > + * XXX: Should we defer the free of the page table to avoid the > + * flush? > + */ > + p2m_tlb_flush_sync(p2m); > + > + mfn = pte_get_mfn(entry); > + ASSERT(mfn_valid(mfn)); > + > + pg = mfn_to_page(mfn); > + > + page_list_del(pg, &p2m->pages); > + p2m_free_page(p2m, pg); Once again I wonder whether this code path was actually tested: p2m_free_page() also invokes page_list_del(), and double deletions typically won't end very well. Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |