From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B687ECDB475 for ; Mon, 22 Jun 2026 18:49:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type:Cc:To:From: Subject:Message-ID:References:Mime-Version:In-Reply-To:Date:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=uxmxXtXLX2FKIn/jikNfDJMM+jo3cX9aru0TaotD/JM=; b=OU7RMRIVj5UkCRboIJjYHlDy35 4u778M0/RMO6KxcgLAZY5oCu/ck5n6ukK0v/xF8l5IUcAYN8e9MqwEe93CUIZkFDcdQSsrfavV5M+ YzSg5v+jiMAYScqHV59Cx8IXi4y+PfMYgHPRSWw3N08KEal1aC7oTBb/U5HSeWyWImn5rR+IBL9l0 8YYz83/rJP8OEoMZ+mtzTS89Uas+ueRihttXQ9C2aY+LtByzlqGpWFK5qxRoMRLXIwsnllFIhmLCG ab1jUtVJQ5Fw3RodCGcT4o5RDVYVAye2zgmMIpOqAPxFLAqF3kVbID/H+wP+I6b8HvfOr/6iS/MZm CWqrSXlw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1wbjhl-00000005JJC-3c64; Mon, 22 Jun 2026 18:49:09 +0000 Received: from mail-wm1-x34a.google.com ([2a00:1450:4864:20::34a]) by bombadil.infradead.org with esmtps (Exim 4.99.1 #2 (Red Hat Linux)) id 1wbjhi-00000005JGD-1dMM for kexec@lists.infradead.org; Mon, 22 Jun 2026 18:49:07 +0000 Received: by mail-wm1-x34a.google.com with SMTP id 5b1f17b1804b1-490b37e1f48so28470495e9.0 for ; Mon, 22 Jun 2026 11:49:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1782154144; x=1782758944; darn=lists.infradead.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=uxmxXtXLX2FKIn/jikNfDJMM+jo3cX9aru0TaotD/JM=; b=JVL0X+/xAPND41pTJ8as4m10h63FHn+5MazOgpQmLbQlXbj9bTKjgA/tLW9Cxp7m4O wUTt/7r5wc+D4hzEN+xOCFAnGeZd7kqvVhvg/OxgSdiXKrBRO3lJ1s6HL3j3pAfDhRmA 483sZGmFhonZXNEynDv9Sx8E0KalDIbXHoJ6nTuesViuL0GnQ0lPjpBwaqDFGVOTxLgL 1c/bQxP5KGhfQkCdfy5CcA0GYOWHg6pFrThfpRdATywbNNWZFqW17tsF/kYYupSXZChS pX6JpQ+6/zgyJGVbqdV2/3Ev0yC0D95nEeNlVv8ZvGOIOvYvpO7m26dtnJLRTFP2nftZ VjIg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782154144; x=1782758944; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=uxmxXtXLX2FKIn/jikNfDJMM+jo3cX9aru0TaotD/JM=; b=pgU9JqYO/EOdYwH42pYG+pdLtCRlFQ0mIobFj6fVwLqT7YuyijW1y20cvsONhp0yaN jN/DdDeWQH0rTYOqjCA5sjxqfqUKc+FC0ZYYooDH8YWgBT38YuIgc8ecZh2reQ4Wx1fI nx3EyIGscpBzmGQ9awjA2kyAF3We16yOctfJyTkRvar4tw+HaqIbtyv2cBiyK+OY3Ezd hWyoasqEIEWktxT4OixQkvd4PsBSXhvwnitXBuzSHn8yyZEAJkEt2xt6U8yTmUMZyzvC gmczuEldHakUp+SDMOxPJfVjdKrQw6yYXMd85YPyUDuzHEjFxk3YaaqjpiVcDBHW+ccV JE1w== X-Forwarded-Encrypted: i=1; AFNElJ96SaELfhT/HCrhc5dwLjocP5ebM4mgGG2WchU6zuZ8qreKjlIOhXHLgH9+S2RDcSyr1uS11Q==@lists.infradead.org X-Gm-Message-State: AOJu0YzDpallZOL3Qjem6q4kiXcwgfmoJMSb80yqpa/9kjowfnYKGsSt 9sI3wjH89lixqltgBaapHlhHiDH7199rDh5B0+cBIHWBdnh94vHCqKOOJ2OXAAhd7MB05fG6HQB jS+yp1/5Wtn4v5tRDzQ== X-Received: from wmix10-n2.prod.google.com ([2002:a05:600c:e54a:20b0:492:4a6f:ac6d]) (user=tarunsahu job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:8b74:b0:492:348:ba08 with SMTP id 5b1f17b1804b1-4923f44035dmr253038125e9.16.1782154143613; Mon, 22 Jun 2026 11:49:03 -0700 (PDT) Date: Mon, 22 Jun 2026 18:48:45 +0000 In-Reply-To: <20260622184851.2309827-1-tarunsahu@google.com> Mime-Version: 1.0 References: <20260622184851.2309827-1-tarunsahu@google.com> X-Mailer: git-send-email 2.55.0.rc0.786.g65d90a0328-goog Message-ID: <20260622184851.2309827-4-tarunsahu@google.com> Subject: [PATCH v3 3/9] kvm: kvm_luo: Allow kvm preservation with LUO From: Tarun Sahu To: Jonathan Corbet , Mike Rapoport , Paolo Bonzini , Alexander Graf , Shuah Khan , Pratyush Yadav , Tarun Sahu , Pasha Tatashin Cc: kvm@vger.kernel.org, linux-mm@kvack.org, kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Content-Type: text/plain; charset="UTF-8" X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.9.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260622_114906_499984_479C67DC X-CRM114-Status: GOOD ( 30.86 ) X-BeenThere: kexec@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "kexec" Errors-To: kexec-bounces+kexec=archiver.kernel.org@lists.infradead.org Introduce KVM VM preservation support for Live Update Orchestrator. Register an LUO file handler for KVM files to serialize and deserialize necessary VM state across live updates. Currently, this preserves the VM type. This implementation provides the necessary infrastructure and dependencies for the upcoming guest_memfd preservation support. And it can be extended to preserve more vm state in future. Retrieve is simply creating the kvm and populate the retrieved data. Only catch here is there is no way to know which fd is going to be assigned to this kvm file hence I am using atomically incremented id for the fdname. This change also updates the MAINTAINERS list for kvm_luo.c. Signed-off-by: Tarun Sahu --- MAINTAINERS | 11 ++ include/linux/kho/abi/kvm.h | 39 ++++++++ virt/kvm/Makefile.kvm | 1 + virt/kvm/kvm_luo.c | 195 ++++++++++++++++++++++++++++++++++++ virt/kvm/kvm_main.c | 8 ++ virt/kvm/kvm_mm.h | 8 ++ 6 files changed, 262 insertions(+) create mode 100644 include/linux/kho/abi/kvm.h create mode 100644 virt/kvm/kvm_luo.c diff --git a/MAINTAINERS b/MAINTAINERS index 5dbc8a6..7c000e6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14411,6 +14411,17 @@ S: Maintained F: Documentation/devicetree/bindings/leds/backlight/kinetic,ktz8866.yaml F: drivers/video/backlight/ktz8866.c +KVM LIVE UPDATE +M: Pasha Tatashin +M: Mike Rapoport +M: Pratyush Yadav +R: Tarun Sahu +L: kexec@lists.infradead.org +L: kvm@vger.kernel.org +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git +F: virt/kvm/kvm_luo.c + KVM PARAVIRT (KVM/paravirt) M: Paolo Bonzini R: Vitaly Kuznetsov diff --git a/include/linux/kho/abi/kvm.h b/include/linux/kho/abi/kvm.h new file mode 100644 index 0000000..718db68 --- /dev/null +++ b/include/linux/kho/abi/kvm.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2026, Google LLC. + * Tarun Sahu + * + * KVM Preservation ABI for Live Update Orchestrator (LUO) + */ +#ifndef _LINUX_KHO_ABI_KVM_H +#define _LINUX_KHO_ABI_KVM_H + +#include +#include + +/** + * DOC: KVM Live Update ABI + * + * KVM uses the ABI defined below for preserving its state + * across a kexec reboot using the LUO. + * + * The state is serialized into a packed structure `struct kvm_luo_ser` + * which is handed over to the next kernel via the KHO mechanism. + * + * This interface is a contract. Any modification to the structure layout + * constitutes a breaking change. Such changes require incrementing the + * version number in the KVM_LUO_FH_COMPATIBLE compatibility string. + */ + +/** + * struct kvm_luo_ser - Main serialization structure for a KVM VM. + * @type: The type of VM. + */ +struct kvm_luo_ser { + u64 type; +} __packed; + +/* The compatibility string for KVM VM file handler */ +#define KVM_LUO_FH_COMPATIBLE "kvm_vm_luo_v1" + +#endif /* _LINUX_KHO_ABI_KVM_H */ diff --git a/virt/kvm/Makefile.kvm b/virt/kvm/Makefile.kvm index d047d4c..c1a9621 100644 --- a/virt/kvm/Makefile.kvm +++ b/virt/kvm/Makefile.kvm @@ -13,3 +13,4 @@ kvm-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(KVM)/irqchip.o kvm-$(CONFIG_HAVE_KVM_DIRTY_RING) += $(KVM)/dirty_ring.o kvm-$(CONFIG_HAVE_KVM_PFNCACHE) += $(KVM)/pfncache.o kvm-$(CONFIG_KVM_GUEST_MEMFD) += $(KVM)/guest_memfd.o +kvm-$(CONFIG_LIVEUPDATE_GUEST_MEMFD) += $(KVM)/kvm_luo.o diff --git a/virt/kvm/kvm_luo.c b/virt/kvm/kvm_luo.c new file mode 100644 index 0000000..6728877 --- /dev/null +++ b/virt/kvm/kvm_luo.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2026, Google LLC. + * Tarun Sahu + * + * KVM VM Preservation for Live Update Orchestrator (LUO) + */ + +/** + * DOC: KVM VM Preservation via LUO + * + * Overview + * ======== + * + * KVM virtual machines (VMs) can be preserved over a kexec reboot using the + * Live Update Orchestrator (LUO) file preservation. This allows userspace + * to preserve KVM VM state across kexec reboots. + * + * The preservation is not intended to be fully transparent. Only specific + * VM configuration and state are preserved, while other aspects of the VM + * must be re-established or re-configured by userspace after retrieval. + * + * Preserved Properties + * ==================== + * + * The following properties of the KVM VM are preserved across kexec: + * + * VM Type + * The VM type (e.g., on x86 architecture, the vm_type parameter) is + * preserved. + * + * Non-Preserved Properties + * ======================== + * + * The preservation does not cover: + * + * - vCPUs and vCPU states + * - Memspots / Memory slot layout (memslots) + * - Interrupt controllers and IRQ routings + * - Coalesced MMIO zones + * - Device bindings (VFIO/Eventfds) + * - Active paging or guest registers state + * - etc + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kvm_mm.h" + +static bool kvm_luo_can_preserve(struct liveupdate_file_handler *handler, + struct file *file) +{ + return file_is_kvm(file); +} + +static int kvm_luo_preserve(struct liveupdate_file_op_args *args) +{ + DECLARE_KHOSER_PTR(sd, struct kvm_luo_ser *); + struct kvm *kvm = args->file->private_data; + struct kvm_luo_ser *ser; + + if (kvm->vm_dead || kvm->vm_bugged) + return -EINVAL; + + ser = kho_alloc_preserve(sizeof(*ser)); + if (IS_ERR(ser)) + return PTR_ERR(ser); + +#if defined(CONFIG_X86) + ser->type = kvm->arch.vm_type; +#elif defined(CONFIG_ARM64) + ser->type = kvm_phys_shift(&kvm->arch.mmu); + if (kvm_vm_is_protected(kvm)) + ser->type |= KVM_VM_TYPE_ARM_PROTECTED; + +#else + ser->type = 0; +#endif + + KHOSER_STORE_PTR(sd, ser); + KHOSER_COPY_TYPEUNSAFE(args->serialized_data, sd); + + return 0; +} + +static atomic_t restored_vm_id = ATOMIC_INIT(0); + +static int kvm_luo_retrieve(struct liveupdate_file_op_args *args) +{ + char fdname[ITOA_MAX_LEN + 1]; + struct kvm_luo_ser *ser; + struct file *file; + struct kvm *kvm; + int err = 0; + + ser = KHOSER_LOAD_PTR(args->serialized_data); + if (!ser) + return -EINVAL; + + snprintf(fdname, sizeof(fdname), "%d", + atomic_inc_return(&restored_vm_id)); + + file = kvm_create_vm_file(ser->type, fdname); + if (IS_ERR(file)) { + err = PTR_ERR(file); + goto err_free_ser; + } + + kvm = file->private_data; + + args->file = file; + kho_restore_free(ser); + + kvm_uevent_notify_vm_create(kvm); + return 0; + +err_free_ser: + kho_restore_free(ser); + return err; +} + +static void kvm_luo_unpreserve(struct liveupdate_file_op_args *args) +{ + struct kvm_luo_ser *ser; + + /* + * in case preservation failed, args->serialized_data will + * be NULL and kvm_luo_preserve takes care of cleaning up. + * If preserve succeeds, this condition fails and unpreserve + * function takes care of cleaning up. + */ + ser = KHOSER_LOAD_PTR(args->serialized_data); + if (WARN_ON_ONCE(!ser)) + return; + + kho_unpreserve_free(ser); +} + +static void kvm_luo_finish(struct liveupdate_file_op_args *args) +{ + struct kvm_luo_ser *ser; + + /* + * If retrieve_status is true or set to error, nothing to do here. + * Already cleaned up in kvm_luo_retrieve(). + */ + if (args->retrieve_status) + return; + + ser = KHOSER_LOAD_PTR(args->serialized_data); + if (!ser) + return; + + kho_restore_free(ser); +} + +static const struct liveupdate_file_ops kvm_luo_file_ops = { + .can_preserve = kvm_luo_can_preserve, + .preserve = kvm_luo_preserve, + .retrieve = kvm_luo_retrieve, + .unpreserve = kvm_luo_unpreserve, + .finish = kvm_luo_finish, + .owner = THIS_MODULE, +}; + +static struct liveupdate_file_handler kvm_luo_handler = { + .ops = &kvm_luo_file_ops, + .compatible = KVM_LUO_FH_COMPATIBLE, +}; + +int kvm_luo_init(void) +{ + int err = liveupdate_register_file_handler(&kvm_luo_handler); + + if (err && err != -EOPNOTSUPP) { + pr_err("Could not register kvm_vm_luo handler: %pe\n", ERR_PTR(err)); + return err; + } + + return 0; +} + +void kvm_luo_exit(void) +{ + liveupdate_unregister_file_handler(&kvm_luo_handler); +} + diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 14c3254..d9c3dd1 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -6577,6 +6577,10 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module) if (r) goto err_virt; + r = kvm_luo_init(); + if (r) + goto err_luo; + /* * Registration _must_ be the very last thing done, as this exposes * /dev/kvm to userspace, i.e. all infrastructure must be setup! @@ -6590,6 +6594,8 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module) return 0; err_register: + kvm_luo_exit(); +err_luo: kvm_uninit_virtualization(); err_virt: kvm_gmem_exit(); @@ -6619,6 +6625,8 @@ void kvm_exit(void) */ misc_deregister(&kvm_dev); + kvm_luo_exit(); + kvm_uninit_virtualization(); debugfs_remove_recursive(kvm_debugfs_dir); diff --git a/virt/kvm/kvm_mm.h b/virt/kvm/kvm_mm.h index 6241617..8719871 100644 --- a/virt/kvm/kvm_mm.h +++ b/virt/kvm/kvm_mm.h @@ -100,4 +100,12 @@ static inline void kvm_gmem_unbind(struct kvm_memory_slot *slot) } #endif /* CONFIG_KVM_GUEST_MEMFD */ +#ifdef CONFIG_LIVEUPDATE_GUEST_MEMFD +int kvm_luo_init(void); +void kvm_luo_exit(void); +#else +static inline int kvm_luo_init(void) { return 0; } +static inline void kvm_luo_exit(void) {} +#endif /* CONFIG_LIVEUPDATE_GUEST_MEMFD */ + #endif /* __KVM_MM_H__ */ -- 2.55.0.rc0.786.g65d90a0328-goog