From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=209.85.221.54 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793749658; b=1bbSqXQQhqzNeh8CMHMw77ubVhrW2FdrQ1Ay5NkKVAIjoQdloH8RUFCG9+5kldegf0Re 9LJCx4OxC1l094ZZzAkSBvF4Ti16DoyvIWvJkPeio3SO7SGS29RzSRM8jBAYCAaiMEB0g NQC4f6PRfNxFsGacrQV1Xu+pedAjDoCZcnIeN13ZO8dD731ndIiExmBaYKv2hL8RK3e4R 4xR4QqOijU5dlg5dJVk/l8XWaeJ20gvTKI5ySFC4kG2o0rIJ+PgZnYpwBliONI+IDilmo tWt34DXTlUUlptJ/WzVpHB9CTbb2Mf52pQEV+ZGME4xKoRS56xGTyFnemNlHk/0DSzw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793749658; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Gm-Gg:X-Received:Received: From:To:Cc:Subject:Date:Message-ID:X-Mailer:MIME-Version: Content-Transfer-Encoding; bh=AkKw4T5m37AkLEe85hcfetEiJRRZnmi/qOahhWII6+4=; b=00aGmEhJK9b0PowHRO4qwXK0eEpZGQclPMqA2vjKkIPgYZ7/nGWLmDw3Sa3BW74p9U1I XX5+C2F5YWF9Dq56g21yFRtc/p/a9ql5uV9iayLVT5xBpN4u6nCAdziu9IfQLhTTppBCK dOazATKLb4OWdagPd5W07BKIR1EiQq3PwYp+DA5Cfmd/yFSke8mmJHPrbBQ7v1+0UyDsc qsngMUIpb9SQL+pGoY8SWYEJYwzVlTNwsnIiNrdb5LuSrgc1wsh8f1pON7EKlBRvnIDZM YKph7/5YUD6htNwcvwZfmhS/VcxA2wUCSeExFykW3oOP7r3o56OBY9XLqazKysm6DKg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=ERXTcHWS; arc=none smtp.remote-ip=209.85.221.54 Received: from mail-wr1-f54.google.com (mail-wr1-f54.google.com [209.85.221.54]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E9959606A32C for ; Tue, 3 Nov 2026 23:47:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org E9959606A32C Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=ERXTcHWS Received: by mail-wr1-f54.google.com with SMTP id ffacd0b85a97d-48c4d870d54so66605f8f.2 for ; Tue, 03 Nov 2026 15:47:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793749656; x=1794354456; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=AkKw4T5m37AkLEe85hcfetEiJRRZnmi/qOahhWII6+4=; b=ERXTcHWSYCrkK2Qrh6f15zyBfRtOn/QeZy+UFHEqi3AW08uOHBNpKkrULsL3Qy3sN0 MfxlbOAAFb2//xkWF0ZAuksl8OCrXuixPN/k2+yuQ/BFQHCujTyaeact3H8+qco3HkPv 58U8g0M/vvgu7X7IeehrhIxJRca4IiiyXrFEDZksElVBfOIGiXl5K3BHyqX/xI+8Uc2R 8+Z0CDSfd9a7BSZjk8ncQaf4tJG2if7DHqpykhBy04YuBoD6+XKLd4s6+Y0FWNu70ZaC sv2ZoLuUTg1xOPzQNnQyYzLaoEXlNCY3KZlZuTwvBw9v9jc3JR8UNViBdilNkXPtelLv 8d4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793749656; x=1794354456; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=AkKw4T5m37AkLEe85hcfetEiJRRZnmi/qOahhWII6+4=; b=fQ2HqKciGuMi6gxMbUTSnytU90T5/U6y4AeK2MQkGdHJvm94JE+QiKyAYLZ7xU6ezS 8owdDSTpBclmUgQhOP5JOSRI/c11ELjOG0YDAnmW8KhLE/6J/8HRvvm/yNxEC5KcL7xB ZsymaK/iia2ZUvz9cRoPv4UrWduMHI9kPwxv47dJSHOQfPvMogQX/RTnwlj4/l63qLqX Dpe2gMXNPEUkY0uASoo/UVPNNPrC19k9GpsejhIq4bPsNig1bhSbSjHKkdvMt3Fy5S+1 wlHp0OFRshwJuAnw24gtmHhcGtKITo96D82Qjf/ucKENlLNwmA49o2jU7cQG9+kHyyvK Yabg== X-Forwarded-Encrypted: i=1; AKwUvBxQkbwdd4FVPwm+gmHsJzHwagy+3wyHmLGpuEJkpBEOpxQFa/WJdgBbhkVTgz3gbo8X2W2/19tzuyr7k1I=@vger.kernel.org X-Gm-Message-State: APuU4Z9hrFb8N7E+VlEdfFB+5Hl3CuITHgLph6glQJTioeYXeA7L5/// aoobc2g9iQ/TxIGNvvGXxEp4xYzExeIkWbe+7UtTTLEOW/EitV9keR759nVW28MocYZZ9w== X-Gm-Gg: AYBFou2uiRUrR1M+crWJC815ZXetFvewbrt08Uc/5wYxEYmIJluH4/Jbljw0vwoiXm4 KcctD7DGbY3NQfqTXuE1YvWeYSvUaYjiDRfBulwGWJQMYCoclzglg4rkDFFkoE9qBy630N0lfuD ICoErLckCwl8NjAfxKVXNO+Bvs7dtDz74P66DKHPqM2CF4p/WltiZJKhnOxjSEbpbRjPdqbVUzq 59ncYQyzFtX0nc0qJeR00y1hyc5i/0KCsOj9NJUXGqcJalTtinFhGcHGnrSDpvAv87ciKsXsgWH fxmFQ+xRuQ8COqwXwgFFEUpeBnb1b2xhSBtOUDvErvyh6EJPrEBqiQvLE/HYC3z13C2ShAPfLNk SSj5qvkfutsgN7PKxtzWqaElFGqWiNGoZK56ogwGKHGndXRlefh7pVm/ds1okh2PN02qToybglw lBectodloy9+eYqa+0I1BNahbwEobHzT3IUDo230FnlQsqypxfi+IK1edNuWjAGDqDpR0SneDS1 zVxvUsRv9WTOIw7+qkr5+oag46Y5u8MH00dlYikEdzmuCgzdTzYu+tshFIeS3aFnfXa0Ax5UB0T qUy+/i1NLqZ6sO9afRZpBVQ6P2/PbANrUwTm4yaw2Nv+bE5k9yanVZ8fNKGMzKNLQ5OoQ/l2Sxt IY7cVsfg4pvV9/hXaGZPS9qte2lmQK4gx+BVQZe02KwLQPYt7LEL4RjhX8Fwl4vtXjQ== X-Received: by 2002:a05:6000:383:b0:48e:889b:5fe8 with SMTP id ffacd0b85a97d-48e889b6deamr11283948f8f.10.1793749656012; Tue, 03 Nov 2026 15:47:36 -0800 (PST) Received: from dev-dsk-fgriffo-1c-93421965.eu-west-1.amazon.com (54-240-197-234.amazon.com. [54.240.197.234]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-48feea5d4e4sm550961f8f.57.2026.11.03.15.47.34 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 03 Nov 2026 15:47:35 -0800 (PST) From: Fred Griffoul To: Sean Christopherson , Paolo Bonzini Cc: Mushahid Hussain , nh-open-source@amazon.com, kvm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] KVM: Add helpers to allocate memslot metadata Date: Tue, 3 Nov 2026 23:47:34 +0000 Message-ID: <20261103234734.45413-1-griffoul@gmail.com> X-Mailer: git-send-email 2.47.3 X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Fred Griffoul __vcalloc() makes every allocation at least one page, so a memslot that spans a single page uses 8 KiB of vmalloc for 8 bytes of lpage_info, plus 4 KiB for a 16-byte dirty bitmap once dirty logging is enabled. The waste grows with the number of memslots and VMs on a host. kvcalloc() avoids it for small arrays, but refuses allocations above INT_MAX bytes, which the rmap and write-tracking arrays of a large memslot exceed. Add kvm_memslot_metadata_alloc() and kvm_memslot_metadata_free(), which use kvzalloc() up to INT_MAX bytes and vmalloc above, and route the dirty bitmap, rmaps, lpage_info and write-tracking arrays through them. That way, how KVM allocates memslot metadata is decided in one place instead of at each array. Suggested-by: Sean Christopherson Link: https://lore.kernel.org/all/arr1VgGZmgUmY4hc@google.com/ Signed-off-by: Fred Griffoul --- Mushahid's patch [1] switched the lpage_info arrays and dirty bitmaps to kvcalloc(). Sean suggested dedicated helpers for memslot metadata instead [2], which this patch adds. [1] https://lore.kernel.org/all/20260815142218.85067-1-hmushi@amazon.co.uk/ [2] https://lore.kernel.org/all/arr1VgGZmgUmY4hc@google.com/ --- arch/x86/kvm/mmu/page_track.c | 6 +++--- arch/x86/kvm/x86.c | 10 +++++----- include/linux/kvm_host.h | 2 ++ virt/kvm/kvm_main.c | 23 +++++++++++++++++++++-- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/mmu/page_track.c b/arch/x86/kvm/mmu/page_track.c index f12558dfcd81..f33547964b98 100644 --- a/arch/x86/kvm/mmu/page_track.c +++ b/arch/x86/kvm/mmu/page_track.c @@ -43,7 +43,7 @@ bool kvm_page_track_write_tracking_enabled(struct kvm *kvm) void kvm_page_track_free_memslot(struct kvm_memory_slot *slot) { - vfree(slot->arch.gfn_write_track); + kvm_memslot_metadata_free(slot->arch.gfn_write_track); slot->arch.gfn_write_track = NULL; } @@ -53,8 +53,8 @@ static int __kvm_page_track_write_tracking_alloc(struct kvm_memory_slot *slot, const size_t size = sizeof(*slot->arch.gfn_write_track); if (!slot->arch.gfn_write_track) - slot->arch.gfn_write_track = __vcalloc(npages, size, - GFP_KERNEL_ACCOUNT); + slot->arch.gfn_write_track = + kvm_memslot_metadata_alloc(npages, size); return slot->arch.gfn_write_track ? 0 : -ENOMEM; } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 26e7beaff8a0..dc716ad83c8f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -10146,7 +10146,7 @@ static void memslot_rmap_free(struct kvm_memory_slot *slot) int i; for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) { - vfree(slot->arch.rmap[i]); + kvm_memslot_metadata_free(slot->arch.rmap[i]); slot->arch.rmap[i] = NULL; } } @@ -10158,7 +10158,7 @@ void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot) memslot_rmap_free(slot); for (i = 1; i < KVM_NR_PAGE_SIZES; ++i) { - vfree(slot->arch.lpage_info[i - 1]); + kvm_memslot_metadata_free(slot->arch.lpage_info[i - 1]); slot->arch.lpage_info[i - 1] = NULL; } @@ -10177,7 +10177,7 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages) if (slot->arch.rmap[i]) continue; - slot->arch.rmap[i] = __vcalloc(lpages, sz, GFP_KERNEL_ACCOUNT); + slot->arch.rmap[i] = kvm_memslot_metadata_alloc(lpages, sz); if (!slot->arch.rmap[i]) { memslot_rmap_free(slot); return -ENOMEM; @@ -10214,7 +10214,7 @@ static int kvm_alloc_memslot_metadata(struct kvm *kvm, lpages = __kvm_mmu_slot_lpages(slot, npages, level); - linfo = __vcalloc(lpages, sizeof(*linfo), GFP_KERNEL_ACCOUNT); + linfo = kvm_memslot_metadata_alloc(lpages, sizeof(*linfo)); if (!linfo) goto out_free; @@ -10250,7 +10250,7 @@ static int kvm_alloc_memslot_metadata(struct kvm *kvm, memslot_rmap_free(slot); for (i = 1; i < KVM_NR_PAGE_SIZES; ++i) { - vfree(slot->arch.lpage_info[i - 1]); + kvm_memslot_metadata_free(slot->arch.lpage_info[i - 1]); slot->arch.lpage_info[i - 1] = NULL; } return -ENOMEM; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index e7fc94e2910a..11a6f501a78b 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1253,6 +1253,8 @@ enum kvm_mr_change { int kvm_set_internal_memslot(struct kvm *kvm, const struct kvm_userspace_memory_region2 *mem); +void *kvm_memslot_metadata_alloc(size_t n, size_t size); +void kvm_memslot_metadata_free(void *p); void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot); void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen); int kvm_arch_prepare_memory_region(struct kvm *kvm, diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index cf4cb586f140..ce872ffc779f 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -941,12 +941,31 @@ static void kvm_destroy_pm_notifier(struct kvm *kvm) } #endif /* CONFIG_HAVE_KVM_PM_NOTIFIER */ +void *kvm_memslot_metadata_alloc(size_t n, size_t size) +{ + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) + return NULL; + + /* kvzalloc() refuses sizes above INT_MAX, which large memslots need. */ + if (bytes <= INT_MAX) + return kvzalloc(bytes, GFP_KERNEL_ACCOUNT); + + return __vmalloc(bytes, GFP_KERNEL_ACCOUNT | __GFP_ZERO); +} + +void kvm_memslot_metadata_free(void *p) +{ + kvfree(p); +} + static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot) { if (!memslot->dirty_bitmap) return; - vfree(memslot->dirty_bitmap); + kvm_memslot_metadata_free(memslot->dirty_bitmap); memslot->dirty_bitmap = NULL; } @@ -1449,7 +1468,7 @@ static int kvm_alloc_dirty_bitmap(struct kvm_memory_slot *memslot) { unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(memslot); - memslot->dirty_bitmap = __vcalloc(2, dirty_bytes, GFP_KERNEL_ACCOUNT); + memslot->dirty_bitmap = kvm_memslot_metadata_alloc(2, dirty_bytes); if (!memslot->dirty_bitmap) return -ENOMEM; base-commit: d21eef2084a9af87ac2a783bc7c2b175ba114e4e -- 2.47.3