diff mbox series

[3/3] KVM: selftests: Fix dirty bitmap offset calculation

Message ID 20210915213034.1613552-4-dmatlack@google.com (mailing list archive)
State New, archived
Headers show
Series KVM: selftests: Small fixes for dirty_log_perf_test | expand

Commit Message

David Matlack Sept. 15, 2021, 9:30 p.m. UTC
The calculation to get the per-slot dirty bitmap was incorrect leading
to a buffer overrun. Fix it by dividing the number of pages by
BITS_PER_LONG, since each element of the bitmap is a long and there is
one bit per page.

Fixes: 609e6202ea5f ("KVM: selftests: Support multiple slots in dirty_log_perf_test")
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/dirty_log_perf_test.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

Comments

Ben Gardon Sept. 15, 2021, 9:55 p.m. UTC | #1
On Wed, Sep 15, 2021 at 2:30 PM David Matlack <dmatlack@google.com> wrote:
>
> The calculation to get the per-slot dirty bitmap was incorrect leading
> to a buffer overrun. Fix it by dividing the number of pages by
> BITS_PER_LONG, since each element of the bitmap is a long and there is
> one bit per page.
>
> Fixes: 609e6202ea5f ("KVM: selftests: Support multiple slots in dirty_log_perf_test")
> Signed-off-by: David Matlack <dmatlack@google.com>

I was a little confused initially because we're allocating only one
dirty bitmap in userspace even when we have multiple slots, but that's
not a problem.

Reviewed-by: Ben Gardon <bgardon@google.com>


>
> ---
>  tools/testing/selftests/kvm/dirty_log_perf_test.c | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c
> index 5ad9f2bc7369..0dd4626571e9 100644
> --- a/tools/testing/selftests/kvm/dirty_log_perf_test.c
> +++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c
> @@ -118,6 +118,12 @@ static inline void disable_dirty_logging(struct kvm_vm *vm, int slots)
>         toggle_dirty_logging(vm, slots, false);
>  }
>
> +static unsigned long *get_slot_bitmap(unsigned long *bitmap, uint64_t page_offset)
> +{
> +       /* Guaranteed to be evenly divisible by the TEST_ASSERT in run_test. */
> +       return &bitmap[page_offset / BITS_PER_LONG];
> +}
> +
>  static void get_dirty_log(struct kvm_vm *vm, int slots, unsigned long *bitmap,
>                           uint64_t nr_pages)
>  {
> @@ -126,7 +132,8 @@ static void get_dirty_log(struct kvm_vm *vm, int slots, unsigned long *bitmap,
>
>         for (i = 0; i < slots; i++) {
>                 int slot = PERF_TEST_MEM_SLOT_INDEX + i;
> -               unsigned long *slot_bitmap = bitmap + i * slot_pages;
> +               uint64_t page_offset = slot_pages * i;
> +               unsigned long *slot_bitmap = get_slot_bitmap(bitmap, page_offset);
>
>                 kvm_vm_get_dirty_log(vm, slot, slot_bitmap);
>         }
> @@ -140,7 +147,8 @@ static void clear_dirty_log(struct kvm_vm *vm, int slots, unsigned long *bitmap,
>
>         for (i = 0; i < slots; i++) {
>                 int slot = PERF_TEST_MEM_SLOT_INDEX + i;
> -               unsigned long *slot_bitmap = bitmap + i * slot_pages;
> +               uint64_t page_offset = slot_pages * i;
> +               unsigned long *slot_bitmap = get_slot_bitmap(bitmap, page_offset);
>
>                 kvm_vm_clear_dirty_log(vm, slot, slot_bitmap, 0, slot_pages);
>         }
> @@ -172,6 +180,9 @@ static void run_test(enum vm_guest_mode mode, void *arg)
>         guest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages);
>         host_num_pages = vm_num_host_pages(mode, guest_num_pages);
>         bmap = bitmap_alloc(host_num_pages);
> +       TEST_ASSERT((host_num_pages / p->slots) % BITS_PER_LONG == 0,
> +                   "The number of pages per slot must be divisible by %d.",
> +                   BITS_PER_LONG);
>
>         if (dirty_log_manual_caps) {
>                 cap.cap = KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2;
> --
> 2.33.0.309.g3052b89438-goog
>
Andrew Jones Sept. 16, 2021, 8:49 a.m. UTC | #2
On Wed, Sep 15, 2021 at 02:55:03PM -0700, Ben Gardon wrote:
> On Wed, Sep 15, 2021 at 2:30 PM David Matlack <dmatlack@google.com> wrote:
> >
> > The calculation to get the per-slot dirty bitmap was incorrect leading
> > to a buffer overrun. Fix it by dividing the number of pages by
> > BITS_PER_LONG, since each element of the bitmap is a long and there is
> > one bit per page.
> >
> > Fixes: 609e6202ea5f ("KVM: selftests: Support multiple slots in dirty_log_perf_test")
> > Signed-off-by: David Matlack <dmatlack@google.com>
> 
> I was a little confused initially because we're allocating only one
> dirty bitmap in userspace even when we have multiple slots, but that's
> not a problem.

It's also confusing to me. Wouldn't it be better to create a bitmap per
slot? I think the new constraint that host mem must be a multiple of 64
is unfortunate.

Thanks,
drew
David Matlack Sept. 16, 2021, 4:37 p.m. UTC | #3
On Thu, Sep 16, 2021 at 1:49 AM Andrew Jones <drjones@redhat.com> wrote:
>
> On Wed, Sep 15, 2021 at 02:55:03PM -0700, Ben Gardon wrote:
> > On Wed, Sep 15, 2021 at 2:30 PM David Matlack <dmatlack@google.com> wrote:
> > >
> > > The calculation to get the per-slot dirty bitmap was incorrect leading
> > > to a buffer overrun. Fix it by dividing the number of pages by
> > > BITS_PER_LONG, since each element of the bitmap is a long and there is
> > > one bit per page.
> > >
> > > Fixes: 609e6202ea5f ("KVM: selftests: Support multiple slots in dirty_log_perf_test")
> > > Signed-off-by: David Matlack <dmatlack@google.com>
> >
> > I was a little confused initially because we're allocating only one
> > dirty bitmap in userspace even when we have multiple slots, but that's
> > not a problem.
>
> It's also confusing to me. Wouldn't it be better to create a bitmap per
> slot? I think the new constraint that host mem must be a multiple of 64
> is unfortunate.

I don't think think the multiple-of-64 (256K) constraint will matter
much in practice. But it wouldn't be very complicated to switch to a
bitmap per slot, and would prevent further confusion.

I'll switch it over in v2.

>
> Thanks,
> drew
>
Paolo Bonzini Sept. 22, 2021, 11:09 a.m. UTC | #4
On 16/09/21 10:49, Andrew Jones wrote:
>> I was a little confused initially because we're allocating only one
>> dirty bitmap in userspace even when we have multiple slots, but that's
>> not a problem.
> It's also confusing to me. Wouldn't it be better to create a bitmap per
> slot? I think the new constraint that host mem must be a multiple of 64
> is unfortunate.

Yeah, I wouldn't mind if someone took a look at that.  Also because 
anyway this patch doesn't apply to master right now, I've queued 1-2 only.

Paolo
Andrew Jones Sept. 22, 2021, 11:19 a.m. UTC | #5
On Wed, Sep 22, 2021 at 01:09:57PM +0200, Paolo Bonzini wrote:
> On 16/09/21 10:49, Andrew Jones wrote:
> > > I was a little confused initially because we're allocating only one
> > > dirty bitmap in userspace even when we have multiple slots, but that's
> > > not a problem.
> > It's also confusing to me. Wouldn't it be better to create a bitmap per
> > slot? I think the new constraint that host mem must be a multiple of 64
> > is unfortunate.
> 
> Yeah, I wouldn't mind if someone took a look at that.  Also because anyway
> this patch doesn't apply to master right now, I've queued 1-2 only.

David posted a v2 on Sept. 17 with the bitmap split up per slot for patch
3/3. I think the other patches got some tweaks too.

Thanks
drew
diff mbox series

Patch

diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c
index 5ad9f2bc7369..0dd4626571e9 100644
--- a/tools/testing/selftests/kvm/dirty_log_perf_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c
@@ -118,6 +118,12 @@  static inline void disable_dirty_logging(struct kvm_vm *vm, int slots)
 	toggle_dirty_logging(vm, slots, false);
 }
 
+static unsigned long *get_slot_bitmap(unsigned long *bitmap, uint64_t page_offset)
+{
+	/* Guaranteed to be evenly divisible by the TEST_ASSERT in run_test. */
+	return &bitmap[page_offset / BITS_PER_LONG];
+}
+
 static void get_dirty_log(struct kvm_vm *vm, int slots, unsigned long *bitmap,
 			  uint64_t nr_pages)
 {
@@ -126,7 +132,8 @@  static void get_dirty_log(struct kvm_vm *vm, int slots, unsigned long *bitmap,
 
 	for (i = 0; i < slots; i++) {
 		int slot = PERF_TEST_MEM_SLOT_INDEX + i;
-		unsigned long *slot_bitmap = bitmap + i * slot_pages;
+		uint64_t page_offset = slot_pages * i;
+		unsigned long *slot_bitmap = get_slot_bitmap(bitmap, page_offset);
 
 		kvm_vm_get_dirty_log(vm, slot, slot_bitmap);
 	}
@@ -140,7 +147,8 @@  static void clear_dirty_log(struct kvm_vm *vm, int slots, unsigned long *bitmap,
 
 	for (i = 0; i < slots; i++) {
 		int slot = PERF_TEST_MEM_SLOT_INDEX + i;
-		unsigned long *slot_bitmap = bitmap + i * slot_pages;
+		uint64_t page_offset = slot_pages * i;
+		unsigned long *slot_bitmap = get_slot_bitmap(bitmap, page_offset);
 
 		kvm_vm_clear_dirty_log(vm, slot, slot_bitmap, 0, slot_pages);
 	}
@@ -172,6 +180,9 @@  static void run_test(enum vm_guest_mode mode, void *arg)
 	guest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages);
 	host_num_pages = vm_num_host_pages(mode, guest_num_pages);
 	bmap = bitmap_alloc(host_num_pages);
+	TEST_ASSERT((host_num_pages / p->slots) % BITS_PER_LONG == 0,
+		    "The number of pages per slot must be divisible by %d.",
+		    BITS_PER_LONG);
 
 	if (dirty_log_manual_caps) {
 		cap.cap = KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2;