From: "Pratyush Yadav (Google)" <[email protected]>

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) <[email protected]>
---
 .../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"
 
+#define ZERO_SESSION_NAME "zero_session"
+#define ZERO_MEMFD_TOKEN 1
+
 #define LIVEUPDATE_DEV "/dev/liveupdate"
 static int luo_fd = -1, stage;
 
@@ -89,6 +92,50 @@ TEST(memfd_data)
        }
 }
 
+/*
+ * 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 = { .size = 
sizeof(preserve_arg) };
+       struct liveupdate_session_retrieve_fd retrieve_arg = { .size = 
sizeof(retrieve_arg) };
+
+       switch (stage) {
+       case 1:
+               session = luo_create_session(luo_fd, ZERO_SESSION_NAME);
+               ASSERT_GE(session, 0);
+
+               zero_fd = memfd_create("zero_memfd", 0);
+               ASSERT_GE(zero_fd, 0);
+
+               preserve_arg.fd = zero_fd;
+               preserve_arg.token = ZERO_MEMFD_TOKEN;
+               ASSERT_GE(ioctl(session, LIVEUPDATE_SESSION_PRESERVE_FD, 
&preserve_arg), 0);
+
+               close(zero_fd);
+               daemonize_and_wait();
+               break;
+       case 2:
+               session = luo_retrieve_session(luo_fd, ZERO_SESSION_NAME);
+               ASSERT_GE(session, 0);
+
+               retrieve_arg.token = ZERO_MEMFD_TOKEN;
+               ASSERT_GE(ioctl(session, LIVEUPDATE_SESSION_RETRIEVE_FD, 
&retrieve_arg), 0);
+               zero_fd = 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 = 0;
-- 
2.53.0.473.g4a7958ca14-goog


Reply via email to