Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright Intel Corporation, 2023
  4 *
  5 * Author: Chao Peng <chao.p.peng@linux.intel.com>
  6 */
  7
  8#define _GNU_SOURCE
  9#include <stdlib.h>
 10#include <string.h>
 11#include <unistd.h>
 12#include <errno.h>
 13#include <stdio.h>
 14#include <fcntl.h>
 15
 16#include <linux/bitmap.h>
 17#include <linux/falloc.h>
 18#include <sys/mman.h>
 19#include <sys/types.h>
 20#include <sys/stat.h>
 21
 22#include "test_util.h"
 23#include "kvm_util_base.h"
 24
 25static void test_file_read_write(int fd)
 26{
 27	char buf[64];
 28
 29	TEST_ASSERT(read(fd, buf, sizeof(buf)) < 0,
 30		    "read on a guest_mem fd should fail");
 31	TEST_ASSERT(write(fd, buf, sizeof(buf)) < 0,
 32		    "write on a guest_mem fd should fail");
 33	TEST_ASSERT(pread(fd, buf, sizeof(buf), 0) < 0,
 34		    "pread on a guest_mem fd should fail");
 35	TEST_ASSERT(pwrite(fd, buf, sizeof(buf), 0) < 0,
 36		    "pwrite on a guest_mem fd should fail");
 37}
 38
 39static void test_mmap(int fd, size_t page_size)
 40{
 41	char *mem;
 42
 43	mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 44	TEST_ASSERT_EQ(mem, MAP_FAILED);
 45}
 46
 47static void test_file_size(int fd, size_t page_size, size_t total_size)
 48{
 49	struct stat sb;
 50	int ret;
 51
 52	ret = fstat(fd, &sb);
 53	TEST_ASSERT(!ret, "fstat should succeed");
 54	TEST_ASSERT_EQ(sb.st_size, total_size);
 55	TEST_ASSERT_EQ(sb.st_blksize, page_size);
 56}
 57
 58static void test_fallocate(int fd, size_t page_size, size_t total_size)
 59{
 60	int ret;
 61
 62	ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, total_size);
 63	TEST_ASSERT(!ret, "fallocate with aligned offset and size should succeed");
 64
 65	ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 66			page_size - 1, page_size);
 67	TEST_ASSERT(ret, "fallocate with unaligned offset should fail");
 68
 69	ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, total_size, page_size);
 70	TEST_ASSERT(ret, "fallocate beginning at total_size should fail");
 71
 72	ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, total_size + page_size, page_size);
 73	TEST_ASSERT(ret, "fallocate beginning after total_size should fail");
 74
 75	ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 76			total_size, page_size);
 77	TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) at total_size should succeed");
 78
 79	ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 80			total_size + page_size, page_size);
 81	TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) after total_size should succeed");
 82
 83	ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 84			page_size, page_size - 1);
 85	TEST_ASSERT(ret, "fallocate with unaligned size should fail");
 86
 87	ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
 88			page_size, page_size);
 89	TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) with aligned offset and size should succeed");
 90
 91	ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, page_size, page_size);
 92	TEST_ASSERT(!ret, "fallocate to restore punched hole should succeed");
 93}
 94
 95static void test_invalid_punch_hole(int fd, size_t page_size, size_t total_size)
 96{
 97	struct {
 98		off_t offset;
 99		off_t len;
100	} testcases[] = {
101		{0, 1},
102		{0, page_size - 1},
103		{0, page_size + 1},
104
105		{1, 1},
106		{1, page_size - 1},
107		{1, page_size},
108		{1, page_size + 1},
109
110		{page_size, 1},
111		{page_size, page_size - 1},
112		{page_size, page_size + 1},
113	};
114	int ret, i;
115
116	for (i = 0; i < ARRAY_SIZE(testcases); i++) {
117		ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
118				testcases[i].offset, testcases[i].len);
119		TEST_ASSERT(ret == -1 && errno == EINVAL,
120			    "PUNCH_HOLE with !PAGE_SIZE offset (%lx) and/or length (%lx) should fail",
121			    testcases[i].offset, testcases[i].len);
122	}
123}
124
125static void test_create_guest_memfd_invalid(struct kvm_vm *vm)
126{
127	size_t page_size = getpagesize();
128	uint64_t flag;
129	size_t size;
130	int fd;
131
132	for (size = 1; size < page_size; size++) {
133		fd = __vm_create_guest_memfd(vm, size, 0);
134		TEST_ASSERT(fd == -1 && errno == EINVAL,
135			    "guest_memfd() with non-page-aligned page size '0x%lx' should fail with EINVAL",
136			    size);
137	}
138
139	for (flag = 0; flag; flag <<= 1) {
140		fd = __vm_create_guest_memfd(vm, page_size, flag);
141		TEST_ASSERT(fd == -1 && errno == EINVAL,
142			    "guest_memfd() with flag '0x%lx' should fail with EINVAL",
143			    flag);
144	}
145}
146
147static void test_create_guest_memfd_multiple(struct kvm_vm *vm)
148{
149	int fd1, fd2, ret;
150	struct stat st1, st2;
151
152	fd1 = __vm_create_guest_memfd(vm, 4096, 0);
153	TEST_ASSERT(fd1 != -1, "memfd creation should succeed");
154
155	ret = fstat(fd1, &st1);
156	TEST_ASSERT(ret != -1, "memfd fstat should succeed");
157	TEST_ASSERT(st1.st_size == 4096, "memfd st_size should match requested size");
158
159	fd2 = __vm_create_guest_memfd(vm, 8192, 0);
160	TEST_ASSERT(fd2 != -1, "memfd creation should succeed");
161
162	ret = fstat(fd2, &st2);
163	TEST_ASSERT(ret != -1, "memfd fstat should succeed");
164	TEST_ASSERT(st2.st_size == 8192, "second memfd st_size should match requested size");
165
166	ret = fstat(fd1, &st1);
167	TEST_ASSERT(ret != -1, "memfd fstat should succeed");
168	TEST_ASSERT(st1.st_size == 4096, "first memfd st_size should still match requested size");
169	TEST_ASSERT(st1.st_ino != st2.st_ino, "different memfd should have different inode numbers");
170
171	close(fd2);
172	close(fd1);
173}
174
175int main(int argc, char *argv[])
176{
177	size_t page_size;
178	size_t total_size;
179	int fd;
180	struct kvm_vm *vm;
181
182	TEST_REQUIRE(kvm_has_cap(KVM_CAP_GUEST_MEMFD));
183
184	page_size = getpagesize();
185	total_size = page_size * 4;
186
187	vm = vm_create_barebones();
188
189	test_create_guest_memfd_invalid(vm);
190	test_create_guest_memfd_multiple(vm);
191
192	fd = vm_create_guest_memfd(vm, total_size, 0);
193
194	test_file_read_write(fd);
195	test_mmap(fd, page_size);
196	test_file_size(fd, page_size, total_size);
197	test_fallocate(fd, page_size, total_size);
198	test_invalid_punch_hole(fd, page_size, total_size);
199
200	close(fd);
201}