[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] x86/mem_sharing: cleanup code and comments in various locations
commit ca14eba3ccb92a1219a12e8fe671f8e5a96ccf31 Author: Tamas K Lengyel <tamas.lengyel@xxxxxxxxx> AuthorDate: Wed Dec 18 11:40:41 2019 -0800 Commit: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> CommitDate: Thu Dec 19 18:05:11 2019 +0000 x86/mem_sharing: cleanup code and comments in various locations No functional changes. Signed-off-by: Tamas K Lengyel <tamas.lengyel@xxxxxxxxx> Acked-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> [Further cleanup] Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- xen/arch/x86/hvm/hvm.c | 13 +- xen/arch/x86/mm/mem_sharing.c | 898 ++++++++++++++++++++------------------ xen/arch/x86/mm/p2m.c | 17 +- xen/include/asm-x86/mem_sharing.h | 40 +- 4 files changed, 512 insertions(+), 456 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 614ed60fe4..3cc6d22dfb 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -1884,7 +1884,7 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, * If this GFN is emulated MMIO or marked as read-only, pass the fault * to the mmio handler. */ - if ( (p2mt == p2m_mmio_dm) || + if ( (p2mt == p2m_mmio_dm) || (npfec.write_access && (p2m_is_discard_write(p2mt) || (p2mt == p2m_ioreq_server))) ) { @@ -1902,12 +1902,11 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, if ( npfec.write_access && (p2mt == p2m_ram_shared) ) { ASSERT(p2m_is_hostp2m(p2m)); - sharing_enomem = - (mem_sharing_unshare_page(currd, gfn, 0) < 0); + sharing_enomem = mem_sharing_unshare_page(currd, gfn, 0); rc = 1; goto out_put_gfn; } - + /* Spurious fault? PoD and log-dirty also take this path. */ if ( p2m_is_ram(p2mt) ) { @@ -1953,9 +1952,11 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, __put_gfn(p2m, gfn); __put_gfn(hostp2m, gfn); out: - /* All of these are delayed until we exit, since we might + /* + * All of these are delayed until we exit, since we might * sleep on event ring wait queues, and we must not hold - * locks in such circumstance */ + * locks in such circumstance. + */ if ( paged ) p2m_mem_paging_populate(currd, gfn); if ( sharing_enomem ) diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index efb8821768..ddf1f0f9f9 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -59,8 +59,10 @@ static DEFINE_PER_CPU(pg_lock_data_t, __pld); #define RMAP_USES_HASHTAB(page) \ ((page)->sharing->hash_table.flag == NULL) #define RMAP_HEAVY_SHARED_PAGE RMAP_HASHTAB_SIZE -/* A bit of hysteresis. We don't want to be mutating between list and hash - * table constantly. */ +/* + * A bit of hysteresis. We don't want to be mutating between list and hash + * table constantly. + */ #define RMAP_LIGHT_SHARED_PAGE (RMAP_HEAVY_SHARED_PAGE >> 2) #if MEM_SHARING_AUDIT @@ -75,7 +77,7 @@ static void _free_pg_shared_info(struct rcu_head *head) xfree(container_of(head, struct page_sharing_info, rcu_head)); } -static inline void audit_add_list(struct page_info *page) +static void audit_add_list(struct page_info *page) { INIT_LIST_HEAD(&page->sharing->entry); spin_lock(&shr_audit_lock); @@ -84,12 +86,12 @@ static inline void audit_add_list(struct page_info *page) } /* Removes from the audit list and cleans up the page sharing metadata. */ -static inline void page_sharing_dispose(struct page_info *page) +static void page_sharing_dispose(struct page_info *page) { /* Unlikely given our thresholds, but we should be careful. */ if ( unlikely(RMAP_USES_HASHTAB(page)) ) - free_xenheap_pages(page->sharing->hash_table.bucket, - RMAP_HASHTAB_ORDER); + free_xenheap_pages(page->sharing->hash_table.bucket, + RMAP_HASHTAB_ORDER); spin_lock(&shr_audit_lock); list_del_rcu(&page->sharing->entry); @@ -101,12 +103,12 @@ static inline void page_sharing_dispose(struct page_info *page) #else #define audit_add_list(p) ((void)0) -static inline void page_sharing_dispose(struct page_info *page) +static void page_sharing_dispose(struct page_info *page) { /* Unlikely given our thresholds, but we should be careful. */ if ( unlikely(RMAP_USES_HASHTAB(page)) ) - free_xenheap_pages(page->sharing->hash_table.bucket, - RMAP_HASHTAB_ORDER); + free_xenheap_pages(page->sharing->hash_table.bucket, + RMAP_HASHTAB_ORDER); xfree(page->sharing); } @@ -122,12 +124,12 @@ static inline void page_sharing_dispose(struct page_info *page) * Nesting may happen when sharing (and locking) two pages. * Deadlock is avoided by locking pages in increasing order. * All memory sharing code paths take the p2m lock of the affected gfn before - * taking the lock for the underlying page. We enforce ordering between page_lock - * and p2m_lock using an mm-locks.h construct. + * taking the lock for the underlying page. We enforce ordering between + * page_lock and p2m_lock using an mm-locks.h construct. * * TODO: Investigate if PGT_validated is necessary. */ -static inline bool _page_lock(struct page_info *page) +static bool _page_lock(struct page_info *page) { unsigned long x, nx; @@ -144,7 +146,7 @@ static inline bool _page_lock(struct page_info *page) return true; } -static inline void _page_unlock(struct page_info *page) +static void _page_unlock(struct page_info *page) { unsigned long x, nx, y = page->u.inuse.type_info; @@ -158,7 +160,7 @@ static inline void _page_unlock(struct page_info *page) } while ( (y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x ); } -static inline bool mem_sharing_page_lock(struct page_info *pg) +static bool mem_sharing_page_lock(struct page_info *pg) { bool rc; pg_lock_data_t *pld = &(this_cpu(__pld)); @@ -168,25 +170,25 @@ static inline bool mem_sharing_page_lock(struct page_info *pg) if ( rc ) { preempt_disable(); - page_sharing_mm_post_lock(&pld->mm_unlock_level, + page_sharing_mm_post_lock(&pld->mm_unlock_level, &pld->recurse_count); } return rc; } -static inline void mem_sharing_page_unlock(struct page_info *pg) +static void mem_sharing_page_unlock(struct page_info *pg) { pg_lock_data_t *pld = &(this_cpu(__pld)); - page_sharing_mm_unlock(pld->mm_unlock_level, + page_sharing_mm_unlock(pld->mm_unlock_level, &pld->recurse_count); preempt_enable(); _page_unlock(pg); } -static inline shr_handle_t get_next_handle(void) +static shr_handle_t get_next_handle(void) { - /* Get the next handle get_page style */ + /* Get the next handle get_page style */ uint64_t x, y = next_handle; do { x = y; @@ -198,24 +200,26 @@ static inline shr_handle_t get_next_handle(void) #define mem_sharing_enabled(d) \ (is_hvm_domain(d) && (d)->arch.hvm.mem_sharing_enabled) -static atomic_t nr_saved_mfns = ATOMIC_INIT(0); +static atomic_t nr_saved_mfns = ATOMIC_INIT(0); static atomic_t nr_shared_mfns = ATOMIC_INIT(0); -/** Reverse map **/ -/* Every shared frame keeps a reverse map (rmap) of <domain, gfn> tuples that +/* + * Reverse map + * + * Every shared frame keeps a reverse map (rmap) of <domain, gfn> tuples that * this shared frame backs. For pages with a low degree of sharing, a O(n) * search linked list is good enough. For pages with higher degree of sharing, - * we use a hash table instead. */ + * we use a hash table instead. + */ typedef struct gfn_info { unsigned long gfn; - domid_t domain; + domid_t domain; struct list_head list; } gfn_info_t; -static inline void -rmap_init(struct page_info *page) +static void rmap_init(struct page_info *page) { /* We always start off as a doubly linked list. */ INIT_LIST_HEAD(&page->sharing->gfns); @@ -225,10 +229,11 @@ rmap_init(struct page_info *page) #define HASH(domain, gfn) \ (((gfn) + (domain)) % RMAP_HASHTAB_SIZE) -/* Conversions. Tuned by the thresholds. Should only happen twice - * (once each) during the lifetime of a shared page */ -static inline int -rmap_list_to_hash_table(struct page_info *page) +/* + * Conversions. Tuned by the thresholds. Should only happen twice + * (once each) during the lifetime of a shared page. + */ +static inline int rmap_list_to_hash_table(struct page_info *page) { unsigned int i; struct list_head *pos, *tmp, *b = @@ -240,10 +245,11 @@ rmap_list_to_hash_table(struct page_info *page) for ( i = 0; i < RMAP_HASHTAB_SIZE; i++ ) INIT_LIST_HEAD(b + i); - list_for_each_safe(pos, tmp, &page->sharing->gfns) + list_for_each_safe ( pos, tmp, &page->sharing->gfns ) { gfn_info_t *gfn_info = list_entry(pos, gfn_info_t, list); struct list_head *bucket = b + HASH(gfn_info->domain, gfn_info->gfn); + list_del(pos); list_add(pos, bucket); } @@ -254,8 +260,7 @@ rmap_list_to_hash_table(struct page_info *page) return 0; } -static inline void -rmap_hash_table_to_list(struct page_info *page) +static void rmap_hash_table_to_list(struct page_info *page) { unsigned int i; struct list_head *bucket = page->sharing->hash_table.bucket; @@ -265,7 +270,8 @@ rmap_hash_table_to_list(struct page_info *page) for ( i = 0; i < RMAP_HASHTAB_SIZE; i++ ) { struct list_head *pos, *tmp, *head = bucket + i; - list_for_each_safe(pos, tmp, head) + + list_for_each_safe ( pos, tmp, head ) { list_del(pos); list_add(pos, &page->sharing->gfns); @@ -276,22 +282,23 @@ rmap_hash_table_to_list(struct page_info *page) } /* Generic accessors to the rmap */ -static inline unsigned long -rmap_count(struct page_info *pg) +static unsigned long rmap_count(const struct page_info *pg) { unsigned long count; unsigned long t = read_atomic(&pg->u.inuse.type_info); + count = t & PGT_count_mask; if ( t & PGT_locked ) count--; return count; } -/* The page type count is always decreased after removing from the rmap. - * Use a convert flag to avoid mutating the rmap if in the middle of an - * iterator, or if the page will be soon destroyed anyways. */ -static inline void -rmap_del(gfn_info_t *gfn_info, struct page_info *page, int convert) +/* + * The page type count is always decreased after removing from the rmap. + * Use a convert flag to avoid mutating the rmap if in the middle of an + * iterator, or if the page will be soon destroyed anyways. + */ +static void rmap_del(gfn_info_t *gfn_info, struct page_info *page, int convert) { if ( RMAP_USES_HASHTAB(page) && convert && (rmap_count(page) <= RMAP_LIGHT_SHARED_PAGE) ) @@ -302,38 +309,38 @@ rmap_del(gfn_info_t *gfn_info, struct page_info *page, int convert) } /* The page type count is always increased before adding to the rmap. */ -static inline void -rmap_add(gfn_info_t *gfn_info, struct page_info *page) +static void rmap_add(gfn_info_t *gfn_info, struct page_info *page) { struct list_head *head; if ( !RMAP_USES_HASHTAB(page) && (rmap_count(page) >= RMAP_HEAVY_SHARED_PAGE) ) - /* The conversion may fail with ENOMEM. We'll be less efficient, - * but no reason to panic. */ + /* + * The conversion may fail with ENOMEM. We'll be less efficient, + * but no reason to panic. + */ (void)rmap_list_to_hash_table(page); - head = (RMAP_USES_HASHTAB(page)) ? - page->sharing->hash_table.bucket + - HASH(gfn_info->domain, gfn_info->gfn) : - &page->sharing->gfns; + head = (RMAP_USES_HASHTAB(page) + ? page->sharing->hash_table.bucket + HASH(gfn_info->domain, + gfn_info->gfn) + : &page->sharing->gfns); INIT_LIST_HEAD(&gfn_info->list); list_add(&gfn_info->list, head); } -static inline gfn_info_t * -rmap_retrieve(uint16_t domain_id, unsigned long gfn, - struct page_info *page) +static gfn_info_t *rmap_retrieve(uint16_t domain_id, unsigned long gfn, + struct page_info *page) { gfn_info_t *gfn_info; struct list_head *le, *head; - head = (RMAP_USES_HASHTAB(page)) ? - page->sharing->hash_table.bucket + HASH(domain_id, gfn) : - &page->sharing->gfns; + head = (RMAP_USES_HASHTAB(page) + ? page->sharing->hash_table.bucket + HASH(domain_id, gfn) + : &page->sharing->gfns); - list_for_each(le, head) + list_for_each ( le, head ) { gfn_info = list_entry(le, gfn_info_t, list); if ( (gfn_info->gfn == gfn) && (gfn_info->domain == domain_id) ) @@ -345,43 +352,44 @@ rmap_retrieve(uint16_t domain_id, unsigned long gfn, } /* Returns true if the rmap has only one entry. O(1) complexity. */ -static inline int rmap_has_one_entry(struct page_info *page) +static bool rmap_has_one_entry(const struct page_info *page) { - return (rmap_count(page) == 1); + return rmap_count(page) == 1; } /* Returns true if the rmap has any entries. O(1) complexity. */ -static inline int rmap_has_entries(struct page_info *page) +static bool rmap_has_entries(const struct page_info *page) { - return (rmap_count(page) != 0); + return rmap_count(page) != 0; } -/* The iterator hides the details of how the rmap is implemented. This - * involves splitting the list_for_each_safe macro into two steps. */ +/* + * The iterator hides the details of how the rmap is implemented. This + * involves splitting the list_for_each_safe macro into two steps. + */ struct rmap_iterator { struct list_head *curr; struct list_head *next; unsigned int bucket; }; -static inline void -rmap_seed_iterator(struct page_info *page, struct rmap_iterator *ri) +static void rmap_seed_iterator(struct page_info *page, struct rmap_iterator *ri) { - ri->curr = (RMAP_USES_HASHTAB(page)) ? - page->sharing->hash_table.bucket : - &page->sharing->gfns; - ri->next = ri->curr->next; + ri->curr = (RMAP_USES_HASHTAB(page) + ? page->sharing->hash_table.bucket + : &page->sharing->gfns); + ri->next = ri->curr->next; ri->bucket = 0; } -static inline gfn_info_t * -rmap_iterate(struct page_info *page, struct rmap_iterator *ri) +static gfn_info_t *rmap_iterate(struct page_info *page, + struct rmap_iterator *ri) { - struct list_head *head = (RMAP_USES_HASHTAB(page)) ? - page->sharing->hash_table.bucket + ri->bucket : - &page->sharing->gfns; + struct list_head *head = (RMAP_USES_HASHTAB(page) + ? page->sharing->hash_table.bucket + ri->bucket + : &page->sharing->gfns); -retry: + retry: if ( ri->next == head) { if ( RMAP_USES_HASHTAB(page) ) @@ -394,7 +402,8 @@ retry: ri->curr = head; ri->next = ri->curr->next; goto retry; - } else + } + else /* List exhausted */ return NULL; } @@ -405,14 +414,13 @@ retry: return list_entry(ri->curr, gfn_info_t, list); } -static inline gfn_info_t *mem_sharing_gfn_alloc(struct page_info *page, - struct domain *d, - unsigned long gfn) +static gfn_info_t *mem_sharing_gfn_alloc(struct page_info *page, + struct domain *d, unsigned long gfn) { gfn_info_t *gfn_info = xmalloc(gfn_info_t); if ( gfn_info == NULL ) - return NULL; + return NULL; gfn_info->gfn = gfn; gfn_info->domain = d->domain_id; @@ -425,9 +433,8 @@ static inline gfn_info_t *mem_sharing_gfn_alloc(struct page_info *page, return gfn_info; } -static inline void mem_sharing_gfn_destroy(struct page_info *page, - struct domain *d, - gfn_info_t *gfn_info) +static void mem_sharing_gfn_destroy(struct page_info *page, struct domain *d, + gfn_info_t *gfn_info) { /* Decrement the number of pages. */ atomic_dec(&d->shr_pages); @@ -437,25 +444,29 @@ static inline void mem_sharing_gfn_destroy(struct page_info *page, xfree(gfn_info); } -static struct page_info* mem_sharing_lookup(unsigned long mfn) +static struct page_info *mem_sharing_lookup(unsigned long mfn) { - if ( mfn_valid(_mfn(mfn)) ) - { - struct page_info* page = mfn_to_page(_mfn(mfn)); - if ( page_get_owner(page) == dom_cow ) - { - /* Count has to be at least two, because we're called - * with the mfn locked (1) and this is supposed to be - * a shared page (1). */ - unsigned long t = read_atomic(&page->u.inuse.type_info); - ASSERT((t & PGT_type_mask) == PGT_shared_page); - ASSERT((t & PGT_count_mask) >= 2); - ASSERT(SHARED_M2P(get_gpfn_from_mfn(mfn))); - return page; - } - } + struct page_info *page; + unsigned long t; - return NULL; + if ( !mfn_valid(_mfn(mfn)) ) + return NULL; + + page = mfn_to_page(_mfn(mfn)); + if ( page_get_owner(page) != dom_cow ) + return NULL; + + /* + * Count has to be at least two, because we're called + * with the mfn locked (1) and this is supposed to be + * a shared page (1). + */ + t = read_atomic(&page->u.inuse.type_info); + ASSERT((t & PGT_type_mask) == PGT_shared_page); + ASSERT((t & PGT_count_mask) >= 2); + ASSERT(SHARED_M2P(get_gpfn_from_mfn(mfn))); + + return page; } static int audit(void) @@ -470,7 +481,7 @@ static int audit(void) rcu_read_lock(&shr_audit_read_lock); - list_for_each_rcu(ae, &shr_audit_list) + list_for_each_rcu ( ae, &shr_audit_list ) { struct page_sharing_info *pg_shared_info; unsigned long nr_gfns = 0; @@ -486,44 +497,46 @@ static int audit(void) /* If we can't lock it, it's definitely not a shared page */ if ( !mem_sharing_page_lock(pg) ) { - MEM_SHARING_DEBUG("mfn %lx in audit list, but cannot be locked (%lx)!\n", - mfn_x(mfn), pg->u.inuse.type_info); - errors++; - continue; + MEM_SHARING_DEBUG( + "mfn %lx in audit list, but cannot be locked (%lx)!\n", + mfn_x(mfn), pg->u.inuse.type_info); + errors++; + continue; } - /* Check if the MFN has correct type, owner and handle. */ + /* Check if the MFN has correct type, owner and handle. */ if ( (pg->u.inuse.type_info & PGT_type_mask) != PGT_shared_page ) { - MEM_SHARING_DEBUG("mfn %lx in audit list, but not PGT_shared_page (%lx)!\n", - mfn_x(mfn), pg->u.inuse.type_info & PGT_type_mask); - errors++; - continue; + MEM_SHARING_DEBUG( + "mfn %lx in audit list, but not PGT_shared_page (%lx)!\n", + mfn_x(mfn), pg->u.inuse.type_info & PGT_type_mask); + errors++; + continue; } /* Check the page owner. */ if ( page_get_owner(pg) != dom_cow ) { - MEM_SHARING_DEBUG("mfn %lx shared, but wrong owner (%hu)!\n", - mfn_x(mfn), page_get_owner(pg)->domain_id); - errors++; + MEM_SHARING_DEBUG("mfn %lx shared, but wrong owner %pd!\n", + mfn_x(mfn), page_get_owner(pg)); + errors++; } /* Check the m2p entry */ if ( !SHARED_M2P(get_gpfn_from_mfn(mfn_x(mfn))) ) { - MEM_SHARING_DEBUG("mfn %lx shared, but wrong m2p entry (%lx)!\n", - mfn_x(mfn), get_gpfn_from_mfn(mfn_x(mfn))); - errors++; + MEM_SHARING_DEBUG("mfn %lx shared, but wrong m2p entry (%lx)!\n", + mfn_x(mfn), get_gpfn_from_mfn(mfn_x(mfn))); + errors++; } /* Check we have a list */ if ( (!pg->sharing) || !rmap_has_entries(pg) ) { - MEM_SHARING_DEBUG("mfn %lx shared, but empty gfn list!\n", - mfn_x(mfn)); - errors++; - continue; + MEM_SHARING_DEBUG("mfn %lx shared, but empty gfn list!\n", + mfn_x(mfn)); + errors++; + continue; } /* We've found a page that is shared */ @@ -545,7 +558,7 @@ static int audit(void) errors++; continue; } - o_mfn = get_gfn_query_unlocked(d, g->gfn, &t); + o_mfn = get_gfn_query_unlocked(d, g->gfn, &t); if ( !mfn_eq(o_mfn, mfn) ) { MEM_SHARING_DEBUG("Incorrect P2M for d=%hu, PFN=%lx." @@ -568,7 +581,7 @@ static int audit(void) { MEM_SHARING_DEBUG("Mismatched counts for MFN=%lx." "nr_gfns in list %lu, in type_info %lx\n", - mfn_x(mfn), nr_gfns, + mfn_x(mfn), nr_gfns, (pg->u.inuse.type_info & PGT_count_mask)); errors++; } @@ -600,11 +613,11 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned long gfn, .reason = VM_EVENT_REASON_MEM_SHARING, .vcpu_id = v->vcpu_id, .u.mem_sharing.gfn = gfn, - .u.mem_sharing.p2mt = p2m_ram_shared + .u.mem_sharing.p2mt = p2m_ram_shared, }; - if ( (rc = __vm_event_claim_slot(d, - d->vm_event_share, allow_sleep)) < 0 ) + if ( (rc = __vm_event_claim_slot( + d, d->vm_event_share, allow_sleep)) < 0 ) return rc; if ( v->domain == d ) @@ -620,18 +633,18 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned long gfn, unsigned int mem_sharing_get_nr_saved_mfns(void) { - return ((unsigned int)atomic_read(&nr_saved_mfns)); + return atomic_read(&nr_saved_mfns); } unsigned int mem_sharing_get_nr_shared_mfns(void) { - return (unsigned int)atomic_read(&nr_shared_mfns); + return atomic_read(&nr_shared_mfns); } /* Functions that change a page's type and ownership */ -static int page_make_sharable(struct domain *d, - struct page_info *page, - int expected_refcnt) +static int page_make_sharable(struct domain *d, + struct page_info *page, + int expected_refcnt) { bool_t drop_dom_ref; @@ -658,8 +671,10 @@ static int page_make_sharable(struct domain *d, return -EEXIST; } - /* Check if the ref count is 2. The first from PGC_allocated, and - * the second from get_page_and_type at the top of this function */ + /* + * Check if the ref count is 2. The first from PGC_allocated, and + * the second from get_page_and_type at the top of this function. + */ if ( page->count_info != (PGC_allocated | (2 + expected_refcnt)) ) { spin_unlock(&d->page_alloc_lock); @@ -684,7 +699,7 @@ static int page_make_private(struct domain *d, struct page_info *page) if ( !get_page(page, dom_cow) ) return -EINVAL; - + spin_lock(&d->page_alloc_lock); if ( d->is_dying ) @@ -721,16 +736,19 @@ static int page_make_private(struct domain *d, struct page_info *page) return 0; } -static inline struct page_info *__grab_shared_page(mfn_t mfn) +static struct page_info *__grab_shared_page(mfn_t mfn) { struct page_info *pg = NULL; if ( !mfn_valid(mfn) ) return NULL; + pg = mfn_to_page(mfn); - /* If the page is not validated we can't lock it, and if it's - * not validated it's obviously not shared. */ + /* + * If the page is not validated we can't lock it, and if it's + * not validated it's obviously not shared. + */ if ( !mem_sharing_page_lock(pg) ) return NULL; @@ -754,12 +772,10 @@ static int debug_mfn(mfn_t mfn) return -EINVAL; } - MEM_SHARING_DEBUG( - "Debug page: MFN=%lx is ci=%lx, ti=%lx, owner_id=%d\n", - mfn_x(page_to_mfn(page)), - page->count_info, - page->u.inuse.type_info, - page_get_owner(page)->domain_id); + MEM_SHARING_DEBUG( + "Debug page: MFN=%lx is ci=%lx, ti=%lx, owner=%pd\n", + mfn_x(page_to_mfn(page)), page->count_info, + page->u.inuse.type_info, page_get_owner(page)); /* -1 because the page is locked and that's an additional type ref */ num_refs = ((int) (page->u.inuse.type_info & PGT_count_mask)) - 1; @@ -775,7 +791,7 @@ static int debug_gfn(struct domain *d, gfn_t gfn) mfn = get_gfn_query(d, gfn_x(gfn), &p2mt); - MEM_SHARING_DEBUG("Debug for dom%d, gfn=%" PRI_gfn "\n", + MEM_SHARING_DEBUG("Debug for dom%d, gfn=%" PRI_gfn "\n", d->domain_id, gfn_x(gfn)); num_refs = debug_mfn(mfn); put_gfn(d, gfn_x(gfn)); @@ -796,10 +812,9 @@ static int debug_gref(struct domain *d, grant_ref_t ref) d->domain_id, ref, rc); return rc; } - - MEM_SHARING_DEBUG( - "==> Grant [dom=%d,ref=%d], status=%x. ", - d->domain_id, ref, status); + + MEM_SHARING_DEBUG("==> Grant [dom=%d,ref=%d], status=%x. ", + d->domain_id, ref, status); return debug_gfn(d, gfn); } @@ -824,15 +839,12 @@ static int nominate_page(struct domain *d, gfn_t gfn, goto out; /* Return the handle if the page is already shared */ - if ( p2m_is_shared(p2mt) ) { + if ( p2m_is_shared(p2mt) ) + { struct page_info *pg = __grab_shared_page(mfn); if ( !pg ) - { - gprintk(XENLOG_ERR, - "Shared p2m entry gfn %" PRI_gfn ", but could not grab mfn %" PRI_mfn " dom%d\n", - gfn_x(gfn), mfn_x(mfn), d->domain_id); BUG(); - } + *phandle = pg->sharing->handle; ret = 0; mem_sharing_page_unlock(pg); @@ -843,7 +855,6 @@ static int nominate_page(struct domain *d, gfn_t gfn, if ( !p2m_is_sharable(p2mt) ) goto out; -#ifdef CONFIG_HVM /* Check if there are mem_access/remapped altp2m entries for this page */ if ( altp2m_active(d) ) { @@ -872,42 +883,42 @@ static int nominate_page(struct domain *d, gfn_t gfn, altp2m_list_unlock(d); } -#endif /* Try to convert the mfn to the sharable type */ page = mfn_to_page(mfn); - ret = page_make_sharable(d, page, expected_refcnt); - if ( ret ) + ret = page_make_sharable(d, page, expected_refcnt); + if ( ret ) goto out; - /* Now that the page is validated, we can lock it. There is no - * race because we're holding the p2m entry, so no one else - * could be nominating this gfn */ + /* + * Now that the page is validated, we can lock it. There is no + * race because we're holding the p2m entry, so no one else + * could be nominating this gfn. + */ ret = -ENOENT; if ( !mem_sharing_page_lock(page) ) goto out; /* Initialize the shared state */ ret = -ENOMEM; - if ( (page->sharing = - xmalloc(struct page_sharing_info)) == NULL ) + if ( !(page->sharing = xmalloc(struct page_sharing_info)) ) { /* Making a page private atomically unlocks it */ - BUG_ON(page_make_private(d, page) != 0); + BUG_ON(page_make_private(d, page)); goto out; } page->sharing->pg = page; rmap_init(page); /* Create the handle */ - page->sharing->handle = get_next_handle(); + page->sharing->handle = get_next_handle(); /* Create the local gfn info */ - if ( mem_sharing_gfn_alloc(page, d, gfn_x(gfn)) == NULL ) + if ( !mem_sharing_gfn_alloc(page, d, gfn_x(gfn)) ) { xfree(page->sharing); page->sharing = NULL; - BUG_ON(page_make_private(d, page) != 0); + BUG_ON(page_make_private(d, page)); goto out; } @@ -946,19 +957,24 @@ static int share_pages(struct domain *sd, gfn_t sgfn, shr_handle_t sh, get_two_gfns(sd, sgfn, &smfn_type, NULL, &smfn, cd, cgfn, &cmfn_type, NULL, &cmfn, 0, &tg); - /* This tricky business is to avoid two callers deadlocking if - * grabbing pages in opposite client/source order */ + /* + * This tricky business is to avoid two callers deadlocking if + * grabbing pages in opposite client/source order. + */ if ( mfn_eq(smfn, cmfn) ) { - /* The pages are already the same. We could return some + /* + * The pages are already the same. We could return some * kind of error here, but no matter how you look at it, * the pages are already 'shared'. It possibly represents * a big problem somewhere else, but as far as sharing is - * concerned: great success! */ + * concerned: great success! + */ ret = 0; goto err_out; } - else if ( mfn_x(smfn) < mfn_x(cmfn) ) + + if ( mfn_x(smfn) < mfn_x(cmfn) ) { ret = XENMEM_SHARING_OP_S_HANDLE_INVALID; spage = firstpg = __grab_shared_page(smfn); @@ -972,7 +988,9 @@ static int share_pages(struct domain *sd, gfn_t sgfn, shr_handle_t sh, mem_sharing_page_unlock(spage); goto err_out; } - } else { + } + else + { ret = XENMEM_SHARING_OP_C_HANDLE_INVALID; cpage = firstpg = __grab_shared_page(cmfn); if ( cpage == NULL ) @@ -998,6 +1016,7 @@ static int share_pages(struct domain *sd, gfn_t sgfn, shr_handle_t sh, mem_sharing_page_unlock(firstpg); goto err_out; } + if ( cpage->sharing->handle != ch ) { ret = XENMEM_SHARING_OP_C_HANDLE_INVALID; @@ -1010,11 +1029,15 @@ static int share_pages(struct domain *sd, gfn_t sgfn, shr_handle_t sh, rmap_seed_iterator(cpage, &ri); while ( (gfn = rmap_iterate(cpage, &ri)) != NULL) { - /* Get the source page and type, this should never fail: - * we are under shr lock, and got a successful lookup */ + /* + * Get the source page and type, this should never fail: + * we are under shr lock, and got a successful lookup. + */ BUG_ON(!get_page_and_type(spage, dom_cow, PGT_shared_page)); - /* Move the gfn_info from client list to source list. - * Don't change the type of rmap for the client page. */ + /* + * Move the gfn_info from client list to source list. + * Don't change the type of rmap for the client page. + */ rmap_del(gfn, cpage, 0); rmap_add(gfn, spage); put_count++; @@ -1043,14 +1066,14 @@ static int share_pages(struct domain *sd, gfn_t sgfn, shr_handle_t sh, atomic_dec(&nr_shared_mfns); atomic_inc(&nr_saved_mfns); ret = 0; - + err_out: put_two_gfns(&tg); return ret; } int mem_sharing_add_to_physmap(struct domain *sd, unsigned long sgfn, shr_handle_t sh, - struct domain *cd, unsigned long cgfn) + struct domain *cd, unsigned long cgfn) { struct page_info *spage; int ret = -EINVAL; @@ -1069,15 +1092,18 @@ int mem_sharing_add_to_physmap(struct domain *sd, unsigned long sgfn, shr_handle spage = __grab_shared_page(smfn); if ( spage == NULL ) goto err_out; + ASSERT(smfn_type == p2m_ram_shared); /* Check that the handles match */ if ( spage->sharing->handle != sh ) goto err_unlock; - /* Make sure the target page is a hole in the physmap. These are typically + /* + * Make sure the target page is a hole in the physmap. These are typically * p2m_mmio_dm, but also accept p2m_invalid and paged out pages. See the - * definition of p2m_is_hole in p2m.h. */ + * definition of p2m_is_hole in p2m.h. + */ if ( !p2m_is_hole(cmfn_type) ) { ret = XENMEM_SHARING_OP_C_HANDLE_INVALID; @@ -1086,7 +1112,7 @@ int mem_sharing_add_to_physmap(struct domain *sd, unsigned long sgfn, shr_handle /* This is simpler than regular sharing */ BUG_ON(!get_page_and_type(spage, dom_cow, PGT_shared_page)); - if ( (gfn_info = mem_sharing_gfn_alloc(spage, cd, cgfn)) == NULL ) + if ( !(gfn_info = mem_sharing_gfn_alloc(spage, cd, cgfn)) ) { put_page_and_type(spage); ret = -ENOMEM; @@ -1101,12 +1127,20 @@ int mem_sharing_add_to_physmap(struct domain *sd, unsigned long sgfn, shr_handle { mem_sharing_gfn_destroy(spage, cd, gfn_info); put_page_and_type(spage); - } else { - /* There is a chance we're plugging a hole where a paged out page was */ + } + else + { + /* + * There is a chance we're plugging a hole where a paged out + * page was. + */ if ( p2m_is_paging(cmfn_type) && (cmfn_type != p2m_ram_paging_out) ) { atomic_dec(&cd->paged_pages); - /* Further, there is a chance this was a valid page. Don't leak it. */ + /* + * Further, there is a chance this was a valid page. + * Don't leak it. + */ if ( mfn_valid(cmfn) ) { struct page_info *cpage = mfn_to_page(cmfn); @@ -1133,13 +1167,14 @@ err_out: } -/* A note on the rationale for unshare error handling: +/* + * A note on the rationale for unshare error handling: * 1. Unshare can only fail with ENOMEM. Any other error conditions BUG_ON()'s * 2. We notify a potential dom0 helper through a vm_event ring. But we - * allow the notification to not go to sleep. If the event ring is full + * allow the notification to not go to sleep. If the event ring is full * of ENOMEM warnings, then it's on the ball. * 3. We cannot go to sleep until the unshare is resolved, because we might - * be buried deep into locks (e.g. something -> copy_to_user -> __hvm_copy) + * be buried deep into locks (e.g. something -> copy_to_user -> __hvm_copy) * 4. So, we make sure we: * 4.1. return an error * 4.2. do not corrupt shared memory @@ -1147,19 +1182,20 @@ err_out: * 4.4. let the guest deal with it if the error propagation will reach it */ int __mem_sharing_unshare_page(struct domain *d, - unsigned long gfn, - uint16_t flags) + unsigned long gfn, + uint16_t flags) { p2m_type_t p2mt; mfn_t mfn; struct page_info *page, *old_page; int last_gfn; gfn_info_t *gfn_info = NULL; - + mfn = get_gfn(d, gfn, &p2mt); - + /* Has someone already unshared it? */ - if ( !p2m_is_shared(p2mt) ) { + if ( !p2m_is_shared(p2mt) ) + { put_gfn(d, gfn); return 0; } @@ -1167,26 +1203,30 @@ int __mem_sharing_unshare_page(struct domain *d, page = __grab_shared_page(mfn); if ( page == NULL ) { - gdprintk(XENLOG_ERR, "Domain p2m is shared, but page is not: " - "%lx\n", gfn); + gdprintk(XENLOG_ERR, "Domain p2m is shared, but page is not: %lx\n", + gfn); BUG(); } gfn_info = rmap_retrieve(d->domain_id, gfn, page); if ( unlikely(gfn_info == NULL) ) { - gdprintk(XENLOG_ERR, "Could not find gfn_info for shared gfn: " - "%lx\n", gfn); + gdprintk(XENLOG_ERR, "Could not find gfn_info for shared gfn: %lx\n", + gfn); BUG(); } - /* Do the accounting first. If anything fails below, we have bigger - * bigger fish to fry. First, remove the gfn from the list. */ + /* + * Do the accounting first. If anything fails below, we have bigger + * bigger fish to fry. First, remove the gfn from the list. + */ last_gfn = rmap_has_one_entry(page); if ( last_gfn ) { - /* Clean up shared state. Get rid of the <domid, gfn> tuple - * before destroying the rmap. */ + /* + * Clean up shared state. Get rid of the <domid, gfn> tuple + * before destroying the rmap. + */ mem_sharing_gfn_destroy(page, d, gfn_info); page_sharing_dispose(page); page->sharing = NULL; @@ -1195,8 +1235,10 @@ int __mem_sharing_unshare_page(struct domain *d, else atomic_dec(&nr_saved_mfns); - /* If the GFN is getting destroyed drop the references to MFN - * (possibly freeing the page), and exit early */ + /* + * If the GFN is getting destroyed drop the references to MFN + * (possibly freeing the page), and exit early. + */ if ( flags & MEM_SHARING_DESTROY_GFN ) { if ( !last_gfn ) @@ -1212,7 +1254,7 @@ int __mem_sharing_unshare_page(struct domain *d, return 0; } - + if ( last_gfn ) { /* Making a page private atomically unlocks it */ @@ -1222,14 +1264,16 @@ int __mem_sharing_unshare_page(struct domain *d, old_page = page; page = alloc_domheap_page(d, 0); - if ( !page ) + if ( !page ) { /* Undo dec of nr_saved_mfns, as the retry will decrease again. */ atomic_inc(&nr_saved_mfns); mem_sharing_page_unlock(old_page); put_gfn(d, gfn); - /* Caller is responsible for placing an event - * in the ring */ + /* + * Caller is responsible for placing an event + * in the ring. + */ return -ENOMEM; } @@ -1240,19 +1284,21 @@ int __mem_sharing_unshare_page(struct domain *d, mem_sharing_page_unlock(old_page); put_page_and_type(old_page); -private_page_found: + private_page_found: if ( p2m_change_type_one(d, gfn, p2m_ram_shared, p2m_ram_rw) ) { - gdprintk(XENLOG_ERR, "Could not change p2m type d %hu gfn %lx.\n", - d->domain_id, gfn); + gdprintk(XENLOG_ERR, "Could not change p2m type d %hu gfn %lx.\n", + d->domain_id, gfn); BUG(); } /* Update m2p entry */ set_gpfn_from_mfn(mfn_x(page_to_mfn(page)), gfn); - /* Now that the gfn<->mfn map is properly established, - * marking dirty is feasible */ + /* + * Now that the gfn<->mfn map is properly established, + * marking dirty is feasible + */ paging_mark_dirty(d, page_to_mfn(page)); /* We do not need to unlock a private page */ put_gfn(d, gfn); @@ -1277,20 +1323,23 @@ int relinquish_shared_pages(struct domain *d) mfn_t mfn; int set_rc; - if ( atomic_read(&d->shr_pages) == 0 ) + if ( !atomic_read(&d->shr_pages) ) break; + mfn = p2m->get_entry(p2m, _gfn(gfn), &t, &a, 0, NULL, NULL); - if ( mfn_valid(mfn) && (t == p2m_ram_shared) ) + if ( mfn_valid(mfn) && t == p2m_ram_shared ) { /* Does not fail with ENOMEM given the DESTROY flag */ - BUG_ON(__mem_sharing_unshare_page(d, gfn, - MEM_SHARING_DESTROY_GFN)); - /* Clear out the p2m entry so no one else may try to + BUG_ON(__mem_sharing_unshare_page( + d, gfn, MEM_SHARING_DESTROY_GFN)); + /* + * Clear out the p2m entry so no one else may try to * unshare. Must succeed: we just read the old entry and - * we hold the p2m lock. */ + * we hold the p2m lock. + */ set_rc = p2m->set_entry(p2m, _gfn(gfn), _mfn(0), PAGE_ORDER_4K, p2m_invalid, p2m_access_rwx, -1); - ASSERT(set_rc == 0); + ASSERT(!set_rc); count += 0x10; } else @@ -1392,255 +1441,255 @@ int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg) switch ( mso.op ) { - case XENMEM_sharing_op_nominate_gfn: - { - shr_handle_t handle; + case XENMEM_sharing_op_nominate_gfn: + { + shr_handle_t handle; - rc = -EINVAL; - if ( !mem_sharing_enabled(d) ) - goto out; + rc = -EINVAL; + if ( !mem_sharing_enabled(d) ) + goto out; - rc = nominate_page(d, _gfn(mso.u.nominate.u.gfn), 0, &handle); - mso.u.nominate.handle = handle; - } - break; + rc = nominate_page(d, _gfn(mso.u.nominate.u.gfn), 0, &handle); + mso.u.nominate.handle = handle; + } + break; - case XENMEM_sharing_op_nominate_gref: - { - grant_ref_t gref = mso.u.nominate.u.grant_ref; - gfn_t gfn; - shr_handle_t handle; + case XENMEM_sharing_op_nominate_gref: + { + grant_ref_t gref = mso.u.nominate.u.grant_ref; + gfn_t gfn; + shr_handle_t handle; + + rc = -EINVAL; + if ( !mem_sharing_enabled(d) ) + goto out; + rc = mem_sharing_gref_to_gfn(d->grant_table, gref, &gfn, NULL); + if ( rc < 0 ) + goto out; + + rc = nominate_page(d, gfn, 3, &handle); + mso.u.nominate.handle = handle; + } + break; - rc = -EINVAL; - if ( !mem_sharing_enabled(d) ) - goto out; - rc = mem_sharing_gref_to_gfn(d->grant_table, gref, &gfn, NULL); - if ( rc < 0 ) - goto out; + case XENMEM_sharing_op_share: + { + gfn_t sgfn, cgfn; + struct domain *cd; + shr_handle_t sh, ch; - rc = nominate_page(d, gfn, 3, &handle); - mso.u.nominate.handle = handle; - } - break; + rc = -EINVAL; + if ( !mem_sharing_enabled(d) ) + goto out; - case XENMEM_sharing_op_share: + rc = rcu_lock_live_remote_domain_by_id(mso.u.share.client_domain, + &cd); + if ( rc ) + goto out; + + rc = xsm_mem_sharing_op(XSM_DM_PRIV, d, cd, mso.op); + if ( rc ) { - gfn_t sgfn, cgfn; - struct domain *cd; - shr_handle_t sh, ch; + rcu_unlock_domain(cd); + goto out; + } + if ( !mem_sharing_enabled(cd) ) + { + rcu_unlock_domain(cd); rc = -EINVAL; - if ( !mem_sharing_enabled(d) ) - goto out; + goto out; + } - rc = rcu_lock_live_remote_domain_by_id(mso.u.share.client_domain, - &cd); - if ( rc ) - goto out; + if ( XENMEM_SHARING_OP_FIELD_IS_GREF(mso.u.share.source_gfn) ) + { + grant_ref_t gref = + XENMEM_SHARING_OP_FIELD_GET_GREF(mso.u.share.source_gfn); - rc = xsm_mem_sharing_op(XSM_DM_PRIV, d, cd, mso.op); - if ( rc ) + rc = mem_sharing_gref_to_gfn(d->grant_table, gref, &sgfn, + NULL); + if ( rc < 0 ) { rcu_unlock_domain(cd); goto out; } + } + else + sgfn = _gfn(mso.u.share.source_gfn); - if ( !mem_sharing_enabled(cd) ) + if ( XENMEM_SHARING_OP_FIELD_IS_GREF(mso.u.share.client_gfn) ) + { + grant_ref_t gref = + XENMEM_SHARING_OP_FIELD_GET_GREF(mso.u.share.client_gfn); + + rc = mem_sharing_gref_to_gfn(cd->grant_table, gref, &cgfn, + NULL); + if ( rc < 0 ) { rcu_unlock_domain(cd); - rc = -EINVAL; goto out; } + } + else + cgfn = _gfn(mso.u.share.client_gfn); - if ( XENMEM_SHARING_OP_FIELD_IS_GREF(mso.u.share.source_gfn) ) - { - grant_ref_t gref = (grant_ref_t) - (XENMEM_SHARING_OP_FIELD_GET_GREF( - mso.u.share.source_gfn)); - rc = mem_sharing_gref_to_gfn(d->grant_table, gref, &sgfn, - NULL); - if ( rc < 0 ) - { - rcu_unlock_domain(cd); - goto out; - } - } - else - sgfn = _gfn(mso.u.share.source_gfn); + sh = mso.u.share.source_handle; + ch = mso.u.share.client_handle; - if ( XENMEM_SHARING_OP_FIELD_IS_GREF(mso.u.share.client_gfn) ) - { - grant_ref_t gref = (grant_ref_t) - (XENMEM_SHARING_OP_FIELD_GET_GREF( - mso.u.share.client_gfn)); - rc = mem_sharing_gref_to_gfn(cd->grant_table, gref, &cgfn, - NULL); - if ( rc < 0 ) - { - rcu_unlock_domain(cd); - goto out; - } - } - else - cgfn = _gfn(mso.u.share.client_gfn); + rc = share_pages(d, sgfn, sh, cd, cgfn, ch); - sh = mso.u.share.source_handle; - ch = mso.u.share.client_handle; + rcu_unlock_domain(cd); + } + break; - rc = share_pages(d, sgfn, sh, cd, cgfn, ch); + case XENMEM_sharing_op_add_physmap: + { + unsigned long sgfn, cgfn; + struct domain *cd; + shr_handle_t sh; + + rc = -EINVAL; + if ( !mem_sharing_enabled(d) ) + goto out; + rc = rcu_lock_live_remote_domain_by_id(mso.u.share.client_domain, + &cd); + if ( rc ) + goto out; + + rc = xsm_mem_sharing_op(XSM_DM_PRIV, d, cd, mso.op); + if ( rc ) + { rcu_unlock_domain(cd); + goto out; } - break; - case XENMEM_sharing_op_add_physmap: + if ( !mem_sharing_enabled(cd) ) { - unsigned long sgfn, cgfn; - struct domain *cd; - shr_handle_t sh; + rcu_unlock_domain(cd); + rc = -EINVAL; + goto out; + } + if ( XENMEM_SHARING_OP_FIELD_IS_GREF(mso.u.share.source_gfn) ) + { + /* Cannot add a gref to the physmap */ + rcu_unlock_domain(cd); rc = -EINVAL; - if ( !mem_sharing_enabled(d) ) - goto out; + goto out; + } - rc = rcu_lock_live_remote_domain_by_id(mso.u.share.client_domain, - &cd); - if ( rc ) - goto out; + sgfn = mso.u.share.source_gfn; + sh = mso.u.share.source_handle; + cgfn = mso.u.share.client_gfn; - rc = xsm_mem_sharing_op(XSM_DM_PRIV, d, cd, mso.op); - if ( rc ) - { - rcu_unlock_domain(cd); - goto out; - } + rc = mem_sharing_add_to_physmap(d, sgfn, sh, cd, cgfn); - if ( !mem_sharing_enabled(cd) ) - { - rcu_unlock_domain(cd); - rc = -EINVAL; - goto out; - } + rcu_unlock_domain(cd); + } + break; - if ( XENMEM_SHARING_OP_FIELD_IS_GREF(mso.u.share.source_gfn) ) - { - /* Cannot add a gref to the physmap */ - rcu_unlock_domain(cd); - rc = -EINVAL; - goto out; - } + case XENMEM_sharing_op_range_share: + { + unsigned long max_sgfn, max_cgfn; + struct domain *cd; + + rc = -EINVAL; + if ( mso.u.range._pad[0] || mso.u.range._pad[1] || + mso.u.range._pad[2] ) + goto out; - sgfn = mso.u.share.source_gfn; - sh = mso.u.share.source_handle; - cgfn = mso.u.share.client_gfn; + /* + * We use opaque for the hypercall continuation value. + * Ideally the user sets this to 0 in the beginning but + * there is no good way of enforcing that here, so we just check + * that it's at least in range. + */ + if ( mso.u.range.opaque && + (mso.u.range.opaque < mso.u.range.first_gfn || + mso.u.range.opaque > mso.u.range.last_gfn) ) + goto out; - rc = mem_sharing_add_to_physmap(d, sgfn, sh, cd, cgfn); + if ( !mem_sharing_enabled(d) ) + goto out; + rc = rcu_lock_live_remote_domain_by_id(mso.u.range.client_domain, + &cd); + if ( rc ) + goto out; + + /* + * We reuse XENMEM_sharing_op_share XSM check here as this is + * essentially the same concept repeated over multiple pages. + */ + rc = xsm_mem_sharing_op(XSM_DM_PRIV, d, cd, + XENMEM_sharing_op_share); + if ( rc ) + { rcu_unlock_domain(cd); + goto out; } - break; - case XENMEM_sharing_op_range_share: + if ( !mem_sharing_enabled(cd) ) { - unsigned long max_sgfn, max_cgfn; - struct domain *cd; - + rcu_unlock_domain(cd); rc = -EINVAL; - if ( mso.u.range._pad[0] || mso.u.range._pad[1] || - mso.u.range._pad[2] ) - goto out; - - /* - * We use opaque for the hypercall continuation value. - * Ideally the user sets this to 0 in the beginning but - * there is no good way of enforcing that here, so we just check - * that it's at least in range. - */ - if ( mso.u.range.opaque && - (mso.u.range.opaque < mso.u.range.first_gfn || - mso.u.range.opaque > mso.u.range.last_gfn) ) - goto out; - - if ( !mem_sharing_enabled(d) ) - goto out; - - rc = rcu_lock_live_remote_domain_by_id(mso.u.range.client_domain, - &cd); - if ( rc ) - goto out; - - /* - * We reuse XENMEM_sharing_op_share XSM check here as this is - * essentially the same concept repeated over multiple pages. - */ - rc = xsm_mem_sharing_op(XSM_DM_PRIV, d, cd, - XENMEM_sharing_op_share); - if ( rc ) - { - rcu_unlock_domain(cd); - goto out; - } - - if ( !mem_sharing_enabled(cd) ) - { - rcu_unlock_domain(cd); - rc = -EINVAL; - goto out; - } - - /* - * Sanity check only, the client should keep the domains paused for - * the duration of this op. - */ - if ( !atomic_read(&d->pause_count) || - !atomic_read(&cd->pause_count) ) - { - rcu_unlock_domain(cd); - rc = -EINVAL; - goto out; - } + goto out; + } - max_sgfn = domain_get_maximum_gpfn(d); - max_cgfn = domain_get_maximum_gpfn(cd); + /* + * Sanity check only, the client should keep the domains paused for + * the duration of this op. + */ + if ( !atomic_read(&d->pause_count) || + !atomic_read(&cd->pause_count) ) + { + rcu_unlock_domain(cd); + rc = -EINVAL; + goto out; + } - if ( max_sgfn < mso.u.range.first_gfn || - max_sgfn < mso.u.range.last_gfn || - max_cgfn < mso.u.range.first_gfn || - max_cgfn < mso.u.range.last_gfn ) - { - rcu_unlock_domain(cd); - rc = -EINVAL; - goto out; - } + max_sgfn = domain_get_maximum_gpfn(d); + max_cgfn = domain_get_maximum_gpfn(cd); - rc = range_share(d, cd, &mso.u.range); + if ( max_sgfn < mso.u.range.first_gfn || + max_sgfn < mso.u.range.last_gfn || + max_cgfn < mso.u.range.first_gfn || + max_cgfn < mso.u.range.last_gfn ) + { rcu_unlock_domain(cd); + rc = -EINVAL; + goto out; + } - if ( rc > 0 ) - { - if ( __copy_to_guest(arg, &mso, 1) ) - rc = -EFAULT; - else - rc = hypercall_create_continuation(__HYPERVISOR_memory_op, - "lh", XENMEM_sharing_op, - arg); - } + rc = range_share(d, cd, &mso.u.range); + rcu_unlock_domain(cd); + + if ( rc > 0 ) + { + if ( __copy_to_guest(arg, &mso, 1) ) + rc = -EFAULT; else - mso.u.range.opaque = 0; + rc = hypercall_create_continuation(__HYPERVISOR_memory_op, + "lh", XENMEM_sharing_op, + arg); } - break; + else + mso.u.range.opaque = 0; + } + break; - case XENMEM_sharing_op_debug_gfn: - rc = debug_gfn(d, _gfn(mso.u.debug.u.gfn)); - break; + case XENMEM_sharing_op_debug_gfn: + rc = debug_gfn(d, _gfn(mso.u.debug.u.gfn)); + break; - case XENMEM_sharing_op_debug_gref: - rc = debug_gref(d, mso.u.debug.u.gref); - break; + case XENMEM_sharing_op_debug_gref: + rc = debug_gref(d, mso.u.debug.u.gref); + break; - default: - rc = -ENOSYS; - break; + default: + rc = -ENOSYS; + break; } if ( !rc && __copy_to_guest(arg, &mso, 1) ) @@ -1657,22 +1706,21 @@ int mem_sharing_domctl(struct domain *d, struct xen_domctl_mem_sharing_op *mec) /* Only HAP is supported */ if ( !hap_enabled(d) ) - return -ENODEV; + return -ENODEV; - switch(mec->op) + switch ( mec->op ) { - case XEN_DOMCTL_MEM_SHARING_CONTROL: - { - rc = 0; - if ( unlikely(is_iommu_enabled(d) && mec->u.enable) ) - rc = -EXDEV; - else - d->arch.hvm.mem_sharing_enabled = mec->u.enable; - } + case XEN_DOMCTL_MEM_SHARING_CONTROL: + rc = 0; + if ( unlikely(is_iommu_enabled(d) && mec->u.enable) ) + rc = -EXDEV; + else + d->arch.hvm.mem_sharing_enabled = mec->u.enable; break; - default: - rc = -ENOSYS; + default: + rc = -ENOSYS; + break; } return rc; diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index ba126f790a..3119269073 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -511,8 +511,10 @@ mfn_t __get_gfn_type_access(struct p2m_domain *p2m, unsigned long gfn_l, if ( (q & P2M_UNSHARE) && p2m_is_shared(*t) ) { ASSERT(p2m_is_hostp2m(p2m)); - /* Try to unshare. If we fail, communicate ENOMEM without - * sleeping. */ + /* + * Try to unshare. If we fail, communicate ENOMEM without + * sleeping. + */ if ( mem_sharing_unshare_page(p2m->domain, gfn_l, 0) < 0 ) mem_sharing_notify_enomem(p2m->domain, gfn_l, false); mfn = p2m->get_entry(p2m, gfn, t, a, q, page_order, NULL); @@ -892,15 +894,15 @@ guest_physmap_add_entry(struct domain *d, gfn_t gfn, mfn_t mfn, &a, 0, NULL, NULL); if ( p2m_is_shared(ot) ) { - /* Do an unshare to cleanly take care of all corner - * cases. */ + /* Do an unshare to cleanly take care of all corner cases. */ int rc; rc = mem_sharing_unshare_page(p2m->domain, gfn_x(gfn_add(gfn, i)), 0); if ( rc ) { p2m_unlock(p2m); - /* NOTE: Should a guest domain bring this upon itself, + /* + * NOTE: Should a guest domain bring this upon itself, * there is not a whole lot we can do. We are buried * deep in locks from most code paths by now. So, fail * the call and don't try to sleep on a wait queue @@ -909,8 +911,9 @@ guest_physmap_add_entry(struct domain *d, gfn_t gfn, mfn_t mfn, * However, all current (changeset 3432abcf9380) code * paths avoid this unsavoury situation. For now. * - * Foreign domains are okay to place an event as they - * won't go to sleep. */ + * Foreign domains are okay to place an event as they + * won't go to sleep. + */ (void)mem_sharing_notify_enomem(p2m->domain, gfn_x(gfn_add(gfn, i)), false); return rc; diff --git a/xen/include/asm-x86/mem_sharing.h b/xen/include/asm-x86/mem_sharing.h index db22468744..af2a1038b5 100644 --- a/xen/include/asm-x86/mem_sharing.h +++ b/xen/include/asm-x86/mem_sharing.h @@ -33,12 +33,14 @@ #define MEM_SHARING_AUDIT 0 #endif -typedef uint64_t shr_handle_t; +typedef uint64_t shr_handle_t; typedef struct rmap_hashtab { struct list_head *bucket; - /* Overlaps with prev pointer of list_head in union below. - * Unlike the prev pointer, this can be NULL. */ + /* + * Overlaps with prev pointer of list_head in union below. + * Unlike the prev pointer, this can be NULL. + */ void *flag; } rmap_hashtab_t; @@ -57,34 +59,33 @@ struct page_sharing_info }; }; -#define sharing_supported(_d) \ - (is_hvm_domain(_d) && paging_mode_hap(_d)) - unsigned int mem_sharing_get_nr_saved_mfns(void); unsigned int mem_sharing_get_nr_shared_mfns(void); #define MEM_SHARING_DESTROY_GFN (1<<1) /* Only fails with -ENOMEM. Enforce it with a BUG_ON wrapper. */ int __mem_sharing_unshare_page(struct domain *d, - unsigned long gfn, - uint16_t flags); + unsigned long gfn, + uint16_t flags); + static inline int mem_sharing_unshare_page(struct domain *d, unsigned long gfn, uint16_t flags) { int rc = __mem_sharing_unshare_page(d, gfn, flags); - BUG_ON( rc && (rc != -ENOMEM) ); + BUG_ON(rc && (rc != -ENOMEM)); return rc; } -/* If called by a foreign domain, possible errors are +/* + * If called by a foreign domain, possible errors are * -EBUSY -> ring full * -ENOSYS -> no ring to begin with * and the foreign mapper is responsible for retrying. * - * If called by the guest vcpu itself and allow_sleep is set, may - * sleep on a wait queue, so the caller is responsible for not - * holding locks on entry. It may only fail with ENOSYS + * If called by the guest vcpu itself and allow_sleep is set, may + * sleep on a wait queue, so the caller is responsible for not + * holding locks on entry. It may only fail with ENOSYS * * If called by the guest vcpu itself and allow_sleep is not set, * then it's the same as a foreign domain. @@ -92,10 +93,11 @@ static inline int mem_sharing_unshare_page(struct domain *d, int mem_sharing_notify_enomem(struct domain *d, unsigned long gfn, bool allow_sleep); int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg); -int mem_sharing_domctl(struct domain *d, +int mem_sharing_domctl(struct domain *d, struct xen_domctl_mem_sharing_op *mec); -/* Scans the p2m and relinquishes any shared pages, destroying +/* + * Scans the p2m and relinquishes any shared pages, destroying * those for which this domain holds the final reference. * Preemptible. */ @@ -107,19 +109,21 @@ static inline unsigned int mem_sharing_get_nr_saved_mfns(void) { return 0; } + static inline unsigned int mem_sharing_get_nr_shared_mfns(void) { return 0; } -static inline int mem_sharing_unshare_page(struct domain *d, - unsigned long gfn, + +static inline int mem_sharing_unshare_page(struct domain *d, unsigned long gfn, uint16_t flags) { ASSERT_UNREACHABLE(); return -EOPNOTSUPP; } + static inline int mem_sharing_notify_enomem(struct domain *d, unsigned long gfn, - bool allow_sleep) + bool allow_sleep) { ASSERT_UNREACHABLE(); return -EOPNOTSUPP; -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |