In current code, only one bit (bit 0) is used in rmap, this patch export more bits from rmap, during pte add/remove, it only touches bit 0 and other bits are keeped Signed-off-by: Xiao Guangrong <xiaoguangrong@xxxxxxxxxxxxxxxxxx> --- arch/x86/kvm/mmu.c | 143 +++++++++++++++++++++++++++++++++------------------- 1 files changed, 91 insertions(+), 52 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index bb4d292..84b9775 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -796,6 +796,17 @@ static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn) return level - 1; } +#define PTE_LIST_DESC (0x1ull) +#define PTE_LIST_FLAG_MASK (0x3ull) + +static void +pte_list_decode(const unsigned long *pte_list, unsigned long *map, + unsigned long *flags) +{ + *map = *pte_list & (~PTE_LIST_FLAG_MASK); + *flags = *pte_list & PTE_LIST_FLAG_MASK; +} + /* * Pte mapping structures: * @@ -812,50 +823,67 @@ static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte, unsigned long *pte_list) { struct pte_list_desc *desc; + unsigned long map, flags; int i, count = 0; - if (!*pte_list) { + pte_list_decode(pte_list, &map, &flags); + + if (!map) { rmap_printk("pte_list_add: %p %llx 0->1\n", spte, *spte); - *pte_list = (unsigned long)spte; - } else if (!(*pte_list & 1)) { + WARN_ON(flags & PTE_LIST_DESC); + *pte_list = (unsigned long)spte | flags ; + + return 0; + } + + if (!(flags & PTE_LIST_DESC)) { rmap_printk("pte_list_add: %p %llx 1->many\n", spte, *spte); desc = mmu_alloc_pte_list_desc(vcpu); - desc->sptes[0] = (u64 *)*pte_list; + desc->sptes[0] = (u64 *)map; desc->sptes[1] = spte; - *pte_list = (unsigned long)desc | 1; - ++count; - } else { - rmap_printk("pte_list_add: %p %llx many->many\n", spte, *spte); - desc = (struct pte_list_desc *)(*pte_list & ~1ul); - while (desc->sptes[PTE_LIST_EXT-1] && desc->more) { - desc = desc->more; - count += PTE_LIST_EXT; - } - if (desc->sptes[PTE_LIST_EXT-1]) { - desc->more = mmu_alloc_pte_list_desc(vcpu); - desc = desc->more; - } - for (i = 0; desc->sptes[i]; ++i) - ++count; - desc->sptes[i] = spte; + *pte_list = (unsigned long)desc | flags | PTE_LIST_DESC; + + return 1; + } + + rmap_printk("pte_list_add: %p %llx many->many\n", spte, *spte); + desc = (struct pte_list_desc *)map; + while (desc->sptes[PTE_LIST_EXT - 1] && desc->more) { + desc = desc->more; + count += PTE_LIST_EXT; + } + + if (desc->sptes[PTE_LIST_EXT - 1]) { + desc->more = mmu_alloc_pte_list_desc(vcpu); + desc = desc->more; } + + for (i = 0; desc->sptes[i]; ++i) + ++count; + desc->sptes[i] = spte; + return count; } static u64 *pte_list_next(unsigned long *pte_list, u64 *spte) { struct pte_list_desc *desc; + unsigned long map, flags; u64 *prev_spte; int i; - if (!*pte_list) + pte_list_decode(pte_list, &map, &flags); + + if (!map) return NULL; - else if (!(*pte_list & 1)) { + + if (!(flags & PTE_LIST_DESC)) { if (!spte) - return (u64 *)*pte_list; + return (u64 *)map; return NULL; } - desc = (struct pte_list_desc *)(*pte_list & ~1ul); + + desc = (struct pte_list_desc *)map; prev_spte = NULL; while (desc) { for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i) { @@ -870,7 +898,8 @@ static u64 *pte_list_next(unsigned long *pte_list, u64 *spte) static void pte_list_desc_remove_entry(unsigned long *pte_list, struct pte_list_desc *desc, - int i, struct pte_list_desc *prev_desc) + int i, struct pte_list_desc *prev_desc, + unsigned long flags) { int j; @@ -881,12 +910,13 @@ pte_list_desc_remove_entry(unsigned long *pte_list, struct pte_list_desc *desc, if (j != 0) return; if (!prev_desc && !desc->more) - *pte_list = (unsigned long)desc->sptes[0]; + *pte_list = (unsigned long)desc->sptes[0] | + (flags & (~PTE_LIST_DESC)) ; else if (prev_desc) prev_desc->more = desc->more; else - *pte_list = (unsigned long)desc->more | 1; + *pte_list = (unsigned long)desc->more | flags; mmu_free_pte_list_desc(desc); } @@ -894,51 +924,60 @@ static void pte_list_remove(u64 *spte, unsigned long *pte_list) { struct pte_list_desc *desc; struct pte_list_desc *prev_desc; + unsigned long map, flags; int i; - if (!*pte_list) { + pte_list_decode(pte_list, &map, &flags); + + if (!map) { printk(KERN_ERR "pte_list_remove: %p 0->BUG\n", spte); BUG(); - } else if (!(*pte_list & 1)) { + return; + } + + if (!(flags & PTE_LIST_DESC)) { rmap_printk("pte_list_remove: %p 1->0\n", spte); - if ((u64 *)*pte_list != spte) { + if ((u64 *)map != spte) { printk(KERN_ERR "pte_list_remove: %p 1->BUG\n", spte); BUG(); } - *pte_list = 0; - } else { - rmap_printk("pte_list_remove: %p many->many\n", spte); - desc = (struct pte_list_desc *)(*pte_list & ~1ul); - prev_desc = NULL; - while (desc) { - for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i) - if (desc->sptes[i] == spte) { - pte_list_desc_remove_entry(pte_list, - desc, i, - prev_desc); - return; - } - prev_desc = desc; - desc = desc->more; - } - pr_err("pte_list_remove: %p many->many\n", spte); - BUG(); + *pte_list = flags; + return; + } + + rmap_printk("pte_list_remove: %p many->many\n", spte); + desc = (struct pte_list_desc *)map; + prev_desc = NULL; + while (desc) { + for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i) + if (desc->sptes[i] == spte) { + pte_list_desc_remove_entry(pte_list, + desc, i, prev_desc, flags); + return; + } + prev_desc = desc; + desc = desc->more; } + pr_err("pte_list_remove: %p many->many\n", spte); + BUG(); } typedef void (*pte_list_walk_fn) (u64 *spte); static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn) { struct pte_list_desc *desc; + unsigned long map, flags; int i; - if (!*pte_list) + pte_list_decode(pte_list, &map, &flags); + + if (!map) return; - if (!(*pte_list & 1)) - return fn((u64 *)*pte_list); + if (!(flags & PTE_LIST_DESC)) + return fn((u64 *)map); - desc = (struct pte_list_desc *)(*pte_list & ~1ul); + desc = (struct pte_list_desc *)map; while (desc) { for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i) fn(desc->sptes[i]); -- 1.7.7.6 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html