From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-dl1-f45.google.com (mail-dl1-f45.google.com [74.125.82.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D24A1643B for ; Mon, 22 Jun 2026 23:01:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=74.125.82.45 ARC-Seal:i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782169296; cv=pass; b=I1T6VYPwne6tYY1tpKE87wLkm42yYRupfyO/aB6kBzSussOT+jzyXgh9Ztppc3Q1kMWo81TdgGbH5OokoKU/ORyw2Dk/YJ7f9IzfnUOJwzSEkCOv91Dv7XItSlg5eQEwjOLn6Mrf6i6gqs1con1nhljIPxTMw7orxVq1OjfstOw= ARC-Message-Signature:i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782169296; c=relaxed/simple; bh=BWQPMoKQOTeGkRSmowzT6uGFQN8jRHlTD1UMypmkjkw=; h=From:In-Reply-To:References:MIME-Version:Date:Message-ID:Subject: To:Cc:Content-Type; b=X0RJmPpgi5kY6wSXaw1S0Tg6WEFRyAm5vTsOTKaNlofw4if7q7yr1x3G1TXEhH0m10J/G4kDWrNlw0FCsBhIzqYX27whKhBjrHOZQrme5d3RE2gIdbci32oECSJ0kiWpXEddnbpjomtly2ScMRofhgIdGoPRX+ReSb5yEjGX7Og= ARC-Authentication-Results:i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=hQ5ArTg5; arc=pass smtp.client-ip=74.125.82.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="hQ5ArTg5" Received: by mail-dl1-f45.google.com with SMTP id a92af1059eb24-1384eb94d20so11946118c88.1 for ; Mon, 22 Jun 2026 16:01:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1782169294; cv=none; d=google.com; s=arc-20240605; b=aYr0HgkCa9EY9x3ip3px4m7enPaXfNJb41R3yeQQ642Rlblo0OPjqFlgKKzj1axwLB oPsok3iW1PHqXyx5s6EeQfA91tKuRe6/hNI4BVf34pnT27/nr0hGkzDKW/4RNyZGjmGM YYsKjw/zeR0F1bZST9w/gqYLroqyej3Shcbv9hmvXCC47wa1ZxdRk+5veGhjp8sqVdbU 6SSoIU24Hu6TZAfcMGOsC+qjOhxmjbZDzaGfRqO2UC50A7UNGPjco1JSSP3YhJzt0QUb +96AhjfuJGaLg/e7uslbDnfMyhmdkotc9xZXBEo/EslYuF99d9av64YrZq4FO4VfYdog w0EA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:mime-version:references:in-reply-to :from:dkim-signature; bh=Se78T3ehOJrnIX6EVHqhbA3McVgxD20iSWZ28XYCDdw=; fh=rdoJtuwfZioBHHO26ka/jUJLXoN25lgfltu/Ds5i7X8=; b=WZLekOkE2vsJjb2+//I1ObJdqsYZO3l7Ysss01tIxrahbyMM1mYPXXxU+PY4MylGqe jP5sCdKJLwV0vbyf1g8m0/yvO9yygldVQqrwS62iCLRoFSJUDgevolABjGQCEij/zfIo D+m631ZacJgnMQxXbuo7fIHTpHi/8yQ2XjEVx/PAwDeDyS8BCgpQJWZqm3bhLKV+ncNf OoKntIbjGCtVQH+CEiLlqXWPDtKHZKHfgzkm4AA87vmxBZq4dHOyEKFUmCLpii2ruI2m 86oiR7sYtogB/Sgg1+z4ghTvLnm6naY3SIXsOObMsMo0SoQ4AHkq8GzhGW/Tnyl7xjJe M2Xw==; darn=vger.kernel.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1782169294; x=1782774094; darn=vger.kernel.org; h=cc:to:subject:message-id:date:mime-version:references:in-reply-to :from:from:to:cc:subject:date:message-id:reply-to; bh=Se78T3ehOJrnIX6EVHqhbA3McVgxD20iSWZ28XYCDdw=; b=hQ5ArTg5XGxCJHfOdIAcgVkEzKgWkrdxkJbbNGv+gr4IcPaNZhb5VnfCKOLxedvtcP zt4e+JVJXVk7YlPldZUftjmYgnKC78UfmkrrRn4ZfgHj2HXK0CbOhAGc9r23qscShAGo 4gtVTDHZpRydJx0/2FEGhfHtdgFa0+mJrhJ7l7tYqKRp1iDMfmmpbk1BaN4KagbDuyeC 6DJPPSFqb/n1LK3OhgOdr7Xoj3civzFe0/oSXjigGaQCfF9J0aVWj3CcuTt/adVJC/Qu 7eMMCiBapIHMdyAZ3Sfweiu2yWkeeEbJ79UYjpShn4823piYNO3LlCAXq8yuljjN2tmf zyBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782169294; x=1782774094; h=cc:to:subject:message-id:date:mime-version:references:in-reply-to :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=Se78T3ehOJrnIX6EVHqhbA3McVgxD20iSWZ28XYCDdw=; b=dRQd6Xu1fJO7ctxLdIgCPOvdALFH+Y1To1XpKxbGkDHOnaHLows0pcpFEVkMAZ6qP9 AA+e78I4oxElwhwHaNrw7MEpmHnigNmmXCblrpxKE7sKivI+Cx13kaqUagJsE9yE58OD l64kAzAshV0r71TZUq2t8uZfi6Cg939qYWllTFQyBSyfjIjEb/DBcyPFJ2+MwBeDms5G /t6tMSQ9qan6ru4GJ7cyPd65GeZv8PgPSQ37BNx14Jxo+LN39/+vwPKGIF8Aqk23moas grkY3VohYTJCYRKuBoZeJrrZhIajRJsP+lO6ENhG/89Vroa2DG+gt7PrJXfk0BY8u8yT w6qg== X-Forwarded-Encrypted: i=1; AFNElJ/kdNaqM/4SL9NcFGJnki+rHbZqByxW9FMqNifmwci8jyQydJJMQReXBva64Tjjdqn4mQE5RGrJos/jPKg=@vger.kernel.org X-Gm-Message-State: AOJu0YwDyQkYhVVUsws1nUo7qO0fZkuTZAMWPiZQK0gHkpFhRp7ZD9q5 2HpDGHxHqRNegUxvJFYBbBe4ZHORJwNK3b7XMz5JSBwFOwcIivf+f0P1IsEhvIoChPlKXJP5jEq /xbEMKkjnVEj4lP2cjicAHHW+Zksay5HiUGi56shz X-Gm-Gg: AfdE7ckLTIKJ3tgPG/niXXtrb92K7vhlFBxpKRI43EAODLK9IITjnmQHjXE3pRJxdzh 68YL8ar7Pnkd/33+NPvNW+BMKh52LdwtZCygI8TtwfOkpkaYXyTsWA+Ph/rfr/KdEyqnyvSK7kf u7s71gbqKuRctX8OcBZuF8lR4zuB4hMnC5SIY+9jqP/DfucVhghRZKxnOyt5rSRvuEwKUdYNnnT +z/ogSZ1PtEuJwvz50Oefv0hBl5mNPHxwhWAtHE4J1v0loXtvc8tygqPqCyxtJKuzeN1ZOw3VXt VSu58BiLKtepoTJwDx2BU/FyY5lEoMMfTHr9J4nMUZCPwYvSJWozU9i90iY= X-Received: by 2002:a05:7022:78c:b0:137:938a:1044 with SMTP id a92af1059eb24-139a216738cmr11302655c88.33.1782169292599; Mon, 22 Jun 2026 16:01:32 -0700 (PDT) Received: from 176938342045 named unknown by gmailapi.google.com with HTTPREST; Mon, 22 Jun 2026 16:01:31 -0700 Received: from 176938342045 named unknown by gmailapi.google.com with HTTPREST; Mon, 22 Jun 2026 16:01:31 -0700 From: Ackerley Tng In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Date: Mon, 22 Jun 2026 16:01:31 -0700 X-Gm-Features: AVVi8Cfmvsh-tLhJUbMrgpAzFVY6IGOEzbMnkY3GArVYdQhVqbDKG-2CuMgaTr4 Message-ID: Subject: Re: [RFC PATCH v2 10/10] selftests: kvm: Add guest_memfd_preservation_test To: Tarun Sahu , Jonathan Corbet , vannapurve@google.com, fvdl@google.com, Pasha Tatashin , Shuah Khan , sagis@google.com, aneesh.kumar@kernel.org, skhawaja@google.com, vipinsh@google.com, Pratyush Yadav , david@redhat.com, dmatlack@google.com, mark.rutland@arm.com, Paolo Bonzini , Mike Rapoport , Alexander Graf , seanjc@google.com, axelrasmussen@google.com Cc: linux-kselftest@vger.kernel.org, kexec@lists.infradead.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, kvm@vger.kernel.org, linux-mm@kvack.org Content-Type: text/plain; charset="UTF-8" Tarun Sahu writes: > Add a new KVM selftest `guest_memfd_preservation_test` to verify that > guest memory backed by guest_memfd is preserved properly. > Don't think using backticks in commit messages is a common practice but I might be wrong here. > The test leverages the Live Update Orchestrator (LUO) infrastructure > to validate that memory folios and configuration layouts are > successfully saved and then restored during kernel live updates, > preventing any memory loss for the guest. > > Here, I have used the kvm selftests framework by creating a new > vm and mapping two memory slots to it. One is the code that is executed > inside the vm and other is the guest_memfd whose memory is being > written by the guest code. > Don't think commit messages with "I" are common either > In Phase 1: Once data is written the vm exits and wait for the user > to trigger the kexec. > > In Phase 2: A new vm is created with retrieved kvm and again two > memory slots are assigned. Once for guest code, and another is for > retrieved guest_memfd where guest_memfd memory is verified by the > executed guest code. If verification succeeds, The test passes. > > > [...snip...] > > +#define SESSION_NAME "gmem_vm_preservation_session" > +#define VM_TOKEN 0x1001 > +#define GMEM_TOKEN 0x1002 > + > +#define GMEM_SIZE (16ULL * 1024 * 1024) > +#define DATA_SIZE (5ULL * 1024 * 1024) > + > +static size_t page_size; > + > +/* Deterministic byte pattern generation based on offset */ > +static inline uint8_t get_pattern_byte(size_t offset) > +{ > + return (uint8_t)(offset ^ 0x5A); > +} > + > +static void guest_code_phase1(uint64_t gpa, uint64_t size, uint64_t data_size) > +{ > + uint8_t *mem = (uint8_t *)gpa; > + size_t i; > + > + for (i = 0; i < data_size; i++) > + mem[i] = get_pattern_byte(i); > + > + GUEST_DONE(); > +} > + > +static void guest_code_phase2(uint64_t gpa, uint64_t size, uint64_t data_size) > +{ > + uint8_t *mem = (uint8_t *)gpa; > + size_t i; > + > + for (i = 0; i < data_size; i++) { > + uint8_t val = get_pattern_byte(i); > + > + __GUEST_ASSERT(mem[i] == val, > + "Data mismatch at offset %lu! Expected 0x%x, got 0x%x", > + i, val, mem[i]); > + } > + > + GUEST_DONE(); > +} > + > +static void do_phase1(void) > +{ > + uint64_t flags = GUEST_MEMFD_FLAG_MMAP | GUEST_MEMFD_FLAG_INIT_SHARED; Is there a reason to set GUEST_MEMFD_FLAG_MMAP? We're not really accessing that memory from the host in this test. > + int gmem_fd, dev_luo_fd, session_fd, ret; > + const uint64_t gpa = SZ_4G; > + struct kvm_vcpu *vcpu; > + const int slot = 1; > + struct kvm_vm *vm; > + > + vm = __vm_create_shape_with_one_vcpu(VM_SHAPE_DEFAULT, &vcpu, 1, > + guest_code_phase1); > + gmem_fd = vm_create_guest_memfd(vm, GMEM_SIZE, flags); > + vm_set_user_memory_region2(vm, slot, KVM_MEM_GUEST_MEMFD, gpa, GMEM_SIZE, NULL, > + gmem_fd, 0); > + > + for (size_t i = 0; i < GMEM_SIZE; i += page_size) > + virt_pg_map(vm, gpa + i, gpa + i); > + > + vcpu_args_set(vcpu, 3, gpa, GMEM_SIZE, DATA_SIZE); If GMEM_SIZE and DATA_SIZE are static I think we don't have to set those as vcpu_args_set(), they can be used as macros from within the guest. > + > + vcpu_run(vcpu); > + TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); > + > + dev_luo_fd = luo_open_device(); > + TEST_ASSERT(dev_luo_fd >= 0, "Failed to open /dev/liveupdate"); > + > + session_fd = luo_create_session(dev_luo_fd, SESSION_NAME); > + TEST_ASSERT(session_fd >= 0, "Failed to create LUO session"); > + > + ret = luo_session_preserve_fd(session_fd, vm->fd, VM_TOKEN); > + TEST_ASSERT(ret == 0, "Failed to preserve VM file descriptor"); > + > + ret = luo_session_preserve_fd(session_fd, gmem_fd, GMEM_TOKEN); > + TEST_ASSERT(ret == 0, "Failed to preserve guest_memfd file descriptor"); > + Thanks for showing how this works :) > + printf("\n============================================================\n"); > + printf("Phase 1 Complete Successfully!\n"); > + printf("VM file and guest_memfd file have been preserved via LUO.\n"); > + printf("Tokens: VM_TOKEN=0x%x, GMEM_TOKEN=0x%x\n", VM_TOKEN, GMEM_TOKEN); > + printf("Machine Size: %llu MB, Data Size: %llu MB\n", GMEM_SIZE / SZ_1M, > + DATA_SIZE / SZ_1M); > + printf("------------------------------------------------------------\n"); > + > + daemonize_and_wait(); > +} > + > +static struct kvm_vm *vm_create_from_fd(int resurrected_vm_fd, > + struct vm_shape shape) > +{ > + struct kvm_vm *vm; > + > + vm = calloc(1, sizeof(*vm)); > + TEST_ASSERT(vm != NULL, "Insufficient Memory"); > + > + vm_init_fields(vm, shape); What would happen if the shape was changed between preserving and restoring? > + > + vm->kvm_fd = open_path_or_exit(KVM_DEV_PATH, O_RDWR); > + vm->fd = resurrected_vm_fd; > + > + if (kvm_has_cap(KVM_CAP_BINARY_STATS_FD)) > + vm->stats.fd = vm_get_stats_fd(vm); > + else > + vm->stats.fd = -1; > + > + vm_init_memory_properties(vm); > + > + return vm; > +} > + I think vm_create_from_fd() could be introduced in an earlier patch to reduce the amount of new code in this patch. Also, I think it could perhaps be moved to kvm_util.c assuming that other test will use it too. > +static void do_phase2(void) > +{ > + int retrieved_vm_fd, retrieved_gmem_fd, dev_luo_fd, session_fd; > + struct vm_shape shape = VM_SHAPE_DEFAULT; > + const uint64_t gpa = SZ_4G; > + struct kvm_vcpu *vcpu; > + const int slot = 1; > + struct kvm_vm *vm; > + > + dev_luo_fd = luo_open_device(); > + TEST_ASSERT(dev_luo_fd >= 0, "Failed to open /dev/liveupdate"); > + > + session_fd = luo_retrieve_session(dev_luo_fd, SESSION_NAME); > + TEST_ASSERT(session_fd >= 0, "Failed to retrieve LUO session"); > + > + retrieved_vm_fd = luo_session_retrieve_fd(session_fd, VM_TOKEN); > + TEST_ASSERT(retrieved_vm_fd >= 0, "Failed to retrieve VM file descriptor"); > + > + retrieved_gmem_fd = luo_session_retrieve_fd(session_fd, GMEM_TOKEN); > + TEST_ASSERT(retrieved_gmem_fd >= 0, "Failed to retrieve guest_memfd file descriptor"); > + > + vm = vm_create_from_fd(retrieved_vm_fd, shape); > + > + u64 nr_pages = 2048; /* 8MB is plenty for slot0 pages */ > + I don't think declarations are usually mixed with regular code. > + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, nr_pages, 0); > + kvm_vm_elf_load(vm, program_invocation_name); > + > + for (int i = 0; i < NR_MEM_REGIONS; i++) > + vm->memslots[i] = 0; > + > + struct userspace_mem_region *slot0 = memslot2region(vm, 0); > + > + ucall_init(vm, slot0->region.guest_phys_addr + slot0->region.memory_size); > + > + vm_set_user_memory_region2(vm, slot, KVM_MEM_GUEST_MEMFD, gpa, GMEM_SIZE, NULL, > + retrieved_gmem_fd, 0); > + > + for (size_t i = 0; i < GMEM_SIZE; i += page_size) > + virt_pg_map(vm, gpa + i, gpa + i); > + > + vcpu = vm_vcpu_add(vm, 0, guest_code_phase2); > + kvm_arch_vm_finalize_vcpus(vm); > + > + vcpu_args_set(vcpu, 3, gpa, GMEM_SIZE, DATA_SIZE); > + > + printf("Resuming / Running VM in Phase 2...\n"); > + vcpu_run(vcpu); > + TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); > + > + printf("\nSUCCESS: Phase 2 Complete! All 5MB complex data verified intact!\n"); > + > + luo_session_finish(session_fd); > + close(session_fd); > + close(dev_luo_fd); > + /* This will also close the vm_fd */ > + kvm_vm_free(vm); > + close(retrieved_gmem_fd); > +} > + > +int main(int argc, char *argv[]) > +{ > + bool phase2 = false; > + > + TEST_REQUIRE(kvm_has_cap(KVM_CAP_GUEST_MEMFD)); > + page_size = getpagesize(); > + > + for (int i = 1; i < argc; i++) { > + if (strcmp(argv[i], "--phase2") == 0) > + phase2 = true; > + } > + Maybe use getopt() here? > + if (phase2) > + do_phase2(); > + else > + do_phase1(); > + > + return 0; > +} > -- > 2.54.0.1032.g2f8565e1d1-goog I think we also need tests for trying to allocate while frozen, and conversion while frozen, and trying to preserve while preservation is not allowed.