diff --git a/xen/arch/x86/include/asm/paging.h b/xen/arch/x86/include/asm/paging.h index f75e1b771a..38bec8af2e 100644 --- a/xen/arch/x86/include/asm/paging.h +++ b/xen/arch/x86/include/asm/paging.h @@ -187,6 +187,10 @@ bool paging_mfn_is_dirty(const struct domain *d, mfn_t gmfn); #define L4_LOGDIRTY_IDX(pfn) ((pfn_x(pfn) >> (PAGE_SHIFT + 3 + PAGETABLE_ORDER * 2)) & \ (LOGDIRTY_NODE_ENTRIES-1)) +#define paging_logdirty_levels() \ + (DIV_ROUND_UP(PADDR_BITS - PAGE_SHIFT - (PAGE_SHIFT + 3), \ + PAGE_SHIFT - ilog2(sizeof(mfn_t))) + 1) + #ifdef CONFIG_HVM /* VRAM dirty tracking support */ struct sh_dirty_vram { diff --git a/xen/arch/x86/mm/paging.c b/xen/arch/x86/mm/paging.c index 616010e6b8..ff5b480677 100644 --- a/xen/arch/x86/mm/paging.c +++ b/xen/arch/x86/mm/paging.c @@ -282,6 +282,7 @@ void paging_mark_pfn_dirty(struct domain *d, pfn_t pfn) if ( unlikely(!VALID_M2P(pfn_x(pfn))) ) return; + BUILD_BUG_ON(paging_logdirty_levels() != 4); i1 = L1_LOGDIRTY_IDX(pfn); i2 = L2_LOGDIRTY_IDX(pfn); i3 = L3_LOGDIRTY_IDX(pfn); diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 7ad0e538b3..7ced6aec0a 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -1012,7 +1012,17 @@ bool shadow_prealloc(struct domain *d, unsigned int type, unsigned int count) if ( unlikely(d->is_dying) ) return false; - ret = _shadow_prealloc(d, shadow_size(type) * count); + count *= shadow_size(type); + /* + * Log-dirty handling may result in allocations when populating its + * tracking structures. Tie this to the caller requesting space for L1 + * shadows. + */ + if ( paging_mode_log_dirty(d) && + ((SHF_L1_ANY | SHF_FL1_ANY) & (1u << type)) ) + count += paging_logdirty_levels(); + + ret = _shadow_prealloc(d, count); if ( !ret && (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) /* * Failing to allocate memory required for shadow usage can only result in