qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] hw/ppc/spapr: Check for valid page size when ho


From: David Gibson
Subject: Re: [Qemu-devel] [PATCH] hw/ppc/spapr: Check for valid page size when hot plugging memory
Date: Thu, 16 Feb 2017 13:28:24 +1100
User-agent: Mutt/1.7.1 (2016-10-04)

On Wed, Feb 15, 2017 at 10:21:44AM +0100, Thomas Huth wrote:
> On POWER, the valid page sizes that the guest can use are bound
> to the CPU and not to the memory region. QEMU already has some
> fancy logic to find out the right maximum memory size to tell
> it to the guest during boot (see getrampagesize() in the file
> target/ppc/kvm.c for more information).
> However, once we're booted and the guest is using huge pages
> already, it is currently still possible to hot-plug memory regions
> that does not support huge pages - which of course does not work
> on POWER, since the guest thinks that it is possible to use huge
> pages everywhere. The KVM_RUN ioctl will then abort with -EFAULT,
> QEMU spills out a not very helpful error message together with
> a register dump and the user is annoyed that the VM unexpectedly
> died.
> To avoid this situation, we should check the page size of hot-plugged
> DIMMs to see whether it is possible to use it in the current VM.
> If it does not fit, we can print out a better error message and
> refuse to add it, so that the VM does not die unexpectely and the
> user has a second chance to plug a DIMM with a matching memory
> backend instead.
> 
> Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1419466
> Signed-off-by: Thomas Huth <address@hidden>

Using the global is a bit yucky, but I can't see an easy way to remove
it, and it's not like there aren't already some ugly globals in the
KVM code.  In the meantime this fixes a real bug, so I've merged this
to ppc-for-2.9.

Thanks.

> ---
>  hw/ppc/spapr.c       |  8 ++++++++
>  target/ppc/kvm.c     | 32 ++++++++++++++++++++++++++++----
>  target/ppc/kvm_ppc.h |  7 +++++++
>  3 files changed, 43 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index e465d7a..1a90aae 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -2357,6 +2357,7 @@ static void spapr_memory_plug(HotplugHandler 
> *hotplug_dev, DeviceState *dev,
>      uint64_t align = memory_region_get_alignment(mr);
>      uint64_t size = memory_region_size(mr);
>      uint64_t addr;
> +    char *mem_dev;
>  
>      if (size % SPAPR_MEMORY_BLOCK_SIZE) {
>          error_setg(&local_err, "Hotplugged memory size must be a multiple of 
> "
> @@ -2364,6 +2365,13 @@ static void spapr_memory_plug(HotplugHandler 
> *hotplug_dev, DeviceState *dev,
>          goto out;
>      }
>  
> +    mem_dev = object_property_get_str(OBJECT(dimm), PC_DIMM_MEMDEV_PROP, 
> NULL);
> +    if (mem_dev && !kvmppc_is_mem_backend_page_size_ok(mem_dev)) {
> +        error_setg(&local_err, "Memory backend has bad page size. "
> +                   "Use 'memory-backend-file' with correct mem-path.");
> +        goto out;
> +    }
> +
>      pc_dimm_memory_plug(dev, &ms->hotplug_memory, mr, align, &local_err);
>      if (local_err) {
>          goto out;
> diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> index 663d2e7..584546b 100644
> --- a/target/ppc/kvm.c
> +++ b/target/ppc/kvm.c
> @@ -438,12 +438,13 @@ static bool kvm_valid_page_size(uint32_t flags, long 
> rampgsize, uint32_t shift)
>      return (1ul << shift) <= rampgsize;
>  }
>  
> +static long max_cpu_page_size;
> +
>  static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
>  {
>      static struct kvm_ppc_smmu_info smmu_info;
>      static bool has_smmu_info;
>      CPUPPCState *env = &cpu->env;
> -    long rampagesize;
>      int iq, ik, jq, jk;
>      bool has_64k_pages = false;
>  
> @@ -458,7 +459,9 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
>          has_smmu_info = true;
>      }
>  
> -    rampagesize = getrampagesize();
> +    if (!max_cpu_page_size) {
> +        max_cpu_page_size = getrampagesize();
> +    }
>  
>      /* Convert to QEMU form */
>      memset(&env->sps, 0, sizeof(env->sps));
> @@ -478,14 +481,14 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
>          struct ppc_one_seg_page_size *qsps = &env->sps.sps[iq];
>          struct kvm_ppc_one_seg_page_size *ksps = &smmu_info.sps[ik];
>  
> -        if (!kvm_valid_page_size(smmu_info.flags, rampagesize,
> +        if (!kvm_valid_page_size(smmu_info.flags, max_cpu_page_size,
>                                   ksps->page_shift)) {
>              continue;
>          }
>          qsps->page_shift = ksps->page_shift;
>          qsps->slb_enc = ksps->slb_enc;
>          for (jk = jq = 0; jk < KVM_PPC_PAGE_SIZES_MAX_SZ; jk++) {
> -            if (!kvm_valid_page_size(smmu_info.flags, rampagesize,
> +            if (!kvm_valid_page_size(smmu_info.flags, max_cpu_page_size,
>                                       ksps->enc[jk].page_shift)) {
>                  continue;
>              }
> @@ -510,12 +513,33 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
>          env->mmu_model &= ~POWERPC_MMU_64K;
>      }
>  }
> +
> +bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
> +{
> +    Object *mem_obj = object_resolve_path(obj_path, NULL);
> +    char *mempath = object_property_get_str(mem_obj, "mem-path", NULL);
> +    long pagesize;
> +
> +    if (mempath) {
> +        pagesize = gethugepagesize(mempath);
> +    } else {
> +        pagesize = getpagesize();
> +    }
> +
> +    return pagesize >= max_cpu_page_size;
> +}
> +
>  #else /* defined (TARGET_PPC64) */
>  
>  static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu)
>  {
>  }
>  
> +int kvmppc_is_mem_backend_page_size_ok(char *obj_path)
> +{
> +    return true;
> +}
> +
>  #endif /* !defined (TARGET_PPC64) */
>  
>  unsigned long kvm_arch_vcpu_id(CPUState *cpu)
> diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> index 151c00b..8da2ee4 100644
> --- a/target/ppc/kvm_ppc.h
> +++ b/target/ppc/kvm_ppc.h
> @@ -60,6 +60,8 @@ int kvmppc_enable_hwrng(void);
>  int kvmppc_put_books_sregs(PowerPCCPU *cpu);
>  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
>  
> +bool kvmppc_is_mem_backend_page_size_ok(char *obj_path);
> +
>  #else
>  
>  static inline uint32_t kvmppc_get_tbfreq(void)
> @@ -192,6 +194,11 @@ static inline uint64_t kvmppc_rma_size(uint64_t 
> current_size,
>      return ram_size;
>  }
>  
> +static inline bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
> +{
> +    return true;
> +}
> +
>  #endif /* !CONFIG_USER_ONLY */
>  
>  static inline bool kvmppc_has_cap_epr(void)

-- 
David Gibson                    | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist, thank you.  NOT _the_ _other_
                                | _way_ _around_!
http://www.ozlabs.org/~dgibson

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]