Skip to content

Commit 0bb599f

Browse files
author
David Vrabel
committed
xen: remove scratch frames for ballooned pages and m2p override
The scratch frame mappings for ballooned pages and the m2p override are broken. Remove them in preparation for replacing them with simpler mechanisms that works. The scratch pages did not ensure that the page was not in use. In particular, the foreign page could still be in use by hardware. If the guest reused the frame the hardware could read or write that frame. The m2p override did not handle the same frame being granted by two different grant references. Trying an M2P override lookup in this case is impossible. With the m2p override removed, the grant map/unmap for the kernel mappings (for x86 PV) can be easily batched in set_foreign_p2m_mapping() and clear_foreign_p2m_mapping(). Signed-off-by: David Vrabel <[email protected]> Reviewed-by: Stefano Stabellini <[email protected]>
1 parent 853d028 commit 0bb599f

File tree

3 files changed

+14
-344
lines changed

3 files changed

+14
-344
lines changed

arch/x86/include/asm/xen/page.h

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ extern int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
5757
extern int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
5858
struct gnttab_unmap_grant_ref *kunmap_ops,
5959
struct page **pages, unsigned int count);
60-
extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
6160

6261
/*
6362
* Helper functions to write or read unsigned long values to/from
@@ -154,21 +153,12 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
154153
return mfn;
155154

156155
pfn = mfn_to_pfn_no_overrides(mfn);
157-
if (__pfn_to_mfn(pfn) != mfn) {
158-
/*
159-
* If this appears to be a foreign mfn (because the pfn
160-
* doesn't map back to the mfn), then check the local override
161-
* table to see if there's a better pfn to use.
162-
*
163-
* m2p_find_override_pfn returns ~0 if it doesn't find anything.
164-
*/
165-
pfn = m2p_find_override_pfn(mfn, ~0);
166-
}
156+
if (__pfn_to_mfn(pfn) != mfn)
157+
pfn = ~0;
167158

168159
/*
169-
* pfn is ~0 if there are no entries in the m2p for mfn or if the
170-
* entry doesn't map back to the mfn and m2p_override doesn't have a
171-
* valid entry for it.
160+
* pfn is ~0 if there are no entries in the m2p for mfn or the
161+
* entry doesn't map back to the mfn.
172162
*/
173163
if (pfn == ~0 && __pfn_to_mfn(mfn) == IDENTITY_FRAME(mfn))
174164
pfn = mfn;

arch/x86/xen/p2m.c

Lines changed: 8 additions & 246 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@
8484

8585
#define PMDS_PER_MID_PAGE (P2M_MID_PER_PAGE / PTRS_PER_PTE)
8686

87-
static void __init m2p_override_init(void);
88-
8987
unsigned long *xen_p2m_addr __read_mostly;
9088
EXPORT_SYMBOL_GPL(xen_p2m_addr);
9189
unsigned long xen_p2m_size __read_mostly;
@@ -402,8 +400,6 @@ void __init xen_vmalloc_p2m_tree(void)
402400
xen_p2m_size = xen_max_p2m_pfn;
403401

404402
xen_inv_extra_mem();
405-
406-
m2p_override_init();
407403
}
408404

409405
unsigned long get_phys_to_machine(unsigned long pfn)
@@ -652,100 +648,21 @@ bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
652648
return true;
653649
}
654650

655-
#define M2P_OVERRIDE_HASH_SHIFT 10
656-
#define M2P_OVERRIDE_HASH (1 << M2P_OVERRIDE_HASH_SHIFT)
657-
658-
static struct list_head *m2p_overrides;
659-
static DEFINE_SPINLOCK(m2p_override_lock);
660-
661-
static void __init m2p_override_init(void)
662-
{
663-
unsigned i;
664-
665-
m2p_overrides = alloc_bootmem_align(
666-
sizeof(*m2p_overrides) * M2P_OVERRIDE_HASH,
667-
sizeof(unsigned long));
668-
669-
for (i = 0; i < M2P_OVERRIDE_HASH; i++)
670-
INIT_LIST_HEAD(&m2p_overrides[i]);
671-
}
672-
673-
static unsigned long mfn_hash(unsigned long mfn)
674-
{
675-
return hash_long(mfn, M2P_OVERRIDE_HASH_SHIFT);
676-
}
677-
678-
/* Add an MFN override for a particular page */
679-
static int m2p_add_override(unsigned long mfn, struct page *page,
680-
struct gnttab_map_grant_ref *kmap_op)
681-
{
682-
unsigned long flags;
683-
unsigned long pfn;
684-
unsigned long uninitialized_var(address);
685-
unsigned level;
686-
pte_t *ptep = NULL;
687-
688-
pfn = page_to_pfn(page);
689-
if (!PageHighMem(page)) {
690-
address = (unsigned long)__va(pfn << PAGE_SHIFT);
691-
ptep = lookup_address(address, &level);
692-
if (WARN(ptep == NULL || level != PG_LEVEL_4K,
693-
"m2p_add_override: pfn %lx not mapped", pfn))
694-
return -EINVAL;
695-
}
696-
697-
if (kmap_op != NULL) {
698-
if (!PageHighMem(page)) {
699-
struct multicall_space mcs =
700-
xen_mc_entry(sizeof(*kmap_op));
701-
702-
MULTI_grant_table_op(mcs.mc,
703-
GNTTABOP_map_grant_ref, kmap_op, 1);
704-
705-
xen_mc_issue(PARAVIRT_LAZY_MMU);
706-
}
707-
}
708-
spin_lock_irqsave(&m2p_override_lock, flags);
709-
list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]);
710-
spin_unlock_irqrestore(&m2p_override_lock, flags);
711-
712-
/* p2m(m2p(mfn)) == mfn: the mfn is already present somewhere in
713-
* this domain. Set the FOREIGN_FRAME_BIT in the p2m for the other
714-
* pfn so that the following mfn_to_pfn(mfn) calls will return the
715-
* pfn from the m2p_override (the backend pfn) instead.
716-
* We need to do this because the pages shared by the frontend
717-
* (xen-blkfront) can be already locked (lock_page, called by
718-
* do_read_cache_page); when the userspace backend tries to use them
719-
* with direct_IO, mfn_to_pfn returns the pfn of the frontend, so
720-
* do_blockdev_direct_IO is going to try to lock the same pages
721-
* again resulting in a deadlock.
722-
* As a side effect get_user_pages_fast might not be safe on the
723-
* frontend pages while they are being shared with the backend,
724-
* because mfn_to_pfn (that ends up being called by GUPF) will
725-
* return the backend pfn rather than the frontend pfn. */
726-
pfn = mfn_to_pfn_no_overrides(mfn);
727-
if (__pfn_to_mfn(pfn) == mfn)
728-
set_phys_to_machine(pfn, FOREIGN_FRAME(mfn));
729-
730-
return 0;
731-
}
732-
733651
int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
734652
struct gnttab_map_grant_ref *kmap_ops,
735653
struct page **pages, unsigned int count)
736654
{
737655
int i, ret = 0;
738-
bool lazy = false;
739656
pte_t *pte;
740657

741658
if (xen_feature(XENFEAT_auto_translated_physmap))
742659
return 0;
743660

744-
if (kmap_ops &&
745-
!in_interrupt() &&
746-
paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) {
747-
arch_enter_lazy_mmu_mode();
748-
lazy = true;
661+
if (kmap_ops) {
662+
ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
663+
kmap_ops, count);
664+
if (ret)
665+
goto out;
749666
}
750667

751668
for (i = 0; i < count; i++) {
@@ -773,160 +690,22 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
773690
ret = -ENOMEM;
774691
goto out;
775692
}
776-
777-
if (kmap_ops) {
778-
ret = m2p_add_override(mfn, pages[i], &kmap_ops[i]);
779-
if (ret)
780-
goto out;
781-
}
782693
}
783694

784695
out:
785-
if (lazy)
786-
arch_leave_lazy_mmu_mode();
787-
788696
return ret;
789697
}
790698
EXPORT_SYMBOL_GPL(set_foreign_p2m_mapping);
791699

792-
static struct page *m2p_find_override(unsigned long mfn)
793-
{
794-
unsigned long flags;
795-
struct list_head *bucket;
796-
struct page *p, *ret;
797-
798-
if (unlikely(!m2p_overrides))
799-
return NULL;
800-
801-
ret = NULL;
802-
bucket = &m2p_overrides[mfn_hash(mfn)];
803-
804-
spin_lock_irqsave(&m2p_override_lock, flags);
805-
806-
list_for_each_entry(p, bucket, lru) {
807-
if (page_private(p) == mfn) {
808-
ret = p;
809-
break;
810-
}
811-
}
812-
813-
spin_unlock_irqrestore(&m2p_override_lock, flags);
814-
815-
return ret;
816-
}
817-
818-
static int m2p_remove_override(struct page *page,
819-
struct gnttab_unmap_grant_ref *kunmap_op,
820-
unsigned long mfn)
821-
{
822-
unsigned long flags;
823-
unsigned long pfn;
824-
unsigned long uninitialized_var(address);
825-
unsigned level;
826-
pte_t *ptep = NULL;
827-
828-
pfn = page_to_pfn(page);
829-
830-
if (!PageHighMem(page)) {
831-
address = (unsigned long)__va(pfn << PAGE_SHIFT);
832-
ptep = lookup_address(address, &level);
833-
834-
if (WARN(ptep == NULL || level != PG_LEVEL_4K,
835-
"m2p_remove_override: pfn %lx not mapped", pfn))
836-
return -EINVAL;
837-
}
838-
839-
spin_lock_irqsave(&m2p_override_lock, flags);
840-
list_del(&page->lru);
841-
spin_unlock_irqrestore(&m2p_override_lock, flags);
842-
843-
if (kunmap_op != NULL) {
844-
if (!PageHighMem(page)) {
845-
struct multicall_space mcs;
846-
struct gnttab_unmap_and_replace *unmap_op;
847-
struct page *scratch_page = get_balloon_scratch_page();
848-
unsigned long scratch_page_address = (unsigned long)
849-
__va(page_to_pfn(scratch_page) << PAGE_SHIFT);
850-
851-
/*
852-
* It might be that we queued all the m2p grant table
853-
* hypercalls in a multicall, then m2p_remove_override
854-
* get called before the multicall has actually been
855-
* issued. In this case handle is going to -1 because
856-
* it hasn't been modified yet.
857-
*/
858-
if (kunmap_op->handle == -1)
859-
xen_mc_flush();
860-
/*
861-
* Now if kmap_op->handle is negative it means that the
862-
* hypercall actually returned an error.
863-
*/
864-
if (kunmap_op->handle == GNTST_general_error) {
865-
pr_warn("m2p_remove_override: pfn %lx mfn %lx, failed to modify kernel mappings",
866-
pfn, mfn);
867-
put_balloon_scratch_page();
868-
return -1;
869-
}
870-
871-
xen_mc_batch();
872-
873-
mcs = __xen_mc_entry(
874-
sizeof(struct gnttab_unmap_and_replace));
875-
unmap_op = mcs.args;
876-
unmap_op->host_addr = kunmap_op->host_addr;
877-
unmap_op->new_addr = scratch_page_address;
878-
unmap_op->handle = kunmap_op->handle;
879-
880-
MULTI_grant_table_op(mcs.mc,
881-
GNTTABOP_unmap_and_replace, unmap_op, 1);
882-
883-
mcs = __xen_mc_entry(0);
884-
MULTI_update_va_mapping(mcs.mc, scratch_page_address,
885-
pfn_pte(page_to_pfn(scratch_page),
886-
PAGE_KERNEL_RO), 0);
887-
888-
xen_mc_issue(PARAVIRT_LAZY_MMU);
889-
890-
put_balloon_scratch_page();
891-
}
892-
}
893-
894-
/* p2m(m2p(mfn)) == FOREIGN_FRAME(mfn): the mfn is already present
895-
* somewhere in this domain, even before being added to the
896-
* m2p_override (see comment above in m2p_add_override).
897-
* If there are no other entries in the m2p_override corresponding
898-
* to this mfn, then remove the FOREIGN_FRAME_BIT from the p2m for
899-
* the original pfn (the one shared by the frontend): the backend
900-
* cannot do any IO on this page anymore because it has been
901-
* unshared. Removing the FOREIGN_FRAME_BIT from the p2m entry of
902-
* the original pfn causes mfn_to_pfn(mfn) to return the frontend
903-
* pfn again. */
904-
mfn &= ~FOREIGN_FRAME_BIT;
905-
pfn = mfn_to_pfn_no_overrides(mfn);
906-
if (__pfn_to_mfn(pfn) == FOREIGN_FRAME(mfn) &&
907-
m2p_find_override(mfn) == NULL)
908-
set_phys_to_machine(pfn, mfn);
909-
910-
return 0;
911-
}
912-
913700
int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
914701
struct gnttab_unmap_grant_ref *kunmap_ops,
915702
struct page **pages, unsigned int count)
916703
{
917704
int i, ret = 0;
918-
bool lazy = false;
919705

920706
if (xen_feature(XENFEAT_auto_translated_physmap))
921707
return 0;
922708

923-
if (kunmap_ops &&
924-
!in_interrupt() &&
925-
paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) {
926-
arch_enter_lazy_mmu_mode();
927-
lazy = true;
928-
}
929-
930709
for (i = 0; i < count; i++) {
931710
unsigned long mfn = __pfn_to_mfn(page_to_pfn(pages[i]));
932711
unsigned long pfn = page_to_pfn(pages[i]);
@@ -940,32 +719,15 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
940719
WARN_ON(!PagePrivate(pages[i]));
941720
ClearPagePrivate(pages[i]);
942721
set_phys_to_machine(pfn, pages[i]->index);
943-
944-
if (kunmap_ops)
945-
ret = m2p_remove_override(pages[i], &kunmap_ops[i], mfn);
946-
if (ret)
947-
goto out;
948722
}
949-
723+
if (kunmap_ops)
724+
ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
725+
kunmap_ops, count);
950726
out:
951-
if (lazy)
952-
arch_leave_lazy_mmu_mode();
953727
return ret;
954728
}
955729
EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping);
956730

957-
unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn)
958-
{
959-
struct page *p = m2p_find_override(mfn);
960-
unsigned long ret = pfn;
961-
962-
if (p)
963-
ret = page_to_pfn(p);
964-
965-
return ret;
966-
}
967-
EXPORT_SYMBOL_GPL(m2p_find_override_pfn);
968-
969731
#ifdef CONFIG_XEN_DEBUG_FS
970732
#include <linux/debugfs.h>
971733
#include "debugfs.h"

0 commit comments

Comments
 (0)