Commit db3fe4eb authored by Takuya Yoshikawa's avatar Takuya Yoshikawa Committed by Avi Kivity

KVM: Introduce kvm_memory_slot::arch and move lpage_info into it

Some members of kvm_memory_slot are not used by every architecture.

This patch is the first step to make this difference clear by
introducing kvm_memory_slot::arch;  lpage_info is moved into it.
Signed-off-by: default avatarTakuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 189a2f7b
...@@ -459,6 +459,9 @@ struct kvm_sal_data { ...@@ -459,6 +459,9 @@ struct kvm_sal_data {
unsigned long boot_gp; unsigned long boot_gp;
}; };
struct kvm_arch_memory_slot {
};
struct kvm_arch { struct kvm_arch {
spinlock_t dirty_log_lock; spinlock_t dirty_log_lock;
......
...@@ -1571,6 +1571,16 @@ int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) ...@@ -1571,6 +1571,16 @@ int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
return VM_FAULT_SIGBUS; return VM_FAULT_SIGBUS;
} }
void kvm_arch_free_memslot(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont)
{
}
int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
{
return 0;
}
int kvm_arch_prepare_memory_region(struct kvm *kvm, int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot, struct kvm_memory_slot *memslot,
struct kvm_memory_slot old, struct kvm_memory_slot old,
......
...@@ -213,6 +213,9 @@ struct revmap_entry { ...@@ -213,6 +213,9 @@ struct revmap_entry {
#define KVMPPC_PAGE_WRITETHRU HPTE_R_W /* 0x40 */ #define KVMPPC_PAGE_WRITETHRU HPTE_R_W /* 0x40 */
#define KVMPPC_GOT_PAGE 0x80 #define KVMPPC_GOT_PAGE 0x80
struct kvm_arch_memory_slot {
};
struct kvm_arch { struct kvm_arch {
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_64_HV
unsigned long hpt_virt; unsigned long hpt_virt;
......
...@@ -281,6 +281,16 @@ long kvm_arch_dev_ioctl(struct file *filp, ...@@ -281,6 +281,16 @@ long kvm_arch_dev_ioctl(struct file *filp,
return -EINVAL; return -EINVAL;
} }
void kvm_arch_free_memslot(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont)
{
}
int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
{
return 0;
}
int kvm_arch_prepare_memory_region(struct kvm *kvm, int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot, struct kvm_memory_slot *memslot,
struct kvm_memory_slot old, struct kvm_memory_slot old,
......
...@@ -245,6 +245,9 @@ struct kvm_vm_stat { ...@@ -245,6 +245,9 @@ struct kvm_vm_stat {
u32 remote_tlb_flush; u32 remote_tlb_flush;
}; };
struct kvm_arch_memory_slot {
};
struct kvm_arch{ struct kvm_arch{
struct sca_block *sca; struct sca_block *sca;
debug_info_t *dbf; debug_info_t *dbf;
......
...@@ -814,6 +814,16 @@ int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) ...@@ -814,6 +814,16 @@ int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
return VM_FAULT_SIGBUS; return VM_FAULT_SIGBUS;
} }
void kvm_arch_free_memslot(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont)
{
}
int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
{
return 0;
}
/* Section: memory related */ /* Section: memory related */
int kvm_arch_prepare_memory_region(struct kvm *kvm, int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot, struct kvm_memory_slot *memslot,
......
...@@ -483,6 +483,15 @@ struct kvm_vcpu_arch { ...@@ -483,6 +483,15 @@ struct kvm_vcpu_arch {
} osvw; } osvw;
}; };
struct kvm_lpage_info {
unsigned long rmap_pde;
int write_count;
};
struct kvm_arch_memory_slot {
struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
};
struct kvm_arch { struct kvm_arch {
unsigned int n_used_mmu_pages; unsigned int n_used_mmu_pages;
unsigned int n_requested_mmu_pages; unsigned int n_requested_mmu_pages;
......
...@@ -689,7 +689,7 @@ static struct kvm_lpage_info *lpage_info_slot(gfn_t gfn, ...@@ -689,7 +689,7 @@ static struct kvm_lpage_info *lpage_info_slot(gfn_t gfn,
unsigned long idx; unsigned long idx;
idx = gfn_to_index(gfn, slot->base_gfn, level); idx = gfn_to_index(gfn, slot->base_gfn, level);
return &slot->lpage_info[level - 2][idx]; return &slot->arch.lpage_info[level - 2][idx];
} }
static void account_shadowed(struct kvm *kvm, gfn_t gfn) static void account_shadowed(struct kvm *kvm, gfn_t gfn)
......
...@@ -6239,6 +6239,65 @@ void kvm_arch_destroy_vm(struct kvm *kvm) ...@@ -6239,6 +6239,65 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
put_page(kvm->arch.ept_identity_pagetable); put_page(kvm->arch.ept_identity_pagetable);
} }
void kvm_arch_free_memslot(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont)
{
int i;
for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
if (!dont || free->arch.lpage_info[i] != dont->arch.lpage_info[i]) {
vfree(free->arch.lpage_info[i]);
free->arch.lpage_info[i] = NULL;
}
}
}
int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
{
int i;
for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
unsigned long ugfn;
int lpages;
int level = i + 2;
lpages = gfn_to_index(slot->base_gfn + npages - 1,
slot->base_gfn, level) + 1;
slot->arch.lpage_info[i] =
vzalloc(lpages * sizeof(*slot->arch.lpage_info[i]));
if (!slot->arch.lpage_info[i])
goto out_free;
if (slot->base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
slot->arch.lpage_info[i][0].write_count = 1;
if ((slot->base_gfn + npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
slot->arch.lpage_info[i][lpages - 1].write_count = 1;
ugfn = slot->userspace_addr >> PAGE_SHIFT;
/*
* If the gfn and userspace address are not aligned wrt each
* other, or if explicitly asked to, disable large page
* support for this slot
*/
if ((slot->base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE(level) - 1) ||
!kvm_largepages_enabled()) {
unsigned long j;
for (j = 0; j < lpages; ++j)
slot->arch.lpage_info[i][j].write_count = 1;
}
}
return 0;
out_free:
for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
vfree(slot->arch.lpage_info[i]);
slot->arch.lpage_info[i] = NULL;
}
return -ENOMEM;
}
int kvm_arch_prepare_memory_region(struct kvm *kvm, int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot, struct kvm_memory_slot *memslot,
struct kvm_memory_slot old, struct kvm_memory_slot old,
......
...@@ -171,11 +171,6 @@ static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu) ...@@ -171,11 +171,6 @@ static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu)
*/ */
#define KVM_MEM_MAX_NR_PAGES ((1UL << 31) - 1) #define KVM_MEM_MAX_NR_PAGES ((1UL << 31) - 1)
struct kvm_lpage_info {
unsigned long rmap_pde;
int write_count;
};
struct kvm_memory_slot { struct kvm_memory_slot {
gfn_t base_gfn; gfn_t base_gfn;
unsigned long npages; unsigned long npages;
...@@ -184,7 +179,7 @@ struct kvm_memory_slot { ...@@ -184,7 +179,7 @@ struct kvm_memory_slot {
unsigned long *dirty_bitmap; unsigned long *dirty_bitmap;
unsigned long *dirty_bitmap_head; unsigned long *dirty_bitmap_head;
unsigned long nr_dirty_pages; unsigned long nr_dirty_pages;
struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1]; struct kvm_arch_memory_slot arch;
unsigned long userspace_addr; unsigned long userspace_addr;
int user_alloc; int user_alloc;
int id; int id;
...@@ -376,6 +371,9 @@ int kvm_set_memory_region(struct kvm *kvm, ...@@ -376,6 +371,9 @@ int kvm_set_memory_region(struct kvm *kvm,
int __kvm_set_memory_region(struct kvm *kvm, int __kvm_set_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem, struct kvm_userspace_memory_region *mem,
int user_alloc); int user_alloc);
void kvm_arch_free_memslot(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont);
int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages);
int kvm_arch_prepare_memory_region(struct kvm *kvm, int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot, struct kvm_memory_slot *memslot,
struct kvm_memory_slot old, struct kvm_memory_slot old,
...@@ -385,6 +383,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, ...@@ -385,6 +383,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem, struct kvm_userspace_memory_region *mem,
struct kvm_memory_slot old, struct kvm_memory_slot old,
int user_alloc); int user_alloc);
bool kvm_largepages_enabled(void);
void kvm_disable_largepages(void); void kvm_disable_largepages(void);
void kvm_arch_flush_shadow(struct kvm *kvm); void kvm_arch_flush_shadow(struct kvm *kvm);
......
...@@ -535,21 +535,13 @@ static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot) ...@@ -535,21 +535,13 @@ static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot)
static void kvm_free_physmem_slot(struct kvm_memory_slot *free, static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont) struct kvm_memory_slot *dont)
{ {
int i;
if (!dont || free->rmap != dont->rmap) if (!dont || free->rmap != dont->rmap)
vfree(free->rmap); vfree(free->rmap);
if (!dont || free->dirty_bitmap != dont->dirty_bitmap) if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
kvm_destroy_dirty_bitmap(free); kvm_destroy_dirty_bitmap(free);
kvm_arch_free_memslot(free, dont);
for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
if (!dont || free->lpage_info[i] != dont->lpage_info[i]) {
vfree(free->lpage_info[i]);
free->lpage_info[i] = NULL;
}
}
free->npages = 0; free->npages = 0;
free->rmap = NULL; free->rmap = NULL;
...@@ -685,53 +677,6 @@ void update_memslots(struct kvm_memslots *slots, struct kvm_memory_slot *new) ...@@ -685,53 +677,6 @@ void update_memslots(struct kvm_memslots *slots, struct kvm_memory_slot *new)
slots->generation++; slots->generation++;
} }
#ifndef CONFIG_S390
static int create_lpage_info(struct kvm_memory_slot *slot, unsigned long npages)
{
int i;
for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
unsigned long ugfn;
int lpages;
int level = i + 2;
lpages = gfn_to_index(slot->base_gfn + npages - 1,
slot->base_gfn, level) + 1;
slot->lpage_info[i] = vzalloc(lpages * sizeof(*slot->lpage_info[i]));
if (!slot->lpage_info[i])
goto out_free;
if (slot->base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
slot->lpage_info[i][0].write_count = 1;
if ((slot->base_gfn + npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
slot->lpage_info[i][lpages - 1].write_count = 1;
ugfn = slot->userspace_addr >> PAGE_SHIFT;
/*
* If the gfn and userspace address are not aligned wrt each
* other, or if explicitly asked to, disable large page
* support for this slot
*/
if ((slot->base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE(level) - 1) ||
!largepages_enabled) {
unsigned long j;
for (j = 0; j < lpages; ++j)
slot->lpage_info[i][j].write_count = 1;
}
}
return 0;
out_free:
for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
vfree(slot->lpage_info[i]);
slot->lpage_info[i] = NULL;
}
return -ENOMEM;
}
#endif /* not defined CONFIG_S390 */
/* /*
* Allocate some memory and give it an address in the guest physical address * Allocate some memory and give it an address in the guest physical address
* space. * space.
...@@ -819,10 +764,9 @@ int __kvm_set_memory_region(struct kvm *kvm, ...@@ -819,10 +764,9 @@ int __kvm_set_memory_region(struct kvm *kvm,
new.rmap = vzalloc(npages * sizeof(*new.rmap)); new.rmap = vzalloc(npages * sizeof(*new.rmap));
if (!new.rmap) if (!new.rmap)
goto out_free; goto out_free;
if (create_lpage_info(&new, npages))
goto out_free;
#endif /* not defined CONFIG_S390 */ #endif /* not defined CONFIG_S390 */
if (kvm_arch_create_memslot(&new, npages))
goto out_free;
} }
/* Allocate page dirty bitmap if needed */ /* Allocate page dirty bitmap if needed */
...@@ -880,8 +824,7 @@ int __kvm_set_memory_region(struct kvm *kvm, ...@@ -880,8 +824,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
if (!npages) { if (!npages) {
new.rmap = NULL; new.rmap = NULL;
new.dirty_bitmap = NULL; new.dirty_bitmap = NULL;
for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) memset(&new.arch, 0, sizeof(new.arch));
new.lpage_info[i] = NULL;
} }
update_memslots(slots, &new); update_memslots(slots, &new);
...@@ -968,6 +911,11 @@ int kvm_get_dirty_log(struct kvm *kvm, ...@@ -968,6 +911,11 @@ int kvm_get_dirty_log(struct kvm *kvm,
return r; return r;
} }
bool kvm_largepages_enabled(void)
{
return largepages_enabled;
}
void kvm_disable_largepages(void) void kvm_disable_largepages(void)
{ {
largepages_enabled = false; largepages_enabled = false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment