Commit f98a8bf9 authored by David Gibson's avatar David Gibson Committed by Paul Mackerras

KVM: PPC: Book3S HV: Allow KVM_PPC_ALLOCATE_HTAB ioctl() to change HPT size

The KVM_PPC_ALLOCATE_HTAB ioctl() is used to set the size of hashed page
table (HPT) that userspace expects a guest VM to have, and is also used to
clear that HPT when necessary (e.g. guest reboot).

At present, once the ioctl() is called for the first time, the HPT size can
never be changed thereafter - it will be cleared but always sized as from
the first call.

With upcoming HPT resize implementation, we're going to need to allow
userspace to resize the HPT at reset (to change it back to the default size
if the guest changed it).

So, we need to allow this ioctl() to change the HPT size.

This patch also updates Documentation/virtual/kvm/api.txt to reflect
the new behaviour.  In fact the documentation was already slightly
incorrect since 572abd56 "KVM: PPC: Book3S HV: Don't fall back to
smaller HPT size in allocation ioctl"
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
parent aae0777f
...@@ -2443,18 +2443,20 @@ are, it will do nothing and return an EBUSY error. ...@@ -2443,18 +2443,20 @@ are, it will do nothing and return an EBUSY error.
The parameter is a pointer to a 32-bit unsigned integer variable The parameter is a pointer to a 32-bit unsigned integer variable
containing the order (log base 2) of the desired size of the hash containing the order (log base 2) of the desired size of the hash
table, which must be between 18 and 46. On successful return from the table, which must be between 18 and 46. On successful return from the
ioctl, it will have been updated with the order of the hash table that ioctl, the value will not be changed by the kernel.
was allocated.
If no hash table has been allocated when any vcpu is asked to run If no hash table has been allocated when any vcpu is asked to run
(with the KVM_RUN ioctl), the host kernel will allocate a (with the KVM_RUN ioctl), the host kernel will allocate a
default-sized hash table (16 MB). default-sized hash table (16 MB).
If this ioctl is called when a hash table has already been allocated, If this ioctl is called when a hash table has already been allocated,
the kernel will clear out the existing hash table (zero all HPTEs) and with a different order from the existing hash table, the existing hash
return the hash table order in the parameter. (If the guest is using table will be freed and a new one allocated. If this is ioctl is
the virtualized real-mode area (VRMA) facility, the kernel will called when a hash table has already been allocated of the same order
re-create the VMRA HPTEs on the next KVM_RUN of any vcpu.) as specified, the kernel will clear out the existing hash table (zero
all HPTEs). In either case, if the guest is using the virtualized
real-mode area (VRMA) facility, the kernel will re-create the VMRA
HPTEs on the next KVM_RUN of any vcpu.
4.77 KVM_S390_INTERRUPT 4.77 KVM_S390_INTERRUPT
......
...@@ -157,7 +157,7 @@ extern void kvmppc_map_magic(struct kvm_vcpu *vcpu); ...@@ -157,7 +157,7 @@ extern void kvmppc_map_magic(struct kvm_vcpu *vcpu);
extern int kvmppc_allocate_hpt(struct kvm_hpt_info *info, u32 order); extern int kvmppc_allocate_hpt(struct kvm_hpt_info *info, u32 order);
extern void kvmppc_set_hpt(struct kvm *kvm, struct kvm_hpt_info *info); extern void kvmppc_set_hpt(struct kvm *kvm, struct kvm_hpt_info *info);
extern long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp); extern long kvmppc_alloc_reset_hpt(struct kvm *kvm, int order);
extern void kvmppc_free_hpt(struct kvm_hpt_info *info); extern void kvmppc_free_hpt(struct kvm_hpt_info *info);
extern long kvmppc_prepare_vrma(struct kvm *kvm, extern long kvmppc_prepare_vrma(struct kvm *kvm,
struct kvm_userspace_memory_region *mem); struct kvm_userspace_memory_region *mem);
......
...@@ -102,10 +102,10 @@ void kvmppc_set_hpt(struct kvm *kvm, struct kvm_hpt_info *info) ...@@ -102,10 +102,10 @@ void kvmppc_set_hpt(struct kvm *kvm, struct kvm_hpt_info *info)
info->virt, (long)info->order, kvm->arch.lpid); info->virt, (long)info->order, kvm->arch.lpid);
} }
long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp) long kvmppc_alloc_reset_hpt(struct kvm *kvm, int order)
{ {
long err = -EBUSY; long err = -EBUSY;
long order; struct kvm_hpt_info info;
if (kvm_is_radix(kvm)) if (kvm_is_radix(kvm))
return -EINVAL; return -EINVAL;
...@@ -120,8 +120,9 @@ long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp) ...@@ -120,8 +120,9 @@ long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp)
goto out; goto out;
} }
} }
if (kvm->arch.hpt.virt) { if (kvm->arch.hpt.order == order) {
order = kvm->arch.hpt.order; /* We already have a suitable HPT */
/* Set the entire HPT to 0, i.e. invalid HPTEs */ /* Set the entire HPT to 0, i.e. invalid HPTEs */
memset((void *)kvm->arch.hpt.virt, 0, 1ul << order); memset((void *)kvm->arch.hpt.virt, 0, 1ul << order);
/* /*
...@@ -130,17 +131,19 @@ long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp) ...@@ -130,17 +131,19 @@ long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp)
kvmppc_rmap_reset(kvm); kvmppc_rmap_reset(kvm);
/* Ensure that each vcpu will flush its TLB on next entry. */ /* Ensure that each vcpu will flush its TLB on next entry. */
cpumask_setall(&kvm->arch.need_tlb_flush); cpumask_setall(&kvm->arch.need_tlb_flush);
*htab_orderp = order;
err = 0; err = 0;
} else { goto out;
struct kvm_hpt_info info;
err = kvmppc_allocate_hpt(&info, *htab_orderp);
if (err < 0)
goto out;
kvmppc_set_hpt(kvm, &info);
} }
out:
if (kvm->arch.hpt.virt)
kvmppc_free_hpt(&kvm->arch.hpt);
err = kvmppc_allocate_hpt(&info, order);
if (err < 0)
goto out;
kvmppc_set_hpt(kvm, &info);
out:
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->lock);
return err; return err;
} }
......
...@@ -3704,12 +3704,9 @@ static long kvm_arch_vm_ioctl_hv(struct file *filp, ...@@ -3704,12 +3704,9 @@ static long kvm_arch_vm_ioctl_hv(struct file *filp,
r = -EFAULT; r = -EFAULT;
if (get_user(htab_order, (u32 __user *)argp)) if (get_user(htab_order, (u32 __user *)argp))
break; break;
r = kvmppc_alloc_reset_hpt(kvm, &htab_order); r = kvmppc_alloc_reset_hpt(kvm, htab_order);
if (r) if (r)
break; break;
r = -EFAULT;
if (put_user(htab_order, (u32 __user *)argp))
break;
r = 0; r = 0;
break; break;
} }
......
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