From nobody Thu Apr 9 11:15:04 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7F66039E6C4; Mon, 9 Mar 2026 11:54:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057293; cv=none; b=liqsQz17mKLhUFvRQP0BOI6hoZOlFI0uXS6Y1XIMpru058cfbX58txxpNmKrg1z0emr/D1r3sUj54S+GjTzJWy0wJKrO2tTTH7tUBv7F/cq6h/RG4UKCxbIPEXc3xuyOOL26ny6DuEJLrFIP5QvNZ0rOF+GUt6zMTgMe7Je7M/s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057293; c=relaxed/simple; bh=dv/kbGgCScvzX+VINvVvCUHC1AHbYmECjaCbqTlfAsI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qWhCSyHiIT3XP+Z0FapN6uL5llAKS6+tCCfBY8pqdG+rFNOYiGyepDXq08GzTtdKTKLjyKSM3DDfQGEadrmk/pStBcml2Ka37L0ahRgrLQXlSYPiTNeGBa+bRq4EZ417h38oJiFJdy/Stlm1C50ogZkNf3UaAENRkjh0EDrPWCA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QdRW6ZzK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QdRW6ZzK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7B4A7C2BCB0; Mon, 9 Mar 2026 11:54:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773057293; bh=dv/kbGgCScvzX+VINvVvCUHC1AHbYmECjaCbqTlfAsI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QdRW6ZzKPvM1Ns6+2p0lvKAMpE0RLu0wOtgXUj+oduazNRj6Twou+nxnPz6miimer 9Wjfn+JFs1AzaWmo4sguLDjSnoKsVDRzxrZlBAQkud8p2Gs4v/NIyiSYJRhZVChtfu 6N2CQFTIskLmov4Nn7Pk/jm0AxlfAg2a07L8m/zz4pPWKLlTFzl9DV4ZUKPRmweszo vRbHWgX/7X+ZK7fMj3j1BeGSG62kXZw5Sbi0BrQtWQqsVJfk5v0fwo2BpU6eogWK90 kCQ9mxUVUTYIKE2pHg3Qlgi2QE3bDUtwQWEpOOEmu9c+3QJ/P+2G19PbiN5luSvvdw 9BM5cjNtcOa5w== From: Pratyush Yadav To: Pasha Tatashin , Mike Rapoport , Pratyush Yadav , Shuah Khan , Andrew Morton Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org Subject: [PATCH 1/6] selftests/liveupdate: add framework for memfd tests Date: Mon, 9 Mar 2026 11:54:34 +0000 Message-ID: <20260309115441.266805-2-pratyush@kernel.org> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog In-Reply-To: <20260309115441.266805-1-pratyush@kernel.org> References: <20260309115441.266805-1-pratyush@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Pratyush Yadav (Google)" Currently memfd preservation using LUO is only tested indirectly via the luo_multi_session or luo_kexec_simple tests. Their main purpose is to test other live update functionality. Add a framework for writing memfd tests. The framework hooks into the kselftest harness, but adds some things on top to make it suitable for live update. The LUO FD (/dev/liveupdate) can only be opened by one process at a time. Each test runs in its own process. This means the LUO FD must be owned by the main process and shared to children. main() opens the LUO FD and shares it to child runners using a global variable. Live update tests run in two stages. One before kexec and one after. Detect the stage using a special state session. If the session is present, it means the test is in post-kexec state. Additionally, take in an optional --stage argument that lets callers specify expected stage. This is useful as a safety net to catch LUO core failures. If LUO core fails to preserve the state session properly, this option can help detect this and fail early. Since the option is not recognized by the kselftest harness, remove it from argv before calling test_harness_run(). Signed-off-by: Pratyush Yadav (Google) Reviewed-by: Mike Rapoport (Microsoft) --- tools/testing/selftests/liveupdate/Makefile | 1 + .../testing/selftests/liveupdate/luo_memfd.c | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 tools/testing/selftests/liveupdate/luo_memfd.c diff --git a/tools/testing/selftests/liveupdate/Makefile b/tools/testing/se= lftests/liveupdate/Makefile index 080754787ede..051daae55eec 100644 --- a/tools/testing/selftests/liveupdate/Makefile +++ b/tools/testing/selftests/liveupdate/Makefile @@ -6,6 +6,7 @@ TEST_GEN_PROGS +=3D liveupdate =20 TEST_GEN_PROGS_EXTENDED +=3D luo_kexec_simple TEST_GEN_PROGS_EXTENDED +=3D luo_multi_session +TEST_GEN_PROGS_EXTENDED +=3D luo_memfd =20 TEST_FILES +=3D do_kexec.sh =20 diff --git a/tools/testing/selftests/liveupdate/luo_memfd.c b/tools/testing= /selftests/liveupdate/luo_memfd.c new file mode 100644 index 000000000000..b779eee18387 --- /dev/null +++ b/tools/testing/selftests/liveupdate/luo_memfd.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2026, Google LLC. + * Pratyush Yadav (Google) + */ + +/* + * Selftests for memfd preservation via LUO. + */ + +#include +#include +#include +#include +#include + +#include + +#include "../kselftest.h" +#include "../kselftest_harness.h" + +#include "luo_test_utils.h" + +#define STATE_SESSION_NAME "luo-state" +#define STATE_MEMFD_TOKEN 1 + +#define LIVEUPDATE_DEV "/dev/liveupdate" +static int luo_fd =3D -1, stage; + +int main(int argc, char *argv[]) +{ + int session, expected_stage =3D 0; + + /* + * The test takes an optional --stage argument. This lets callers + * provide the expected stage, and if that doesn't match the test errors + * out. + * + * Look for the stage. Since test_harness_run() doesn't recognize it, + * once found, remove it from argv. + */ + for (int i =3D 1; i < argc; i++) { + if (strcmp(argv[i], "--stage") =3D=3D 0) { + if (i + 1 < argc) { + expected_stage =3D atoi(argv[i + 1]); + memmove(&argv[i], &argv[i + 2], (argc - i - 1) * sizeof(char *)); + argc -=3D 2; + i--; + } else { + ksft_exit_fail_msg("Option --stage requires an argument\n"); + } + } + } + + luo_fd =3D luo_open_device(); + if (luo_fd < 0) + ksft_exit_skip("Failed to open %s (%s). Is the luo module loaded?\n", + strerror(errno), LUO_DEVICE); + + session =3D luo_retrieve_session(luo_fd, STATE_SESSION_NAME); + if (session =3D=3D -ENOENT) + stage =3D 1; + else if (session >=3D 0) + stage =3D 2; + else + fail_exit("Failed to check for state session"); + + if (expected_stage && expected_stage !=3D stage) + ksft_exit_fail_msg("Stage mismatch: expected %d, got %d\n", + expected_stage, stage); + + if (stage =3D=3D 1) + create_state_file(luo_fd, STATE_SESSION_NAME, STATE_MEMFD_TOKEN, 2); + + test_harness_run(argc, argv); +} --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 11:15:04 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 939E13A7F52; Mon, 9 Mar 2026 11:54:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057295; cv=none; b=JTdNreDlzvWvD4CEgHB47KPsdxPEo6n8V+1LehaCAVVASBAUDyGeaKncojWteXIxp+FVMEoBx9kuIcFVC/j6FfTMpLEUb15yzPWHYqqihAdvTFZNtdYTF/4OjTnsd8gTqhamnmOsMSnvhC+W+7i/0R7hslgaU1w00tFPYzixQYI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057295; c=relaxed/simple; bh=PghrAoUWQBw2NUIGa/NJWkd6SAFY/nFx+VVc64+OWJE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dt6gvMVdJMWaaOpwXKlSdud/M5VbhCgBdJvKx5W/MrTicsDTO3UsZBqvfQwMDYJyKe0HmGrFtOjE8BHCEYX8lJAXEPUvleDKaV4/Wo0Lm4g005Km5MoPXsNXVty4f3/mBPIeg4q9Lq2tJVB/hdCuS650pt0KMUqG2SMmv7YojNg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TNUsru5j; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TNUsru5j" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 941C6C2BC9E; Mon, 9 Mar 2026 11:54:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773057295; bh=PghrAoUWQBw2NUIGa/NJWkd6SAFY/nFx+VVc64+OWJE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TNUsru5jubWi2MbJKJBuu3usla6/Z1udHfgghCkcSPNQPkz7iUVrHtG3JgprG2w+D a9KONyqqvjdcrsjH4N3Ulg80eqb5X6+2AFZotV2egl2jzV/qaHBGMfm+2vdPWZRXmN e3Hg91eeplQkzr5L1XtSYd+bHogb7SZfHcsoXLD0zXHhV2hqLuX+n9p1A77p6Imasa V+HqEqiAkvyUVN25DP0hP+bso+5VZGiLNkC4jVO8vtgOu+Kuiq512MCw2M9Hn+27+i kfzQa7S6sRGIIJ8KIBj+pT5VqxXsFH8mHZx6VM2AE6ohvd120npMtjV6IBjvRssl0b yKqT3B0U4pSpQ== From: Pratyush Yadav To: Pasha Tatashin , Mike Rapoport , Pratyush Yadav , Shuah Khan , Andrew Morton Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org Subject: [PATCH 2/6] selftests/liveupdate: add helper functions for memfd tests Date: Mon, 9 Mar 2026 11:54:35 +0000 Message-ID: <20260309115441.266805-3-pratyush@kernel.org> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog In-Reply-To: <20260309115441.266805-1-pratyush@kernel.org> References: <20260309115441.266805-1-pratyush@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Pratyush Yadav (Google)" Add some helper functions that will be used by memfd tests. This moves some of the complexity out of the test itself, which results in better test readability and less code duplication. Signed-off-by: Pratyush Yadav Signed-off-by: Pratyush Yadav (Google) Reviewed-by: Mike Rapoport (Microsoft) --- .../selftests/liveupdate/luo_test_utils.c | 175 +++++++++++++++++- .../selftests/liveupdate/luo_test_utils.h | 9 + 2 files changed, 183 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.c b/tools/te= sting/selftests/liveupdate/luo_test_utils.c index 3c8721c505df..45ace3697ee6 100644 --- a/tools/testing/selftests/liveupdate/luo_test_utils.c +++ b/tools/testing/selftests/liveupdate/luo_test_utils.c @@ -1,8 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only =20 /* - * Copyright (c) 2025, Google LLC. + * Copyright (c) 2025-2026, Google LLC. * Pasha Tatashin + * Pratyush Yadav (Google) + * + * Copyright (C) 2025 Amazon.com Inc. or its affiliates. + * Pratyush Yadav */ =20 #define _GNU_SOURCE @@ -23,6 +27,175 @@ =20 #include "luo_test_utils.h" =20 +/* Read exactly specified size from fd. Any less results in error. */ +int read_size(int fd, char *buffer, size_t size) +{ + size_t remain =3D size; + ssize_t bytes_read; + + while (remain) { + bytes_read =3D read(fd, buffer, remain); + if (bytes_read =3D=3D 0) + return -ENODATA; + if (bytes_read < 0) + return -errno; + + remain -=3D bytes_read; + } + + return 0; +} + +/* Write exactly specified size from fd. Any less results in error. */ +int write_size(int fd, const char *buffer, size_t size) +{ + size_t remain =3D size; + ssize_t written; + + while (remain) { + written =3D write(fd, buffer, remain); + if (written =3D=3D 0) + return -EIO; + if (written < 0) + return -errno; + + remain -=3D written; + } + + return 0; +} + +int generate_random_data(char *buffer, size_t size) +{ + int fd, ret; + + fd =3D open("/dev/urandom", O_RDONLY); + if (fd < 0) + return -errno; + + ret =3D read_size(fd, buffer, size); + close(fd); + return ret; +} + +int save_test_data(const char *filename, const char *buffer, size_t size) +{ + int fd, ret; + + fd =3D open(filename, O_RDWR | O_CREAT, 0666); + if (fd < 0) + return -errno; + + ret =3D write_size(fd, buffer, size); + fsync(fd); + close(fd); + return ret; +} + +int load_test_data(const char *filename, char *buffer, size_t size) +{ + int fd, ret; + + fd =3D open(filename, O_RDONLY); + if (fd < 0) + return -errno; + + ret =3D read_size(fd, buffer, size); + close(fd); + return ret; +} + +/* Create and initialize a memfd with random data. */ +int create_random_memfd(const char *memfd_name, char *buffer, size_t size) +{ + int fd; + int ret; + + fd =3D memfd_create(memfd_name, 0); + if (fd < 0) + return -errno; + + ret =3D generate_random_data(buffer, size); + if (ret < 0) { + close(fd); + return ret; + } + + if (write_size(fd, buffer, size) < 0) { + close(fd); + return -errno; + } + + /* Reset file position to beginning */ + if (lseek(fd, 0, SEEK_SET) < 0) { + close(fd); + return -errno; + } + + return fd; +} + +/* + * Make sure fd contains expected data up to size. Returns 0 on success, 1= on + * data mismatch, -errno on error. + */ +int verify_fd_content(int fd, const char *expected_data, size_t size) +{ + char *buffer; + int ret; + + buffer =3D malloc(size); + if (!buffer) + return -ENOMEM; + + /* Reset file position to beginning */ + if (lseek(fd, 0, SEEK_SET) < 0) { + ret =3D -errno; + goto out; + } + + ret =3D read_size(fd, buffer, size); + if (ret < 0) + goto out; + + if (memcmp(buffer, expected_data, size) !=3D 0) { + ret =3D 1; + goto out; + } + + ret =3D 0; + +out: + free(buffer); + return ret; +} + +/* + * Verify fd content using mmap. Returns 0 on success, 1 on data mismatch, + * -errno on error. + */ +int verify_fd_content_mmap(int fd, const char *expected_data, size_t size) +{ + char *mapped_mem; + int ret; + + mapped_mem =3D mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (mapped_mem =3D=3D MAP_FAILED) + return -errno; + + /* ret =3D memcmp(mapped_mem, expected_data, size) ? 1 : 0; */ + ret =3D 0; + for (size_t i =3D 0; i < size; i++) { + if (mapped_mem[i] !=3D expected_data[i]) { + ret =3D 1; + break; + } + } + + munmap(mapped_mem, size); + return ret; +} + int luo_open_device(void) { return open(LUO_DEVICE, O_RDWR); diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.h b/tools/te= sting/selftests/liveupdate/luo_test_utils.h index 90099bf49577..d1b85703708b 100644 --- a/tools/testing/selftests/liveupdate/luo_test_utils.h +++ b/tools/testing/selftests/liveupdate/luo_test_utils.h @@ -35,6 +35,15 @@ void restore_and_read_stage(int state_session_fd, int to= ken, int *stage); =20 void daemonize_and_wait(void); =20 +int read_size(int fd, char *buffer, size_t size); +int write_size(int fd, const char *buffer, size_t size); +int generate_random_data(char *buffer, size_t size); +int save_test_data(const char *filename, const char *buffer, size_t size); +int load_test_data(const char *filename, char *buffer, size_t size); +int create_random_memfd(const char *memfd_name, char *buffer, size_t size); +int verify_fd_content(int fd, const char *expected_data, size_t size); +int verify_fd_content_mmap(int fd, const char *expected_data, size_t size); + typedef void (*luo_test_stage1_fn)(int luo_fd); typedef void (*luo_test_stage2_fn)(int luo_fd, int state_session_fd); =20 --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 11:15:04 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BD17C3A7855; Mon, 9 Mar 2026 11:54:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057297; cv=none; b=fcbMhVIWSNikLprOO6b0kT201hpVzJqWZiW6jzHerB00IQmNEVU+Rw+kpihuGNjSP7gVpFv9BRmpfx05qLgAU1uoLQicWAJLIOIlHBWl27EDqEMHVxdhYV/nGYLgTYyHepyjC+77ahgi0adQYLsVRJACZ/Zhk5bx2c8YCUquoHY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057297; c=relaxed/simple; bh=aukVArEnfq1vpcp1oDLYNMSSeQUJHmSNYgjjmrkbTRU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Mg/oaUvAWO+S7wYXCeTj+T8gD47fyte8oeeUVRiMFLqU+LhnqyrqPG+ncETwIZnE96PFmmm0S+hf9YSSoTYJau//WpY7eDNpbaurBspUI66JVK+0wAd6vMWEnbHWIUL7NyTW05fJMVOw8Qws8MTbmj+aBNn64puR6FTL6Iubc9o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=h+V272oD; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="h+V272oD" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AEF58C2BCB3; Mon, 9 Mar 2026 11:54:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773057297; bh=aukVArEnfq1vpcp1oDLYNMSSeQUJHmSNYgjjmrkbTRU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=h+V272oDbkvOesj7cS1BfEoE2WszM4TfVldXlBBN7FHsPHmmU1wSSAeLBK4g024Lr Gp0Zz69XpjGr2mm4qQzw2Q/KWj1A8kp9Qjj7BwCGbqcMEAVdolh0wrKtv9gshb4cgn kn//cXAoPr5C3IBPgHPPKEDX77h3VqoU7F/ztuqNtnWtM5eGZpwV5y51Fus0UjEkh6 Lf0bh5McIuQz6HfUyCP9D80ZWjOzFIXQmLTxMphUxFh6H/yYy4gnbC0ykCxnUe1GA+ pasfd3hbqDrfdrWUsRrzJb1/rod++t47KYmNqYtC4LjX1LZgUplCKuZP+8wifeZNmX AUQg612eBKvGg== From: Pratyush Yadav To: Pasha Tatashin , Mike Rapoport , Pratyush Yadav , Shuah Khan , Andrew Morton Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org Subject: [PATCH 3/6] selftests/liveupdate: add test for memfd content preservation Date: Mon, 9 Mar 2026 11:54:36 +0000 Message-ID: <20260309115441.266805-4-pratyush@kernel.org> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog In-Reply-To: <20260309115441.266805-1-pratyush@kernel.org> References: <20260309115441.266805-1-pratyush@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Pratyush Yadav (Google)" Add a selftest that makes sure the contents of a memfd are correctly preserved across a live update. In stage 1, create a memfd and fill it with random data, and preserve it. Save the random data to the file system. This will be used by stage 2 to verify the contents are correct. In stage 2, retrieve the memfd and compare its contents with the contents saved on the file system. Signed-off-by: Pratyush Yadav Signed-off-by: Pratyush Yadav (Google) --- tools/testing/selftests/liveupdate/Makefile | 1 + .../testing/selftests/liveupdate/luo_memfd.c | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/tools/testing/selftests/liveupdate/Makefile b/tools/testing/se= lftests/liveupdate/Makefile index 051daae55eec..8e2eb6500c07 100644 --- a/tools/testing/selftests/liveupdate/Makefile +++ b/tools/testing/selftests/liveupdate/Makefile @@ -13,6 +13,7 @@ TEST_FILES +=3D do_kexec.sh include ../lib.mk =20 CFLAGS +=3D $(KHDR_INCLUDES) +CFLAGS +=3D -I$(top_srcdir)/tools/include CFLAGS +=3D -Wall -O2 -Wno-unused-function CFLAGS +=3D -MD =20 diff --git a/tools/testing/selftests/liveupdate/luo_memfd.c b/tools/testing= /selftests/liveupdate/luo_memfd.c index b779eee18387..52b5f6b16e19 100644 --- a/tools/testing/selftests/liveupdate/luo_memfd.c +++ b/tools/testing/selftests/liveupdate/luo_memfd.c @@ -3,6 +3,9 @@ /* * Copyright (c) 2026, Google LLC. * Pratyush Yadav (Google) + * + * Copyright (C) 2025 Amazon.com Inc. or its affiliates. + * Pratyush Yadav */ =20 /* @@ -11,11 +14,14 @@ =20 #include #include +#include #include #include +#include #include =20 #include +#include =20 #include "../kselftest.h" #include "../kselftest_harness.h" @@ -25,9 +31,64 @@ #define STATE_SESSION_NAME "luo-state" #define STATE_MEMFD_TOKEN 1 =20 +#define MEMFD_DATA_SESSION_NAME "memfd_data_session" +#define MEMFD_DATA_TOKEN 1 +#define MEMFD_DATA_BUFFER_SIZE SZ_1M +#define RANDOM_DATA_FILE "luo_random_data.bin" + #define LIVEUPDATE_DEV "/dev/liveupdate" static int luo_fd =3D -1, stage; =20 +/* + * Test that a memfd with its data is preserved across live update. + */ +TEST(memfd_data) +{ + int fd, session; + char *buffer; + struct liveupdate_session_preserve_fd preserve_arg =3D { .size =3D sizeof= (preserve_arg) }; + struct liveupdate_session_retrieve_fd retrieve_arg =3D { .size =3D sizeof= (retrieve_arg) }; + + buffer =3D malloc(MEMFD_DATA_BUFFER_SIZE); + ASSERT_NE(buffer, NULL); + + switch (stage) { + case 1: + session =3D luo_create_session(luo_fd, MEMFD_DATA_SESSION_NAME); + ASSERT_GE(session, 0); + + fd =3D create_random_memfd("memfd_data", buffer, MEMFD_DATA_BUFFER_SIZE); + ASSERT_GE(fd, 0); + + ASSERT_EQ(save_test_data(RANDOM_DATA_FILE, buffer, MEMFD_DATA_BUFFER_SIZ= E), 0); + + preserve_arg.fd =3D fd; + preserve_arg.token =3D MEMFD_DATA_TOKEN; + ASSERT_GE(ioctl(session, LIVEUPDATE_SESSION_PRESERVE_FD, &preserve_arg),= 0); + + daemonize_and_wait(); + break; + case 2: + session =3D luo_retrieve_session(luo_fd, MEMFD_DATA_SESSION_NAME); + ASSERT_GE(session, 0); + + ASSERT_EQ(load_test_data(RANDOM_DATA_FILE, buffer, MEMFD_DATA_BUFFER_SIZ= E), 0); + + retrieve_arg.token =3D MEMFD_DATA_TOKEN; + ASSERT_GE(ioctl(session, LIVEUPDATE_SESSION_RETRIEVE_FD, &retrieve_arg),= 0); + fd =3D retrieve_arg.fd; + ASSERT_GE(fd, 0); + + ASSERT_EQ(verify_fd_content(fd, buffer, MEMFD_DATA_BUFFER_SIZE), 0); + + ASSERT_EQ(luo_session_finish(session), 0); + break; + default: + TH_LOG("Unknown stage %d\n", stage); + ASSERT_FALSE(true); + } +} + int main(int argc, char *argv[]) { int session, expected_stage =3D 0; --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 11:15:04 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D3AC13A5E92; Mon, 9 Mar 2026 11:54:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057299; cv=none; b=C+Z680hh2Rhgow02X2YkrmfYfxdt+/N1IJjwC9pj6XQrJGllXkXjlUSGq9NQq3ca93uNXjMjQ1AZuHGMYNwyVr1oiPolN6sroUdNu6DPr+rA6OBIm2nHxcRgzt1C11q7L/TVGHBglLM1Bk/Mvs3aT2ii82DIkcXwZu6vDBkku8A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057299; c=relaxed/simple; bh=msGcB9Zdx1CYUYZUlEY30sJksrgQfdKtvara48aboNQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CxofEVEXBCu1NFSGfeLKx4GMkDRzoMzgBMyLGBm495bA2XK9QNdIRUBGabdR56nAyU0MnlXSXPNJ33U1TmGGAIfjtG110K+9z2H0WUp0XTL1aniBoneAvBHTHAav61u7G2I4t6aAUnGiGL8IIK5nv23GB0JdOXwkYs9zylhOkPs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QZfhSkk8; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QZfhSkk8" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C98EDC2BCAF; Mon, 9 Mar 2026 11:54:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773057299; bh=msGcB9Zdx1CYUYZUlEY30sJksrgQfdKtvara48aboNQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QZfhSkk80LQ6XowDTBUIF3gokRcMP3Ia+WyiGmzRrKoTsE+ulPe3hhNaMNFdb3Bnz MGw4164XZfzKQElbg4BliKe5j9VgSCGmLRFRdqEg7QFnmJd44jT/M2hqM6pveB/qkY 4wbmtpy7l4bs6HbunVsPhH0R1AmZVXG9LrUEc4yLYh8hIx4QO5IP0JyenXnOijf1yi rIZxJphhLRnPzYsiHdCxIq071i6hfltkTIJ0TSFMEecIXdbhK8dRU54ZmfmFFyatk7 LVgBXH3NpE3d84tuLBNPPg0QiW5aNdJCnhAJDYdUwvLqvTOjVbJxaquMekC564M0nl L5l1J05HSfLDA== From: Pratyush Yadav To: Pasha Tatashin , Mike Rapoport , Pratyush Yadav , Shuah Khan , Andrew Morton Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org Subject: [PATCH 4/6] selftests/liveupdate: add test for zero-size memfd preservation Date: Mon, 9 Mar 2026 11:54:37 +0000 Message-ID: <20260309115441.266805-5-pratyush@kernel.org> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog In-Reply-To: <20260309115441.266805-1-pratyush@kernel.org> References: <20260309115441.266805-1-pratyush@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Pratyush Yadav (Google)" A zero-size memfd is a special case of memfd preservation. It takes a different path from normal both during preservation and during restore. In the serialization structure, the number of folios if zero and the vmalloc array with folios is empty. The restore logic should check for this and make sure to not touch the invalid array. Add a test to make sure this path works as expected. In stage 1, the test creates and preserves a memfd without any data. In stage 2, the test retrieves the memfd and makes sure it is still without data. Signed-off-by: Pratyush Yadav (Google) Reviewed-by: Mike Rapoport (Microsoft) --- .../testing/selftests/liveupdate/luo_memfd.c | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tools/testing/selftests/liveupdate/luo_memfd.c b/tools/testing= /selftests/liveupdate/luo_memfd.c index 52b5f6b16e19..56106cd09978 100644 --- a/tools/testing/selftests/liveupdate/luo_memfd.c +++ b/tools/testing/selftests/liveupdate/luo_memfd.c @@ -36,6 +36,9 @@ #define MEMFD_DATA_BUFFER_SIZE SZ_1M #define RANDOM_DATA_FILE "luo_random_data.bin" =20 +#define ZERO_SESSION_NAME "zero_session" +#define ZERO_MEMFD_TOKEN 1 + #define LIVEUPDATE_DEV "/dev/liveupdate" static int luo_fd =3D -1, stage; =20 @@ -89,6 +92,50 @@ TEST(memfd_data) } } =20 +/* + * Test that a zero-sized memfd is preserved across live update. + */ +TEST(zero_memfd) +{ + int zero_fd, session; + struct liveupdate_session_preserve_fd preserve_arg =3D { .size =3D sizeof= (preserve_arg) }; + struct liveupdate_session_retrieve_fd retrieve_arg =3D { .size =3D sizeof= (retrieve_arg) }; + + switch (stage) { + case 1: + session =3D luo_create_session(luo_fd, ZERO_SESSION_NAME); + ASSERT_GE(session, 0); + + zero_fd =3D memfd_create("zero_memfd", 0); + ASSERT_GE(zero_fd, 0); + + preserve_arg.fd =3D zero_fd; + preserve_arg.token =3D ZERO_MEMFD_TOKEN; + ASSERT_GE(ioctl(session, LIVEUPDATE_SESSION_PRESERVE_FD, &preserve_arg),= 0); + + close(zero_fd); + daemonize_and_wait(); + break; + case 2: + session =3D luo_retrieve_session(luo_fd, ZERO_SESSION_NAME); + ASSERT_GE(session, 0); + + retrieve_arg.token =3D ZERO_MEMFD_TOKEN; + ASSERT_GE(ioctl(session, LIVEUPDATE_SESSION_RETRIEVE_FD, &retrieve_arg),= 0); + zero_fd =3D retrieve_arg.fd; + ASSERT_GE(zero_fd, 0); + + ASSERT_EQ(lseek(zero_fd, 0, SEEK_END), 0); + + ASSERT_EQ(luo_session_finish(session), 0); + close(zero_fd); + break; + default: + TH_LOG("Unknown stage %d\n", stage); + ASSERT_FALSE(true); + } +} + int main(int argc, char *argv[]) { int session, expected_stage =3D 0; --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 11:15:04 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 53D453A8727; Mon, 9 Mar 2026 11:55:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057302; cv=none; b=CjROXa+2qH8MR1Bx1wxCmYC1i9B5TWC3tCnB3AZW86VMjNjbPqJrz1+BpKxjhaU7TeEpglWqlMrXhF71EouhEVKrixeAzJ3E3zS9bv+mxtR6acIC+WGpcK/vW4wvvIILAxMm4nzikcIe2+PyDyPIE0DBZJJwVCHkFtHRzaa9rBo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057302; c=relaxed/simple; bh=hQMT5ZnC+kM/6V8s8lr4xcjgalTDxyHP1vCCvJobalc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KQ0DETCog253l9Dc+ZMt6+jhar8k4UvezRw634Ckwel1VNMqMgbT8kkmy4sw5maRh9jhSfGLcZeqxI2Ppf7CH5B8J9u52gDtNzQW6icV1TEJ2QrLzaFDTh5aAs5DWc2JkPUhlnY7pxswUmY7WiYtuJPVbTIkFTGSa+2PEudG5dM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=j82uKpnm; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="j82uKpnm" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E261CC2BC86; Mon, 9 Mar 2026 11:54:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773057301; bh=hQMT5ZnC+kM/6V8s8lr4xcjgalTDxyHP1vCCvJobalc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=j82uKpnmoFrUvTTCkoOY17tPF5sZCZegqhK196oh4IOsYj3uxdMJQPO+xEB8+B3Jv EUVZElGrUZiu/ZK/gUwawNjkf8ZO9XtmtVH2FxLFvzTDmoEAOknwNOUPN1rT1Z/Geh kiIeGzV/ncOGHcFH2dHL22L53TeXvzNulh8dW1JBHbPAWb5C2WSU2SMiexIjc76usk iNLRP6UHbVU7hXOaUT+d2nO6Utvc0hFkdGQs0N+6emPi85eiI1/BCZCRlcgTqBmM/W Gdd2vlVAO+vxY+41HKbZSqnKWprM5Fw58Qt2XgG2P5j6lL+kV46PQFpGwUONvGVdx4 8b0CfuywmTEog== From: Pratyush Yadav To: Pasha Tatashin , Mike Rapoport , Pratyush Yadav , Shuah Khan , Andrew Morton Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org Subject: [PATCH 5/6] selftests/liveupdate: add test for operations on a preserved memfd Date: Mon, 9 Mar 2026 11:54:38 +0000 Message-ID: <20260309115441.266805-6-pratyush@kernel.org> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog In-Reply-To: <20260309115441.266805-1-pratyush@kernel.org> References: <20260309115441.266805-1-pratyush@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Pratyush Yadav (Google)" Once a memfd is preserved, certain operations are not allowed to succeed since they might make the state of the memfd inconsistent with the serialized state. Among these operations are truncating or growing the memfd. Writes and reads to already existing memfd should succeed. Add a test that makes sure a preserved memfd does not allow growing or shrinking, but does allow reads and writes to existing memory to go thorough. Signed-off-by: Pratyush Yadav Signed-off-by: Pratyush Yadav (Google) Reviewed-by: Mike Rapoport (Microsoft) --- .../testing/selftests/liveupdate/luo_memfd.c | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tools/testing/selftests/liveupdate/luo_memfd.c b/tools/testing= /selftests/liveupdate/luo_memfd.c index 56106cd09978..75f88101e7b5 100644 --- a/tools/testing/selftests/liveupdate/luo_memfd.c +++ b/tools/testing/selftests/liveupdate/luo_memfd.c @@ -39,6 +39,10 @@ #define ZERO_SESSION_NAME "zero_session" #define ZERO_MEMFD_TOKEN 1 =20 +#define PRESERVED_SESSION_NAME "preserved_session" +#define PRESERVED_MEMFD_TOKEN 1 +#define PRESERVED_BUFFER_SIZE SZ_1M + #define LIVEUPDATE_DEV "/dev/liveupdate" static int luo_fd =3D -1, stage; =20 @@ -136,6 +140,59 @@ TEST(zero_memfd) } } =20 +/* + * Test that preserved memfd can't grow or shrink, but reads and writes st= ill + * work. + */ +TEST(preserved_ops) +{ + char write_buffer[128] =3D {'A'}; + int fd, session; + char *buffer; + struct liveupdate_session_preserve_fd preserve_arg =3D { .size =3D sizeof= (preserve_arg) }; + + if (stage !=3D 1) + SKIP(return, "test only expected to run on stage 1"); + + buffer =3D malloc(PRESERVED_BUFFER_SIZE); + ASSERT_NE(buffer, NULL); + + session =3D luo_create_session(luo_fd, PRESERVED_SESSION_NAME); + ASSERT_GE(session, 0); + + fd =3D create_random_memfd("preserved_memfd", buffer, PRESERVED_BUFFER_SI= ZE); + ASSERT_GE(fd, 0); + + preserve_arg.fd =3D fd; + preserve_arg.token =3D PRESERVED_MEMFD_TOKEN; + ASSERT_GE(ioctl(session, LIVEUPDATE_SESSION_PRESERVE_FD, &preserve_arg), = 0); + + /* + * Write to the preserved memfd (within existing size). This should + * work. + */ + ASSERT_GE(lseek(fd, 0, SEEK_SET), 0); + /* Write buffer is smaller than total file size. */ + ASSERT_EQ(write_size(fd, write_buffer, sizeof(write_buffer)), 0); + ASSERT_EQ(verify_fd_content(fd, write_buffer, sizeof(write_buffer)), 0); + + /* Try to grow the file using write(). */ + + /* First, seek to one byte behind initial size. */ + ASSERT_GE(lseek(fd, PRESERVED_BUFFER_SIZE - 1, SEEK_SET), 0); + + /* + * Then, write some data that should increase the file size. This should + * fail. + */ + ASSERT_LT(write_size(fd, write_buffer, sizeof(write_buffer)), 0); + ASSERT_EQ(lseek(fd, 0, SEEK_END), PRESERVED_BUFFER_SIZE); + + /* Try to shrink the file using truncate. This should also fail. */ + ASSERT_LT(ftruncate(fd, PRESERVED_BUFFER_SIZE / 2), 0); + ASSERT_EQ(lseek(fd, 0, SEEK_END), PRESERVED_BUFFER_SIZE); +} + int main(int argc, char *argv[]) { int session, expected_stage =3D 0; --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 11:15:04 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F6DF3A8FF0; Mon, 9 Mar 2026 11:55:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057304; cv=none; b=t15GO/RGxPTzshYICoXrs+QM8IjrUZhnScCZbxHCmPUhD13EuJO3ucEi+GjbbLyOw1SKshJ0r7FlEG56NgcrHEts9PqET978dbPxTCPLb8THRGNbCHg/XystZ+uJw5xZM51RN31eZ/XKrlDpMtYXtpJNxkfRN7PY5ZnAT3QOJJk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773057304; c=relaxed/simple; bh=6RXZOME/fI1l63GcOwoRovNmREiLIcVnjWmc5XmjY64=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=O3w6Li3Jsar20NpjznS6SW8hQuRy4swDfHPiThS58LemgvLM0CQq+J8HfgS8ugMOx+cv6DueImmQv8lf6OKhVlyxsnv0XCx/Cdim3L+DJb45sYs7yyq/jq1gGGpKXExvDmT9pPoCEQPT8lKd2ZZgqwslMFaIfTuDo2Vrsc/UVwg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TQZeh5kB; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TQZeh5kB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 310F8C2BCB2; Mon, 9 Mar 2026 11:55:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773057303; bh=6RXZOME/fI1l63GcOwoRovNmREiLIcVnjWmc5XmjY64=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TQZeh5kBgJ/ZWCqVNeQ+F4HO+HIquSD9vTuIBzKtqtBEJCvEmmR4KehU8FiXOZgIw OWN6/YnE2DKORuQd4J510m65RqNhfsY0aq6DzmuyBsCg+mNThgyIblpncAJeItvys7 Z1tttz52Y9an2AkpwGj1DtiILYbeyrci6kIOY4+3ebU7AByEMbxutKT3/o8hXu++2z SRfn55ud3pVBsW0pzL9AwwZ3PgAPTRWA+SIs4otVWV+v5RDcZGVlqxlLoWogEdC1Pr hkZh8aBQTZTR0azHl5joWDugVJzWStVNhYnklEeDloS3Kg3fJvwPTq9x2hTMagSkvD QDRdcGjvTcTzA== From: Pratyush Yadav To: Pasha Tatashin , Mike Rapoport , Pratyush Yadav , Shuah Khan , Andrew Morton Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org Subject: [PATCH 6/6] selftests/liveupdate: add fallocate test for memfd Date: Mon, 9 Mar 2026 11:54:39 +0000 Message-ID: <20260309115441.266805-7-pratyush@kernel.org> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog In-Reply-To: <20260309115441.266805-1-pratyush@kernel.org> References: <20260309115441.266805-1-pratyush@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Pratyush Yadav (Google)" When memory is added to a memfd via fallocate(), it does not get zeroed immediately. This is tracked by the absence of the uptodate folio flag. Initially, memfd preservation simply saved the folio flags at preserve time. This led to a bug, where all writes to un-initialized fallocated memory after preserve were lost after live update. This is fixed by patch [0] (not in mainline as of writing this). Add a test that fallocates some memory in a memfd, preserves it, writes to it. Then in stage 2 it verifies the written content is still present. [0] https://lore.kernel.org/linux-mm/20260223173931.2221759-2-pratyush@kern= el.org/ Signed-off-by: Pratyush Yadav (Google) Reviewed-by: Mike Rapoport (Microsoft) --- .../testing/selftests/liveupdate/luo_memfd.c | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tools/testing/selftests/liveupdate/luo_memfd.c b/tools/testing= /selftests/liveupdate/luo_memfd.c index 75f88101e7b5..dde3c78db50e 100644 --- a/tools/testing/selftests/liveupdate/luo_memfd.c +++ b/tools/testing/selftests/liveupdate/luo_memfd.c @@ -43,6 +43,11 @@ #define PRESERVED_MEMFD_TOKEN 1 #define PRESERVED_BUFFER_SIZE SZ_1M =20 +#define FALLOCATE_SESSION_NAME "fallocate_session" +#define FALLOCATE_MEMFD_TOKEN 1 +#define FALLOCATE_BUFFER_SIZE SZ_1M +#define RANDOM_DATA_FILE_FALLOCATE "luo_random_data_fallocate.bin" + #define LIVEUPDATE_DEV "/dev/liveupdate" static int luo_fd =3D -1, stage; =20 @@ -193,6 +198,65 @@ TEST(preserved_ops) ASSERT_EQ(lseek(fd, 0, SEEK_END), PRESERVED_BUFFER_SIZE); } =20 +/* + * Test that an fallocated memfd is preserved across live update and can be + * written to after being preserved. + */ +TEST(fallocate_memfd) +{ + int fd, session; + char *buffer; + struct liveupdate_session_preserve_fd preserve_arg =3D { .size =3D sizeof= (preserve_arg) }; + struct liveupdate_session_retrieve_fd retrieve_arg =3D { .size =3D sizeof= (retrieve_arg) }; + + buffer =3D malloc(FALLOCATE_BUFFER_SIZE); + ASSERT_NE(buffer, NULL); + + switch (stage) { + case 1: + session =3D luo_create_session(luo_fd, FALLOCATE_SESSION_NAME); + ASSERT_GE(session, 0); + + fd =3D memfd_create("fallocate_memfd", 0); + ASSERT_GE(fd, 0); + + /* Fallocate memory but do not write to it yet */ + ASSERT_EQ(fallocate(fd, 0, 0, FALLOCATE_BUFFER_SIZE), 0); + + preserve_arg.fd =3D fd; + preserve_arg.token =3D FALLOCATE_MEMFD_TOKEN; + ASSERT_GE(ioctl(session, LIVEUPDATE_SESSION_PRESERVE_FD, &preserve_arg),= 0); + + /* Now write to it after preserving */ + ASSERT_GE(generate_random_data(buffer, FALLOCATE_BUFFER_SIZE), 0); + ASSERT_EQ(save_test_data(RANDOM_DATA_FILE_FALLOCATE, buffer, FALLOCATE_B= UFFER_SIZE), 0); + + ASSERT_GE(lseek(fd, 0, SEEK_SET), 0); + ASSERT_EQ(write_size(fd, buffer, FALLOCATE_BUFFER_SIZE), 0); + + daemonize_and_wait(); + break; + case 2: + session =3D luo_retrieve_session(luo_fd, FALLOCATE_SESSION_NAME); + ASSERT_GE(session, 0); + + ASSERT_EQ(load_test_data(RANDOM_DATA_FILE_FALLOCATE, buffer, FALLOCATE_B= UFFER_SIZE), 0); + + retrieve_arg.token =3D FALLOCATE_MEMFD_TOKEN; + ASSERT_GE(ioctl(session, LIVEUPDATE_SESSION_RETRIEVE_FD, &retrieve_arg),= 0); + fd =3D retrieve_arg.fd; + ASSERT_GE(fd, 0); + + ASSERT_EQ(verify_fd_content(fd, buffer, FALLOCATE_BUFFER_SIZE), 0); + + ASSERT_EQ(luo_session_finish(session), 0); + break; + default: + TH_LOG("Unknown stage %d\n", stage); + ASSERT_FALSE(true); + } +} + int main(int argc, char *argv[]) { int session, expected_stage =3D 0; --=20 2.53.0.473.g4a7958ca14-goog