From: Sean Christopherson <sean.j.christopherson@intel.com>
To: Peter Xu <peterx@redhat.com>
Cc: "Paolo Bonzini" <pbonzini@redhat.com>,
"Paul Mackerras" <paulus@ozlabs.org>,
"Christian Borntraeger" <borntraeger@de.ibm.com>,
"Janosch Frank" <frankja@linux.ibm.com>,
"David Hildenbrand" <david@redhat.com>,
"Cornelia Huck" <cohuck@redhat.com>,
"Vitaly Kuznetsov" <vkuznets@redhat.com>,
"Wanpeng Li" <wanpengli@tencent.com>,
"Jim Mattson" <jmattson@google.com>,
"Joerg Roedel" <joro@8bytes.org>, "Marc Zyngier" <maz@kernel.org>,
"James Morse" <james.morse@arm.com>,
"Julien Thierry" <julien.thierry.kdev@gmail.com>,
"Suzuki K Poulose" <suzuki.poulose@arm.com>,
linux-mips@vger.kernel.org, kvm@vger.kernel.org,
kvm-ppc@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
kvmarm@lists.cs.columbia.edu, linux-kernel@vger.kernel.org,
"Christoffer Dall" <christoffer.dall@arm.com>,
"Philippe Mathieu-Daudé" <f4bug@amsat.org>
Subject: Re: [PATCH v5 18/19] KVM: Dynamically size memslot array based on number of used slots
Date: Fri, 07 Feb 2020 15:38:29 +0000 [thread overview]
Message-ID: <20200207153829.GA2401@linux.intel.com> (raw)
In-Reply-To: <20200206221208.GI700495@xz-x1>
On Thu, Feb 06, 2020 at 05:12:08PM -0500, Peter Xu wrote:
> On Tue, Jan 21, 2020 at 02:31:56PM -0800, Sean Christopherson wrote:
> > Now that the memslot logic doesn't assume memslots are always non-NULL,
> > dynamically size the array of memslots instead of unconditionally
> > allocating memory for the maximum number of memslots.
> >
> > Note, because a to-be-deleted memslot must first be invalidated, the
> > array size cannot be immediately reduced when deleting a memslot.
> > However, consecutive deletions will realize the memory savings, i.e.
> > a second deletion will trim the entry.
> >
> > Tested-by: Christoffer Dall <christoffer.dall@arm.com>
> > Tested-by: Marc Zyngier <maz@kernel.org>
> > Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
> > ---
> > include/linux/kvm_host.h | 2 +-
> > virt/kvm/kvm_main.c | 31 ++++++++++++++++++++++++++++---
> > 2 files changed, 29 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> > index 60ddfdb69378..8bb6fb127387 100644
> > --- a/include/linux/kvm_host.h
> > +++ b/include/linux/kvm_host.h
> > @@ -431,11 +431,11 @@ static inline int kvm_arch_vcpu_memslots_id(struct kvm_vcpu *vcpu)
> > */
> > struct kvm_memslots {
> > u64 generation;
> > - struct kvm_memory_slot memslots[KVM_MEM_SLOTS_NUM];
> > /* The mapping table from slot id to the index in memslots[]. */
> > short id_to_index[KVM_MEM_SLOTS_NUM];
> > atomic_t lru_slot;
> > int used_slots;
> > + struct kvm_memory_slot memslots[];
>
> This patch is tested so I believe this works, however normally I need
> to do similar thing with [0] otherwise gcc might complaint. Is there
> any trick behind to make this work? Or is that because of different
> gcc versions?
array[] and array[0] have the same net affect, but array[] is given special
treatment by gcc to provide extra sanity checks, e.g. requires the field to
be the end of the struct. Last I checked, gcc also doesn't allow array[]
in unions. There are probably other restrictions.
But, it's precisely because of those restrictions that using array[] is
preferred, as it provides extra protections, e.g. if someone moved memslots
to the top of the struct it would fail to compile.
> > };
> >
> > struct kvm {
> > diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> > index 9b614cf2ca20..ed392ce64e59 100644
> > --- a/virt/kvm/kvm_main.c
> > +++ b/virt/kvm/kvm_main.c
> > @@ -565,7 +565,7 @@ static struct kvm_memslots *kvm_alloc_memslots(void)
> > return NULL;
> >
> > for (i = 0; i < KVM_MEM_SLOTS_NUM; i++)
> > - slots->id_to_index[i] = slots->memslots[i].id = -1;
> > + slots->id_to_index[i] = -1;
> >
> > return slots;
> > }
> > @@ -1077,6 +1077,32 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
> > return old_memslots;
> > }
> >
> > +/*
> > + * Note, at a minimum, the current number of used slots must be allocated, even
> > + * when deleting a memslot, as we need a complete duplicate of the memslots for
> > + * use when invalidating a memslot prior to deleting/moving the memslot.
> > + */
> > +static struct kvm_memslots *kvm_dup_memslots(struct kvm_memslots *old,
> > + enum kvm_mr_change change)
> > +{
> > + struct kvm_memslots *slots;
> > + size_t old_size, new_size;
> > +
> > + old_size = sizeof(struct kvm_memslots) +
> > + (sizeof(struct kvm_memory_slot) * old->used_slots);
> > +
> > + if (change = KVM_MR_CREATE)
> > + new_size = old_size + sizeof(struct kvm_memory_slot);
> > + else
> > + new_size = old_size;
> > +
> > + slots = kvzalloc(new_size, GFP_KERNEL_ACCOUNT);
> > + if (likely(slots))
> > + memcpy(slots, old, old_size);
>
> (Maybe directly copy into it?)
I don't follow, are you saying do "*slots = *old"?
@new_size and @old_size are not guaranteed to be the same. More
specifically, slots->memslots and old->slots are now flexible arrays with
potentially different sizes. Doing "*slots = *old" would only copy the
standard members, a memcpy() would still be needed for @memlots.
A more effecient implementation would be:
slots = kvalloc(new_size, GFP_KERNEL_ACCOUNT);
if (likely(slots)) {
memcpy(slots, old, old_size);
if (change = KVM_MR_CREATE)
memset((void *)slots + old_size, 0, new_size - old_size);
}
to avoid unnecessarily zeroing out the entire thing. I opted for the
simpler implementation as this is not performance critical code, for most
cases @slots won't be all that large, and I wanted to be absolutely sure
any mixup would hit zeroed memory and not uninitialized memory.
>
> > +
> > + return slots;
> > +}
> > +
> > static int kvm_set_memslot(struct kvm *kvm,
> > const struct kvm_userspace_memory_region *mem,
> > struct kvm_memory_slot *old,
> > @@ -1087,10 +1113,9 @@ static int kvm_set_memslot(struct kvm *kvm,
> > struct kvm_memslots *slots;
> > int r;
> >
> > - slots = kvzalloc(sizeof(struct kvm_memslots), GFP_KERNEL_ACCOUNT);
> > + slots = kvm_dup_memslots(__kvm_memslots(kvm, as_id), change);
> > if (!slots)
> > return -ENOMEM;
> > - memcpy(slots, __kvm_memslots(kvm, as_id), sizeof(struct kvm_memslots));
> >
> > if (change = KVM_MR_DELETE || change = KVM_MR_MOVE) {
> > /*
> > --
> > 2.24.1
> >
>
> --
> Peter Xu
>
WARNING: multiple messages have this Message-ID (diff)
From: Sean Christopherson <sean.j.christopherson@intel.com>
To: Peter Xu <peterx@redhat.com>
Cc: "Wanpeng Li" <wanpengli@tencent.com>,
kvm@vger.kernel.org, "David Hildenbrand" <david@redhat.com>,
linux-mips@vger.kernel.org, "Paul Mackerras" <paulus@ozlabs.org>,
kvmarm@lists.cs.columbia.edu,
"Janosch Frank" <frankja@linux.ibm.com>,
"Marc Zyngier" <maz@kernel.org>, "Joerg Roedel" <joro@8bytes.org>,
"Christian Borntraeger" <borntraeger@de.ibm.com>,
kvm-ppc@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
"Jim Mattson" <jmattson@google.com>,
"Cornelia Huck" <cohuck@redhat.com>,
linux-kernel@vger.kernel.org,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Vitaly Kuznetsov" <vkuznets@redhat.com>,
"Philippe Mathieu-Daudé" <f4bug@amsat.org>
Subject: Re: [PATCH v5 18/19] KVM: Dynamically size memslot array based on number of used slots
Date: Fri, 7 Feb 2020 07:38:29 -0800 [thread overview]
Message-ID: <20200207153829.GA2401@linux.intel.com> (raw)
In-Reply-To: <20200206221208.GI700495@xz-x1>
On Thu, Feb 06, 2020 at 05:12:08PM -0500, Peter Xu wrote:
> On Tue, Jan 21, 2020 at 02:31:56PM -0800, Sean Christopherson wrote:
> > Now that the memslot logic doesn't assume memslots are always non-NULL,
> > dynamically size the array of memslots instead of unconditionally
> > allocating memory for the maximum number of memslots.
> >
> > Note, because a to-be-deleted memslot must first be invalidated, the
> > array size cannot be immediately reduced when deleting a memslot.
> > However, consecutive deletions will realize the memory savings, i.e.
> > a second deletion will trim the entry.
> >
> > Tested-by: Christoffer Dall <christoffer.dall@arm.com>
> > Tested-by: Marc Zyngier <maz@kernel.org>
> > Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
> > ---
> > include/linux/kvm_host.h | 2 +-
> > virt/kvm/kvm_main.c | 31 ++++++++++++++++++++++++++++---
> > 2 files changed, 29 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> > index 60ddfdb69378..8bb6fb127387 100644
> > --- a/include/linux/kvm_host.h
> > +++ b/include/linux/kvm_host.h
> > @@ -431,11 +431,11 @@ static inline int kvm_arch_vcpu_memslots_id(struct kvm_vcpu *vcpu)
> > */
> > struct kvm_memslots {
> > u64 generation;
> > - struct kvm_memory_slot memslots[KVM_MEM_SLOTS_NUM];
> > /* The mapping table from slot id to the index in memslots[]. */
> > short id_to_index[KVM_MEM_SLOTS_NUM];
> > atomic_t lru_slot;
> > int used_slots;
> > + struct kvm_memory_slot memslots[];
>
> This patch is tested so I believe this works, however normally I need
> to do similar thing with [0] otherwise gcc might complaint. Is there
> any trick behind to make this work? Or is that because of different
> gcc versions?
array[] and array[0] have the same net affect, but array[] is given special
treatment by gcc to provide extra sanity checks, e.g. requires the field to
be the end of the struct. Last I checked, gcc also doesn't allow array[]
in unions. There are probably other restrictions.
But, it's precisely because of those restrictions that using array[] is
preferred, as it provides extra protections, e.g. if someone moved memslots
to the top of the struct it would fail to compile.
> > };
> >
> > struct kvm {
> > diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> > index 9b614cf2ca20..ed392ce64e59 100644
> > --- a/virt/kvm/kvm_main.c
> > +++ b/virt/kvm/kvm_main.c
> > @@ -565,7 +565,7 @@ static struct kvm_memslots *kvm_alloc_memslots(void)
> > return NULL;
> >
> > for (i = 0; i < KVM_MEM_SLOTS_NUM; i++)
> > - slots->id_to_index[i] = slots->memslots[i].id = -1;
> > + slots->id_to_index[i] = -1;
> >
> > return slots;
> > }
> > @@ -1077,6 +1077,32 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
> > return old_memslots;
> > }
> >
> > +/*
> > + * Note, at a minimum, the current number of used slots must be allocated, even
> > + * when deleting a memslot, as we need a complete duplicate of the memslots for
> > + * use when invalidating a memslot prior to deleting/moving the memslot.
> > + */
> > +static struct kvm_memslots *kvm_dup_memslots(struct kvm_memslots *old,
> > + enum kvm_mr_change change)
> > +{
> > + struct kvm_memslots *slots;
> > + size_t old_size, new_size;
> > +
> > + old_size = sizeof(struct kvm_memslots) +
> > + (sizeof(struct kvm_memory_slot) * old->used_slots);
> > +
> > + if (change == KVM_MR_CREATE)
> > + new_size = old_size + sizeof(struct kvm_memory_slot);
> > + else
> > + new_size = old_size;
> > +
> > + slots = kvzalloc(new_size, GFP_KERNEL_ACCOUNT);
> > + if (likely(slots))
> > + memcpy(slots, old, old_size);
>
> (Maybe directly copy into it?)
I don't follow, are you saying do "*slots = *old"?
@new_size and @old_size are not guaranteed to be the same. More
specifically, slots->memslots and old->slots are now flexible arrays with
potentially different sizes. Doing "*slots = *old" would only copy the
standard members, a memcpy() would still be needed for @memlots.
A more effecient implementation would be:
slots = kvalloc(new_size, GFP_KERNEL_ACCOUNT);
if (likely(slots)) {
memcpy(slots, old, old_size);
if (change == KVM_MR_CREATE)
memset((void *)slots + old_size, 0, new_size - old_size);
}
to avoid unnecessarily zeroing out the entire thing. I opted for the
simpler implementation as this is not performance critical code, for most
cases @slots won't be all that large, and I wanted to be absolutely sure
any mixup would hit zeroed memory and not uninitialized memory.
>
> > +
> > + return slots;
> > +}
> > +
> > static int kvm_set_memslot(struct kvm *kvm,
> > const struct kvm_userspace_memory_region *mem,
> > struct kvm_memory_slot *old,
> > @@ -1087,10 +1113,9 @@ static int kvm_set_memslot(struct kvm *kvm,
> > struct kvm_memslots *slots;
> > int r;
> >
> > - slots = kvzalloc(sizeof(struct kvm_memslots), GFP_KERNEL_ACCOUNT);
> > + slots = kvm_dup_memslots(__kvm_memslots(kvm, as_id), change);
> > if (!slots)
> > return -ENOMEM;
> > - memcpy(slots, __kvm_memslots(kvm, as_id), sizeof(struct kvm_memslots));
> >
> > if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
> > /*
> > --
> > 2.24.1
> >
>
> --
> Peter Xu
>
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
WARNING: multiple messages have this Message-ID (diff)
From: Sean Christopherson <sean.j.christopherson@intel.com>
To: Peter Xu <peterx@redhat.com>
Cc: "Paolo Bonzini" <pbonzini@redhat.com>,
"Paul Mackerras" <paulus@ozlabs.org>,
"Christian Borntraeger" <borntraeger@de.ibm.com>,
"Janosch Frank" <frankja@linux.ibm.com>,
"David Hildenbrand" <david@redhat.com>,
"Cornelia Huck" <cohuck@redhat.com>,
"Vitaly Kuznetsov" <vkuznets@redhat.com>,
"Wanpeng Li" <wanpengli@tencent.com>,
"Jim Mattson" <jmattson@google.com>,
"Joerg Roedel" <joro@8bytes.org>, "Marc Zyngier" <maz@kernel.org>,
"James Morse" <james.morse@arm.com>,
"Julien Thierry" <julien.thierry.kdev@gmail.com>,
"Suzuki K Poulose" <suzuki.poulose@arm.com>,
linux-mips@vger.kernel.org, kvm@vger.kernel.org,
kvm-ppc@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
kvmarm@lists.cs.columbia.edu, linux-kernel@vger.kernel.org,
"Christoffer Dall" <christoffer.dall@arm.com>,
"Philippe Mathieu-Daudé" <f4bug@amsat.org>
Subject: Re: [PATCH v5 18/19] KVM: Dynamically size memslot array based on number of used slots
Date: Fri, 7 Feb 2020 07:38:29 -0800 [thread overview]
Message-ID: <20200207153829.GA2401@linux.intel.com> (raw)
In-Reply-To: <20200206221208.GI700495@xz-x1>
On Thu, Feb 06, 2020 at 05:12:08PM -0500, Peter Xu wrote:
> On Tue, Jan 21, 2020 at 02:31:56PM -0800, Sean Christopherson wrote:
> > Now that the memslot logic doesn't assume memslots are always non-NULL,
> > dynamically size the array of memslots instead of unconditionally
> > allocating memory for the maximum number of memslots.
> >
> > Note, because a to-be-deleted memslot must first be invalidated, the
> > array size cannot be immediately reduced when deleting a memslot.
> > However, consecutive deletions will realize the memory savings, i.e.
> > a second deletion will trim the entry.
> >
> > Tested-by: Christoffer Dall <christoffer.dall@arm.com>
> > Tested-by: Marc Zyngier <maz@kernel.org>
> > Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
> > ---
> > include/linux/kvm_host.h | 2 +-
> > virt/kvm/kvm_main.c | 31 ++++++++++++++++++++++++++++---
> > 2 files changed, 29 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> > index 60ddfdb69378..8bb6fb127387 100644
> > --- a/include/linux/kvm_host.h
> > +++ b/include/linux/kvm_host.h
> > @@ -431,11 +431,11 @@ static inline int kvm_arch_vcpu_memslots_id(struct kvm_vcpu *vcpu)
> > */
> > struct kvm_memslots {
> > u64 generation;
> > - struct kvm_memory_slot memslots[KVM_MEM_SLOTS_NUM];
> > /* The mapping table from slot id to the index in memslots[]. */
> > short id_to_index[KVM_MEM_SLOTS_NUM];
> > atomic_t lru_slot;
> > int used_slots;
> > + struct kvm_memory_slot memslots[];
>
> This patch is tested so I believe this works, however normally I need
> to do similar thing with [0] otherwise gcc might complaint. Is there
> any trick behind to make this work? Or is that because of different
> gcc versions?
array[] and array[0] have the same net affect, but array[] is given special
treatment by gcc to provide extra sanity checks, e.g. requires the field to
be the end of the struct. Last I checked, gcc also doesn't allow array[]
in unions. There are probably other restrictions.
But, it's precisely because of those restrictions that using array[] is
preferred, as it provides extra protections, e.g. if someone moved memslots
to the top of the struct it would fail to compile.
> > };
> >
> > struct kvm {
> > diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> > index 9b614cf2ca20..ed392ce64e59 100644
> > --- a/virt/kvm/kvm_main.c
> > +++ b/virt/kvm/kvm_main.c
> > @@ -565,7 +565,7 @@ static struct kvm_memslots *kvm_alloc_memslots(void)
> > return NULL;
> >
> > for (i = 0; i < KVM_MEM_SLOTS_NUM; i++)
> > - slots->id_to_index[i] = slots->memslots[i].id = -1;
> > + slots->id_to_index[i] = -1;
> >
> > return slots;
> > }
> > @@ -1077,6 +1077,32 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
> > return old_memslots;
> > }
> >
> > +/*
> > + * Note, at a minimum, the current number of used slots must be allocated, even
> > + * when deleting a memslot, as we need a complete duplicate of the memslots for
> > + * use when invalidating a memslot prior to deleting/moving the memslot.
> > + */
> > +static struct kvm_memslots *kvm_dup_memslots(struct kvm_memslots *old,
> > + enum kvm_mr_change change)
> > +{
> > + struct kvm_memslots *slots;
> > + size_t old_size, new_size;
> > +
> > + old_size = sizeof(struct kvm_memslots) +
> > + (sizeof(struct kvm_memory_slot) * old->used_slots);
> > +
> > + if (change == KVM_MR_CREATE)
> > + new_size = old_size + sizeof(struct kvm_memory_slot);
> > + else
> > + new_size = old_size;
> > +
> > + slots = kvzalloc(new_size, GFP_KERNEL_ACCOUNT);
> > + if (likely(slots))
> > + memcpy(slots, old, old_size);
>
> (Maybe directly copy into it?)
I don't follow, are you saying do "*slots = *old"?
@new_size and @old_size are not guaranteed to be the same. More
specifically, slots->memslots and old->slots are now flexible arrays with
potentially different sizes. Doing "*slots = *old" would only copy the
standard members, a memcpy() would still be needed for @memlots.
A more effecient implementation would be:
slots = kvalloc(new_size, GFP_KERNEL_ACCOUNT);
if (likely(slots)) {
memcpy(slots, old, old_size);
if (change == KVM_MR_CREATE)
memset((void *)slots + old_size, 0, new_size - old_size);
}
to avoid unnecessarily zeroing out the entire thing. I opted for the
simpler implementation as this is not performance critical code, for most
cases @slots won't be all that large, and I wanted to be absolutely sure
any mixup would hit zeroed memory and not uninitialized memory.
>
> > +
> > + return slots;
> > +}
> > +
> > static int kvm_set_memslot(struct kvm *kvm,
> > const struct kvm_userspace_memory_region *mem,
> > struct kvm_memory_slot *old,
> > @@ -1087,10 +1113,9 @@ static int kvm_set_memslot(struct kvm *kvm,
> > struct kvm_memslots *slots;
> > int r;
> >
> > - slots = kvzalloc(sizeof(struct kvm_memslots), GFP_KERNEL_ACCOUNT);
> > + slots = kvm_dup_memslots(__kvm_memslots(kvm, as_id), change);
> > if (!slots)
> > return -ENOMEM;
> > - memcpy(slots, __kvm_memslots(kvm, as_id), sizeof(struct kvm_memslots));
> >
> > if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
> > /*
> > --
> > 2.24.1
> >
>
> --
> Peter Xu
>
WARNING: multiple messages have this Message-ID (diff)
From: Sean Christopherson <sean.j.christopherson@intel.com>
To: Peter Xu <peterx@redhat.com>
Cc: "Wanpeng Li" <wanpengli@tencent.com>,
kvm@vger.kernel.org, "David Hildenbrand" <david@redhat.com>,
linux-mips@vger.kernel.org, "Paul Mackerras" <paulus@ozlabs.org>,
kvmarm@lists.cs.columbia.edu,
"Janosch Frank" <frankja@linux.ibm.com>,
"Marc Zyngier" <maz@kernel.org>, "Joerg Roedel" <joro@8bytes.org>,
"Christian Borntraeger" <borntraeger@de.ibm.com>,
"Julien Thierry" <julien.thierry.kdev@gmail.com>,
"Suzuki K Poulose" <suzuki.poulose@arm.com>,
kvm-ppc@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
"Jim Mattson" <jmattson@google.com>,
"Cornelia Huck" <cohuck@redhat.com>,
"Christoffer Dall" <christoffer.dall@arm.com>,
linux-kernel@vger.kernel.org, "James Morse" <james.morse@arm.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Vitaly Kuznetsov" <vkuznets@redhat.com>,
"Philippe Mathieu-Daudé" <f4bug@amsat.org>
Subject: Re: [PATCH v5 18/19] KVM: Dynamically size memslot array based on number of used slots
Date: Fri, 7 Feb 2020 07:38:29 -0800 [thread overview]
Message-ID: <20200207153829.GA2401@linux.intel.com> (raw)
In-Reply-To: <20200206221208.GI700495@xz-x1>
On Thu, Feb 06, 2020 at 05:12:08PM -0500, Peter Xu wrote:
> On Tue, Jan 21, 2020 at 02:31:56PM -0800, Sean Christopherson wrote:
> > Now that the memslot logic doesn't assume memslots are always non-NULL,
> > dynamically size the array of memslots instead of unconditionally
> > allocating memory for the maximum number of memslots.
> >
> > Note, because a to-be-deleted memslot must first be invalidated, the
> > array size cannot be immediately reduced when deleting a memslot.
> > However, consecutive deletions will realize the memory savings, i.e.
> > a second deletion will trim the entry.
> >
> > Tested-by: Christoffer Dall <christoffer.dall@arm.com>
> > Tested-by: Marc Zyngier <maz@kernel.org>
> > Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
> > ---
> > include/linux/kvm_host.h | 2 +-
> > virt/kvm/kvm_main.c | 31 ++++++++++++++++++++++++++++---
> > 2 files changed, 29 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> > index 60ddfdb69378..8bb6fb127387 100644
> > --- a/include/linux/kvm_host.h
> > +++ b/include/linux/kvm_host.h
> > @@ -431,11 +431,11 @@ static inline int kvm_arch_vcpu_memslots_id(struct kvm_vcpu *vcpu)
> > */
> > struct kvm_memslots {
> > u64 generation;
> > - struct kvm_memory_slot memslots[KVM_MEM_SLOTS_NUM];
> > /* The mapping table from slot id to the index in memslots[]. */
> > short id_to_index[KVM_MEM_SLOTS_NUM];
> > atomic_t lru_slot;
> > int used_slots;
> > + struct kvm_memory_slot memslots[];
>
> This patch is tested so I believe this works, however normally I need
> to do similar thing with [0] otherwise gcc might complaint. Is there
> any trick behind to make this work? Or is that because of different
> gcc versions?
array[] and array[0] have the same net affect, but array[] is given special
treatment by gcc to provide extra sanity checks, e.g. requires the field to
be the end of the struct. Last I checked, gcc also doesn't allow array[]
in unions. There are probably other restrictions.
But, it's precisely because of those restrictions that using array[] is
preferred, as it provides extra protections, e.g. if someone moved memslots
to the top of the struct it would fail to compile.
> > };
> >
> > struct kvm {
> > diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> > index 9b614cf2ca20..ed392ce64e59 100644
> > --- a/virt/kvm/kvm_main.c
> > +++ b/virt/kvm/kvm_main.c
> > @@ -565,7 +565,7 @@ static struct kvm_memslots *kvm_alloc_memslots(void)
> > return NULL;
> >
> > for (i = 0; i < KVM_MEM_SLOTS_NUM; i++)
> > - slots->id_to_index[i] = slots->memslots[i].id = -1;
> > + slots->id_to_index[i] = -1;
> >
> > return slots;
> > }
> > @@ -1077,6 +1077,32 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
> > return old_memslots;
> > }
> >
> > +/*
> > + * Note, at a minimum, the current number of used slots must be allocated, even
> > + * when deleting a memslot, as we need a complete duplicate of the memslots for
> > + * use when invalidating a memslot prior to deleting/moving the memslot.
> > + */
> > +static struct kvm_memslots *kvm_dup_memslots(struct kvm_memslots *old,
> > + enum kvm_mr_change change)
> > +{
> > + struct kvm_memslots *slots;
> > + size_t old_size, new_size;
> > +
> > + old_size = sizeof(struct kvm_memslots) +
> > + (sizeof(struct kvm_memory_slot) * old->used_slots);
> > +
> > + if (change == KVM_MR_CREATE)
> > + new_size = old_size + sizeof(struct kvm_memory_slot);
> > + else
> > + new_size = old_size;
> > +
> > + slots = kvzalloc(new_size, GFP_KERNEL_ACCOUNT);
> > + if (likely(slots))
> > + memcpy(slots, old, old_size);
>
> (Maybe directly copy into it?)
I don't follow, are you saying do "*slots = *old"?
@new_size and @old_size are not guaranteed to be the same. More
specifically, slots->memslots and old->slots are now flexible arrays with
potentially different sizes. Doing "*slots = *old" would only copy the
standard members, a memcpy() would still be needed for @memlots.
A more effecient implementation would be:
slots = kvalloc(new_size, GFP_KERNEL_ACCOUNT);
if (likely(slots)) {
memcpy(slots, old, old_size);
if (change == KVM_MR_CREATE)
memset((void *)slots + old_size, 0, new_size - old_size);
}
to avoid unnecessarily zeroing out the entire thing. I opted for the
simpler implementation as this is not performance critical code, for most
cases @slots won't be all that large, and I wanted to be absolutely sure
any mixup would hit zeroed memory and not uninitialized memory.
>
> > +
> > + return slots;
> > +}
> > +
> > static int kvm_set_memslot(struct kvm *kvm,
> > const struct kvm_userspace_memory_region *mem,
> > struct kvm_memory_slot *old,
> > @@ -1087,10 +1113,9 @@ static int kvm_set_memslot(struct kvm *kvm,
> > struct kvm_memslots *slots;
> > int r;
> >
> > - slots = kvzalloc(sizeof(struct kvm_memslots), GFP_KERNEL_ACCOUNT);
> > + slots = kvm_dup_memslots(__kvm_memslots(kvm, as_id), change);
> > if (!slots)
> > return -ENOMEM;
> > - memcpy(slots, __kvm_memslots(kvm, as_id), sizeof(struct kvm_memslots));
> >
> > if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
> > /*
> > --
> > 2.24.1
> >
>
> --
> Peter Xu
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2020-02-07 15:38 UTC|newest]
Thread overview: 281+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-01-21 22:31 [PATCH v5 00/19] KVM: Dynamically size memslot arrays Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` [PATCH v5 01/19] KVM: x86: Allocate new rmap and large page tracking when moving memslot Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-05 21:49 ` Peter Xu
2020-02-05 21:49 ` Peter Xu
2020-02-05 21:49 ` Peter Xu
2020-02-05 21:49 ` Peter Xu
2020-02-05 23:55 ` Sean Christopherson
2020-02-05 23:55 ` Sean Christopherson
2020-02-05 23:55 ` Sean Christopherson
2020-02-05 23:55 ` Sean Christopherson
2020-02-06 2:00 ` Peter Xu
2020-02-06 2:00 ` Peter Xu
2020-02-06 2:00 ` Peter Xu
2020-02-06 2:00 ` Peter Xu
2020-02-06 2:17 ` Sean Christopherson
2020-02-06 2:17 ` Sean Christopherson
2020-02-06 2:17 ` Sean Christopherson
2020-02-06 2:17 ` Sean Christopherson
2020-02-06 2:58 ` Peter Xu
2020-02-06 2:58 ` Peter Xu
2020-02-06 2:58 ` Peter Xu
2020-02-06 2:58 ` Peter Xu
2020-02-06 5:05 ` Sean Christopherson
2020-02-06 5:05 ` Sean Christopherson
2020-02-06 5:05 ` Sean Christopherson
2020-02-06 5:05 ` Sean Christopherson
2020-01-21 22:31 ` [PATCH v5 02/19] KVM: Reinstall old memslots if arch preparation fails Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-05 22:08 ` Peter Xu
2020-02-05 22:08 ` Peter Xu
2020-02-05 22:08 ` Peter Xu
2020-02-05 22:08 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 03/19] KVM: Don't free new memslot if allocation of said memslot fails Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-05 22:28 ` Peter Xu
2020-02-05 22:28 ` Peter Xu
2020-02-05 22:28 ` Peter Xu
2020-02-05 22:28 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 04/19] KVM: PPC: Move memslot memory allocation into prepare_memory_region() Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-05 22:41 ` Peter Xu
2020-02-05 22:41 ` Peter Xu
2020-02-05 22:41 ` Peter Xu
2020-02-05 22:41 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 05/19] KVM: x86: Allocate memslot resources during prepare_memory_region() Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` [PATCH v5 06/19] KVM: Drop kvm_arch_create_memslot() Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-05 22:45 ` Peter Xu
2020-02-05 22:45 ` Peter Xu
2020-02-05 22:45 ` Peter Xu
2020-02-05 22:45 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 07/19] KVM: Explicitly free allocated-but-unused dirty bitmap Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` [PATCH v5 08/19] KVM: Refactor error handling for setting memory region Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-05 22:48 ` Peter Xu
2020-02-05 22:48 ` Peter Xu
2020-02-05 22:48 ` Peter Xu
2020-02-05 22:48 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 09/19] KVM: Move setting of memslot into helper routine Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-06 16:26 ` Peter Xu
2020-02-06 16:26 ` Peter Xu
2020-02-06 16:26 ` Peter Xu
2020-02-06 16:26 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 10/19] KVM: Drop "const" attribute from old memslot in commit_memory_region() Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-06 16:26 ` Peter Xu
2020-02-06 16:26 ` Peter Xu
2020-02-06 16:26 ` Peter Xu
2020-02-06 16:26 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 11/19] KVM: x86: Free arrays for old memslot when moving memslot's base gfn Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` [PATCH v5 12/19] KVM: Move memslot deletion to helper function Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-06 16:14 ` Peter Xu
2020-02-06 16:14 ` Peter Xu
2020-02-06 16:14 ` Peter Xu
2020-02-06 16:14 ` Peter Xu
2020-02-06 16:28 ` Sean Christopherson
2020-02-06 16:28 ` Sean Christopherson
2020-02-06 16:28 ` Sean Christopherson
2020-02-06 16:28 ` Sean Christopherson
2020-02-06 16:51 ` Peter Xu
2020-02-06 16:51 ` Peter Xu
2020-02-06 16:51 ` Peter Xu
2020-02-06 16:51 ` Peter Xu
2020-02-07 17:59 ` Sean Christopherson
2020-02-07 17:59 ` Sean Christopherson
2020-02-07 17:59 ` Sean Christopherson
2020-02-07 17:59 ` Sean Christopherson
2020-02-07 18:07 ` Sean Christopherson
2020-02-07 18:07 ` Sean Christopherson
2020-02-07 18:07 ` Sean Christopherson
2020-02-07 18:07 ` Sean Christopherson
2020-02-07 18:17 ` Peter Xu
2020-02-07 18:17 ` Peter Xu
2020-02-07 18:17 ` Peter Xu
2020-02-07 18:17 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 13/19] KVM: Simplify kvm_free_memslot() and all its descendents Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-06 16:29 ` Peter Xu
2020-02-06 16:29 ` Peter Xu
2020-02-06 16:29 ` Peter Xu
2020-02-06 16:29 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 14/19] KVM: Clean up local variable usage in __kvm_set_memory_region() Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-06 19:06 ` Peter Xu
2020-02-06 19:06 ` Peter Xu
2020-02-06 19:06 ` Peter Xu
2020-02-06 19:06 ` Peter Xu
2020-02-06 19:22 ` Sean Christopherson
2020-02-06 19:22 ` Sean Christopherson
2020-02-06 19:22 ` Sean Christopherson
2020-02-06 19:22 ` Sean Christopherson
2020-02-06 19:36 ` Peter Xu
2020-02-06 19:36 ` Peter Xu
2020-02-06 19:36 ` Peter Xu
2020-02-06 19:36 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 15/19] KVM: Provide common implementation for generic dirty log functions Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-06 20:02 ` Peter Xu
2020-02-06 20:02 ` Peter Xu
2020-02-06 20:02 ` Peter Xu
2020-02-06 20:02 ` Peter Xu
2020-02-06 21:21 ` Sean Christopherson
2020-02-06 21:21 ` Sean Christopherson
2020-02-06 21:21 ` Sean Christopherson
2020-02-06 21:21 ` Sean Christopherson
2020-02-06 21:41 ` Peter Xu
2020-02-06 21:41 ` Peter Xu
2020-02-06 21:41 ` Peter Xu
2020-02-06 21:41 ` Peter Xu
2020-02-07 19:45 ` Sean Christopherson
2020-02-07 19:45 ` Sean Christopherson
2020-02-07 19:45 ` Sean Christopherson
2020-02-07 19:45 ` Sean Christopherson
2020-02-08 0:18 ` Peter Xu
2020-02-08 0:18 ` Peter Xu
2020-02-08 0:18 ` Peter Xu
2020-02-08 0:18 ` Peter Xu
2020-02-08 0:42 ` Sean Christopherson
2020-02-08 0:42 ` Sean Christopherson
2020-02-08 0:42 ` Sean Christopherson
2020-02-08 0:42 ` Sean Christopherson
2020-02-08 0:53 ` Peter Xu
2020-02-08 0:53 ` Peter Xu
2020-02-08 0:53 ` Peter Xu
2020-02-08 0:53 ` Peter Xu
2020-02-08 1:29 ` Sean Christopherson
2020-02-08 1:29 ` Sean Christopherson
2020-02-08 1:29 ` Sean Christopherson
2020-02-08 1:29 ` Sean Christopherson
2020-02-17 15:39 ` Vitaly Kuznetsov
2020-02-17 15:39 ` Vitaly Kuznetsov
2020-02-17 15:39 ` Vitaly Kuznetsov
2020-02-17 15:39 ` Vitaly Kuznetsov
2020-02-18 17:10 ` Sean Christopherson
2020-02-18 17:10 ` Sean Christopherson
2020-02-18 17:10 ` Sean Christopherson
2020-02-18 17:10 ` Sean Christopherson
2020-02-17 15:35 ` Vitaly Kuznetsov
2020-02-17 15:35 ` Vitaly Kuznetsov
2020-02-17 15:35 ` Vitaly Kuznetsov
2020-02-17 15:35 ` Vitaly Kuznetsov
2020-02-06 21:24 ` Peter Xu
2020-02-06 21:24 ` Peter Xu
2020-02-06 21:24 ` Peter Xu
2020-02-06 21:24 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 16/19] KVM: Ensure validity of memslot with respect to kvm_get_dirty_log() Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` [PATCH v5 17/19] KVM: Terminate memslot walks via used_slots Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-06 21:09 ` Peter Xu
2020-02-06 21:09 ` Peter Xu
2020-02-06 21:09 ` Peter Xu
2020-02-06 21:09 ` Peter Xu
2020-02-07 18:33 ` Sean Christopherson
2020-02-07 18:33 ` Sean Christopherson
2020-02-07 18:33 ` Sean Christopherson
2020-02-07 18:33 ` Sean Christopherson
2020-02-07 20:39 ` Peter Xu
2020-02-07 20:39 ` Peter Xu
2020-02-07 20:39 ` Peter Xu
2020-02-07 20:39 ` Peter Xu
2020-02-07 21:10 ` Sean Christopherson
2020-02-07 21:10 ` Sean Christopherson
2020-02-07 21:10 ` Sean Christopherson
2020-02-07 21:10 ` Sean Christopherson
2020-02-07 21:46 ` Peter Xu
2020-02-07 21:46 ` Peter Xu
2020-02-07 21:46 ` Peter Xu
2020-02-07 21:46 ` Peter Xu
2020-02-07 22:03 ` Sean Christopherson
2020-02-07 22:03 ` Sean Christopherson
2020-02-07 22:03 ` Sean Christopherson
2020-02-07 22:03 ` Sean Christopherson
2020-02-07 22:24 ` Peter Xu
2020-02-07 22:24 ` Peter Xu
2020-02-07 22:24 ` Peter Xu
2020-02-07 22:24 ` Peter Xu
2020-01-21 22:31 ` [PATCH v5 18/19] KVM: Dynamically size memslot array based on number of used slots Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-06 22:12 ` Peter Xu
2020-02-06 22:12 ` Peter Xu
2020-02-06 22:12 ` Peter Xu
2020-02-06 22:12 ` Peter Xu
2020-02-07 15:38 ` Sean Christopherson [this message]
2020-02-07 15:38 ` Sean Christopherson
2020-02-07 15:38 ` Sean Christopherson
2020-02-07 15:38 ` Sean Christopherson
2020-02-07 16:05 ` Peter Xu
2020-02-07 16:05 ` Peter Xu
2020-02-07 16:05 ` Peter Xu
2020-02-07 16:05 ` Peter Xu
2020-02-07 16:09 ` Peter Xu
2020-02-07 16:15 ` Sean Christopherson
2020-02-07 16:15 ` Sean Christopherson
2020-02-07 16:15 ` Sean Christopherson
2020-02-07 16:15 ` Sean Christopherson
2020-02-07 16:37 ` Peter Xu
2020-02-07 16:37 ` Peter Xu
2020-02-07 16:37 ` Peter Xu
2020-02-07 16:37 ` Peter Xu
2020-02-07 16:47 ` Sean Christopherson
2020-02-07 16:47 ` Sean Christopherson
2020-02-07 16:47 ` Sean Christopherson
2020-02-07 16:47 ` Sean Christopherson
2020-01-21 22:31 ` [PATCH v5 19/19] KVM: selftests: Add test for KVM_SET_USER_MEMORY_REGION Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-01-21 22:31 ` Sean Christopherson
2020-02-06 22:30 ` Peter Xu
2020-02-06 22:30 ` Peter Xu
2020-02-06 22:30 ` Peter Xu
2020-02-06 22:30 ` Peter Xu
2020-02-06 23:11 ` Sean Christopherson
2020-02-06 23:11 ` Sean Christopherson
2020-02-06 23:11 ` Sean Christopherson
2020-02-06 23:11 ` Sean Christopherson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200207153829.GA2401@linux.intel.com \
--to=sean.j.christopherson@intel.com \
--cc=borntraeger@de.ibm.com \
--cc=christoffer.dall@arm.com \
--cc=cohuck@redhat.com \
--cc=david@redhat.com \
--cc=f4bug@amsat.org \
--cc=frankja@linux.ibm.com \
--cc=james.morse@arm.com \
--cc=jmattson@google.com \
--cc=joro@8bytes.org \
--cc=julien.thierry.kdev@gmail.com \
--cc=kvm-ppc@vger.kernel.org \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@vger.kernel.org \
--cc=maz@kernel.org \
--cc=paulus@ozlabs.org \
--cc=pbonzini@redhat.com \
--cc=peterx@redhat.com \
--cc=suzuki.poulose@arm.com \
--cc=vkuznets@redhat.com \
--cc=wanpengli@tencent.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.