Linux Documentation
 help / color / mirror / Atom feed
From: Tarun Sahu <tarunsahu@google.com>
To: ackerleytng@google.com, fuad.tabba@linux.dev,
	 Andrew Morton <akpm@linux-foundation.org>,
	seanjc@google.com, dmatlack@google.com,
	 Shuah Khan <skhan@linuxfoundation.org>,
	Jonathan Corbet <corbet@lwn.net>,
	david@redhat.com,  Tarun Sahu <tarunsahu@google.com>,
	Pasha Tatashin <pasha.tatashin@soleen.com>,
	 Pratyush Yadav <pratyush@kernel.org>,
	sagis@google.com, Paolo Bonzini <pbonzini@redhat.com>,
	 Mike Rapoport <rppt@kernel.org>,
	Alexander Graf <graf@amazon.com>
Cc: linux-kselftest@vger.kernel.org, andre.przywara@arm.com,
	 michael.roth@amd.com, linux-kernel@vger.kernel.org,
	linux-mm@kvack.org,  will@kernel.org, vannapurve@google.com,
	maz@kernel.org, fvdl@google.com,  kvm@vger.kernel.org,
	oliver.upton@linux.dev, kvmarm@lists.linux.dev,
	 alexandru.elisei@arm.com, skhawaja@google.com,
	aneesh.kumar@kernel.org,  linux-doc@vger.kernel.org,
	David Hildenbrand <david@kernel.org>,
	yan.y.zhao@intel.com,  kexec@lists.infradead.org,
	suzuki.poulose@arm.com
Subject: [PATCH v4 11/11] KVM: selftests: Add guest_memfd_preservation_test
Date: Tue, 28 Jul 2026 12:11:38 +0000	[thread overview]
Message-ID: <20260728121138.1103610-12-tarunsahu@google.com> (raw)
In-Reply-To: <20260728121138.1103610-1-tarunsahu@google.com>

Add guest_memfd_preservation_test to verify that KVM VM state and guest
memory backed by guest_memfd are preserved across a kexec reboot via Live
Update Orchestrator (LUO).

This test includes multiple tests
- (A) Test to preserve non-guest_memfd, non-memfd which must fail (/dev/null)
- (B) Test to preserve guest_memfd with no INIT_SHARED flag which must fail
- (C) Test to allocate the guest_memfd memory after preservation because
  preservation makes the guest_memfd frozen. Which must fail as well.
- (D) Test to verify guest_memfd with INIT_SHARED flag preservation across
  kexec: Below is the details of stages in this test.

In Stage 1 (pre-kexec), create a VM with a guest_memfd memory slot, run guest
code to write a deterministic pattern into guest_memfd, and preserve both
the VM and guest_memfd file descriptors via LUO. This stage also tests
A, B and C. A, B and C do not require stage2 so they will finish in
stage 1 only.

In Stage 2 (post-kexec), retrieve the preserved VM and guest_memfd file
descriptors, reconstruct the VM using vm_create_from_fd(), re-map the
retrieved guest_memfd, and execute guest code to verify data integrity
against the original pattern.

Example usage:
  $ ./guest_memfd_preservation_test --s 1
  $ <kexec>
  $ ./guest_memfd_preservation_test --s 2

Signed-off-by: Tarun Sahu <tarunsahu@google.com>
---
 MAINTAINERS                                   |   1 +
 tools/testing/selftests/kvm/Makefile.kvm      |   6 +-
 .../kvm/guest_memfd_preservation_test.c       | 357 ++++++++++++++++++
 3 files changed, 363 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/kvm/guest_memfd_preservation_test.c

diff --git a/MAINTAINERS b/MAINTAINERS
index c032f9a0451b..df764e430d25 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14549,6 +14549,7 @@ L:	kvm@vger.kernel.org
 S:	Maintained
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git
 F:	Documentation/liveupdate/vmm.rst
+F:	tools/testing/selftests/kvm/guest_memfd_preservation_test.c
 F:	virt/kvm/guest_memfd_luo.c
 F:	virt/kvm/kvm_luo.c
 
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 4ace12606e93..02cfd7fc718e 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -165,6 +165,8 @@ TEST_GEN_PROGS_x86 += pre_fault_memory_test
 
 # Compiled outputs used by test targets
 TEST_GEN_PROGS_EXTENDED_x86 += x86/nx_huge_pages_test
+# Manual test that forks a persistent background daemon; skip auto CI run
+TEST_GEN_PROGS_EXTENDED_x86 += guest_memfd_preservation_test
 
 TEST_GEN_PROGS_arm64 = $(TEST_GEN_PROGS_COMMON)
 TEST_GEN_PROGS_arm64 += arm64/aarch32_id_regs
@@ -259,6 +261,7 @@ OVERRIDE_TARGETS = 1
 # which causes the environment variable to override the makefile).
 include ../lib.mk
 include ../cgroup/lib/libcgroup.mk
+include ../liveupdate/lib/libliveupdate.mk
 
 INSTALL_HDR_PATH = $(top_srcdir)/usr
 LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/
@@ -313,7 +316,8 @@ LIBKVM_S := $(filter %.S,$(LIBKVM))
 LIBKVM_C_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_C))
 LIBKVM_S_OBJ := $(patsubst %.S, $(OUTPUT)/%.o, $(LIBKVM_S))
 LIBKVM_STRING_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_STRING))
-LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ) $(LIBCGROUP_O)
+LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ) \
+						$(LIBCGROUP_O) $(LIBLIVEUPDATE_O)
 SPLIT_TEST_GEN_PROGS := $(patsubst %, $(OUTPUT)/%, $(SPLIT_TESTS))
 SPLIT_TEST_GEN_OBJ := $(patsubst %, $(OUTPUT)/$(ARCH)/%.o, $(SPLIT_TESTS))
 
diff --git a/tools/testing/selftests/kvm/guest_memfd_preservation_test.c b/tools/testing/selftests/kvm/guest_memfd_preservation_test.c
new file mode 100644
index 000000000000..b790f2529837
--- /dev/null
+++ b/tools/testing/selftests/kvm/guest_memfd_preservation_test.c
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026, Google LLC.
+ *
+ * Author: Tarun Sahu <tarunsahu@google.com>
+ *
+ * Test for VM and guest_memfd preservation across kexec (Live Update) via LUO.
+ *
+ * NOTE: This is a MANUAL test and is excluded from automated CI/testing
+ * frameworks because Stage 1 daemonizes into the background to pin resources
+ * and requires a human operator to manually trigger kexec before Stage 2
+ * is executed. Running Stage 1 automatically would leak the background daemon
+ * and cause CI runners to falsely interpret it as a passed test.
+ *
+ * Usage:
+ * Stage 1: ./guest_memfd_preservation_test --s 1
+ * Stage 2: ./guest_memfd_preservation_test --s 2
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/sizes.h>
+#include <linux/falloc.h>
+
+#include "kvm_util.h"
+#include "processor.h"
+#include "test_util.h"
+#include "ucall_common.h"
+#include "../kselftest.h"
+#include "../kselftest_harness.h"
+
+#include <libliveupdate.h>
+
+#define TEST_PASSED(fmt, ...) ksft_print_msg(fmt, ##__VA_ARGS__)
+
+#define SESSION_NAME "gmem_vm_preservation_session"
+#define VM_TOKEN 0x1001
+#define GMEM_TOKEN 0x1002
+
+#define STATE_SESSION_NAME "gmem_preservation_state"
+#define STATE_TOKEN 0x999
+
+#define UNSHARED_GMEM_TOKEN 0x9001
+#define MMAP_ONLY_GMEM_TOKEN 0x9002
+#define NON_GMEM_TOKEN 0x9003
+#define FROZEN_GMEM_TOKEN 0x8888
+
+#define GPA SZ_4G
+#define GMEM_MEM_SLOT 1
+#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)
+{
+	uint8_t *mem = (uint8_t *)gpa;
+
+	for (size_t i = 0; i < DATA_SIZE; i++)
+		mem[i] = get_pattern_byte(i);
+
+	GUEST_DONE();
+}
+
+static void guest_code_phase2(uint64_t gpa)
+{
+	uint8_t *mem = (uint8_t *)gpa;
+
+	for (size_t 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 setup_guest_memfd_region(struct kvm_vm *vm, int gmem_fd)
+{
+	vm_set_user_memory_region2(vm, GMEM_MEM_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);
+}
+
+static void test_preserve_disallowed_no_init_shared(int session_fd,
+						    struct kvm_vm *vm)
+{
+	int unshared_fd, ret;
+
+	ksft_print_msg("[STAGE 1] TEST 1: Preserving guest_memfd without INIT_SHARED...\n");
+
+	unshared_fd = __vm_create_guest_memfd(vm, GMEM_SIZE, 0);
+	if (unshared_fd >= 0) {
+		ret = luo_session_preserve_fd(session_fd, unshared_fd, UNSHARED_GMEM_TOKEN);
+		TEST_ASSERT(ret < 0,
+			    "Preservation without INIT_SHARED should fail");
+		close(unshared_fd);
+	}
+	TEST_PASSED("[STAGE 1] TEST 1: PASSED\n");
+}
+
+static void test_preserve_disallowed_mmap_only(int session_fd,
+						struct kvm_vm *vm)
+{
+	int mmap_only_fd, ret;
+
+	if (!(vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS) &
+	      GUEST_MEMFD_FLAG_MMAP))
+		return;
+
+	ksft_print_msg("[STAGE 1] TEST 2: Preserving guest_memfd with MMAP only...\n");
+
+	mmap_only_fd = __vm_create_guest_memfd(vm, GMEM_SIZE,
+					       GUEST_MEMFD_FLAG_MMAP);
+	if (mmap_only_fd >= 0) {
+		ret = luo_session_preserve_fd(session_fd, mmap_only_fd, MMAP_ONLY_GMEM_TOKEN);
+		TEST_ASSERT(ret < 0,
+			    "Preserving guest_memfd with MMAP only should fail");
+		close(mmap_only_fd);
+	}
+	TEST_PASSED("[STAGE 1] TEST 2: PASSED\n");
+}
+
+static void test_preserve_disallowed_non_gmem(int session_fd)
+{
+	int null_fd, ret;
+
+	ksft_print_msg("[STAGE 1] TEST 3: Preserving non-guest_memfd FD (/dev/null)...\n");
+
+	null_fd = open("/dev/null", O_RDWR);
+	if (null_fd >= 0) {
+		ret = luo_session_preserve_fd(session_fd, null_fd, NON_GMEM_TOKEN);
+		TEST_ASSERT(ret < 0,
+			    "Preserving /dev/null should fail");
+		close(null_fd);
+	}
+	TEST_PASSED("[STAGE 1] TEST 3: PASSED\n");
+}
+
+static void test_allocate_while_frozen(int luo_fd, struct kvm_vm *vm)
+{
+	int frozen_session, frozen_fd, ret;
+	uint64_t flags;
+	char *mem;
+
+	flags = GUEST_MEMFD_FLAG_MMAP | GUEST_MEMFD_FLAG_INIT_SHARED;
+	if ((vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS) & flags) != flags)
+		return;
+
+	ksft_print_msg("[STAGE 1] TEST 4: Operations on frozen guest_memfd...\n");
+
+	frozen_session = luo_create_session(luo_fd, "session_frozen_ops");
+	TEST_ASSERT(frozen_session >= 0, "Failed to create frozen test session");
+
+	frozen_fd = __vm_create_guest_memfd(vm, GMEM_SIZE, flags);
+	TEST_ASSERT(frozen_fd >= 0, "Failed to create guest_memfd for frozen test");
+
+	mem = kvm_mmap(GMEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, frozen_fd);
+	mem[0] = get_pattern_byte(0);
+	kvm_munmap(mem, GMEM_SIZE);
+
+	ret = luo_session_preserve_fd(frozen_session, frozen_fd, FROZEN_GMEM_TOKEN);
+	TEST_ASSERT(ret == 0, "Failed to preserve guest_memfd for frozen test");
+
+	ret = fallocate(frozen_fd, FALLOC_FL_KEEP_SIZE, DATA_SIZE, page_size);
+	TEST_ASSERT(ret == -1 && errno == EPERM,
+		    "fallocate on frozen guest_memfd failed ret=%d errno=%d",
+		    ret, errno);
+
+	ret = fallocate(frozen_fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+			0, page_size);
+	TEST_ASSERT(ret == -1 && errno == EPERM,
+		    "fallocate punch hole on frozen guest_memfd failed ret=%d errno=%d",
+		    ret, errno);
+
+	mem = kvm_mmap(GMEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, frozen_fd);
+
+	TEST_ASSERT_EQ(READ_ONCE(mem[0]), get_pattern_byte(0));
+	TEST_EXPECT_SIGBUS((void)READ_ONCE(mem[DATA_SIZE]));
+
+	kvm_munmap(mem, GMEM_SIZE);
+
+	luo_session_finish(frozen_session);
+	close(frozen_session);
+	close(frozen_fd);
+
+	TEST_PASSED("[STAGE 1] TEST 4: PASSED\n");
+}
+
+static void test_gmem_preservation_stage1(int session_fd, struct kvm_vm *vm,
+					   struct kvm_vcpu *vcpu, int *gmem_fd)
+{
+	uint64_t flags = GUEST_MEMFD_FLAG_MMAP | GUEST_MEMFD_FLAG_INIT_SHARED;
+	int fd, ret;
+
+	ksft_print_msg("[STAGE 1] TEST 5: Preserving VM and guest_memfd...\n");
+
+	fd = vm_create_guest_memfd(vm, GMEM_SIZE, flags);
+	setup_guest_memfd_region(vm, fd);
+
+	vcpu_args_set(vcpu, 1, GPA);
+	vcpu_run(vcpu);
+	TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE);
+
+	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, fd, GMEM_TOKEN);
+	TEST_ASSERT(ret == 0, "Failed to preserve guest_memfd file descriptor");
+
+	*gmem_fd = fd;
+}
+
+static void test_gmem_preservation_stage2(int retrieved_vm_fd,
+					   int retrieved_gmem_fd)
+{
+	struct userspace_mem_region *slot0;
+	struct vm_shape shape = VM_SHAPE_DEFAULT;
+	u64 nr_pages = 2048; /* 8MB for slot0 pages */
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	int i;
+
+	ksft_print_msg("[STAGE 2] TEST 5 (cont): Verifying VM & guest_memfd data...\n");
+
+	vm = vm_create_from_fd(retrieved_vm_fd, shape);
+
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0,
+				    nr_pages, 0);
+	kvm_vm_elf_load(vm, program_invocation_name);
+
+	for (i = 0; i < NR_MEM_REGIONS; i++)
+		vm->memslots[i] = 0;
+
+	slot0 = memslot2region(vm, 0);
+	ucall_init(vm, slot0->region.guest_phys_addr +
+		       slot0->region.memory_size);
+
+	setup_guest_memfd_region(vm, retrieved_gmem_fd);
+
+	vcpu = vm_vcpu_add(vm, 0, guest_code_phase2);
+	kvm_arch_vm_finalize_vcpus(vm);
+
+	vcpu_args_set(vcpu, 1, GPA);
+
+	printf("Resuming / Running VM in Phase 2...\n");
+	vcpu_run(vcpu);
+	TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE);
+
+	/* kvm_vm_free will also close retrieved_vm_fd */
+	kvm_vm_free(vm);
+	TEST_PASSED("[STAGE 2] TEST 5: PASSED\n");
+}
+
+static void run_stage_1(int luo_fd)
+{
+	int gmem_fd, session_fd;
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+
+	ksft_print_msg("[STAGE 1] Starting pre-kexec setup...\n");
+
+	ksft_print_msg("[STAGE 1] Creating state file for next stage (2)...\n");
+	create_state_file(luo_fd, STATE_SESSION_NAME, STATE_TOKEN, 2);
+
+	vm = __vm_create_shape_with_one_vcpu(VM_SHAPE_DEFAULT, &vcpu, 1,
+					guest_code_phase1);
+
+	ksft_print_msg("[STAGE 1] Creating session '%s' and preserving FDs...\n",
+		       SESSION_NAME);
+	session_fd = luo_create_session(luo_fd, SESSION_NAME);
+	TEST_ASSERT(session_fd >= 0, "Failed to create LUO session");
+
+	/* Run negative tests for disallowed preservation conditions */
+	test_preserve_disallowed_no_init_shared(session_fd, vm);
+	test_preserve_disallowed_mmap_only(session_fd, vm);
+	test_preserve_disallowed_non_gmem(session_fd);
+
+	/* Run operations on frozen guest_memfd test independently */
+	test_allocate_while_frozen(luo_fd, vm);
+
+	/* Run primary VM & guest_memfd preservation test */
+	test_gmem_preservation_stage1(session_fd, vm, vcpu, &gmem_fd);
+
+	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");
+
+	close(luo_fd);
+	daemonize_and_wait();
+}
+
+static void run_stage_2(int luo_fd, int state_session_fd)
+{
+	int retrieved_vm_fd, retrieved_gmem_fd, session_fd, stage;
+
+	ksft_print_msg("[STAGE 2] Starting post-kexec verification...\n");
+
+	restore_and_read_stage(state_session_fd, STATE_TOKEN, &stage);
+	if (stage != 2)
+		fail_exit("Expected stage 2, but state file contains %d", stage);
+
+	ksft_print_msg("[STAGE 2] Retrieving session '%s'...\n", SESSION_NAME);
+	session_fd = luo_retrieve_session(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");
+
+	/* Run primary VM & guest_memfd post-kexec data verification */
+	test_gmem_preservation_stage2(retrieved_vm_fd, retrieved_gmem_fd);
+
+	printf("\nSUCCESS: Phase 2 Complete! All 5MB complex data verified intact!\n");
+
+	luo_session_finish(session_fd);
+	close(session_fd);
+
+	ksft_print_msg("[STAGE 2] Finalizing state session...\n");
+	if (luo_session_finish(state_session_fd) < 0)
+		fail_exit("luo_session_finish for state session");
+	close(state_session_fd);
+
+	close(retrieved_gmem_fd);
+}
+
+int main(int argc, char *argv[])
+{
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_GUEST_MEMFD));
+	page_size = getpagesize();
+
+	return luo_test(argc, argv, STATE_SESSION_NAME,
+			run_stage_1, run_stage_2);
+}
-- 
2.55.0.229.g6434b31f56-goog


      parent reply	other threads:[~2026-07-28 12:11 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-28 12:11 [PATCH v4 00/11] liveupdate: kvm: Guest_memfd preservation Tarun Sahu
2026-07-28 12:11 ` [PATCH v4 01/11] liveupdate: Add LIVEUPDATE_GUEST_MEMFD config option Tarun Sahu
2026-07-28 12:11 ` [PATCH v4 02/11] KVM: Introduce kvm_create_vm_file() helper Tarun Sahu
2026-07-28 12:11 ` [PATCH v4 03/11] KVM: Export kvm_uevent_notify_vm_create() Tarun Sahu
2026-07-28 12:11 ` [PATCH v4 04/11] KVM: Track weak reference to vm_file in struct kvm Tarun Sahu
2026-07-28 12:11 ` [PATCH v4 05/11] KVM: LUO: Support VM preservation across live updates Tarun Sahu
2026-07-28 12:11 ` [PATCH v4 06/11] KVM: guest_memfd: Move internal definitions to internal header Tarun Sahu
2026-07-28 12:11 ` [PATCH v4 07/11] KVM: guest_memfd: Add support for freezing mappings Tarun Sahu
2026-07-28 12:11 ` [PATCH v4 08/11] KVM: guest_memfd: Add support for preservation via LUO Tarun Sahu
2026-07-28 12:11 ` [PATCH v4 09/11] docs: liveupdate: Add documentation for VM and guest_memfd preservation Tarun Sahu
2026-07-28 12:11 ` [PATCH v4 10/11] KVM: selftests: Split ____vm_create() and add vm_create_from_fd() Tarun Sahu
2026-07-28 12:11 ` Tarun Sahu [this message]

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=20260728121138.1103610-12-tarunsahu@google.com \
    --to=tarunsahu@google.com \
    --cc=ackerleytng@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=alexandru.elisei@arm.com \
    --cc=andre.przywara@arm.com \
    --cc=aneesh.kumar@kernel.org \
    --cc=corbet@lwn.net \
    --cc=david@kernel.org \
    --cc=david@redhat.com \
    --cc=dmatlack@google.com \
    --cc=fuad.tabba@linux.dev \
    --cc=fvdl@google.com \
    --cc=graf@amazon.com \
    --cc=kexec@lists.infradead.org \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=maz@kernel.org \
    --cc=michael.roth@amd.com \
    --cc=oliver.upton@linux.dev \
    --cc=pasha.tatashin@soleen.com \
    --cc=pbonzini@redhat.com \
    --cc=pratyush@kernel.org \
    --cc=rppt@kernel.org \
    --cc=sagis@google.com \
    --cc=seanjc@google.com \
    --cc=skhan@linuxfoundation.org \
    --cc=skhawaja@google.com \
    --cc=suzuki.poulose@arm.com \
    --cc=vannapurve@google.com \
    --cc=will@kernel.org \
    --cc=yan.y.zhao@intel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox