Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/drivers/dma-buf/udmabuf.c
26292 views
1
// SPDX-License-Identifier: GPL-2.0
2
#define _GNU_SOURCE
3
#define __EXPORTED_HEADERS__
4
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <unistd.h>
8
#include <string.h>
9
#include <errno.h>
10
#include <fcntl.h>
11
#include <malloc.h>
12
#include <stdbool.h>
13
14
#include <sys/ioctl.h>
15
#include <sys/syscall.h>
16
#include <sys/mman.h>
17
#include <linux/memfd.h>
18
#include <linux/udmabuf.h>
19
#include "../../kselftest.h"
20
21
#define TEST_PREFIX "drivers/dma-buf/udmabuf"
22
#define NUM_PAGES 4
23
#define NUM_ENTRIES 4
24
#define MEMFD_SIZE 1024 /* in pages */
25
26
static unsigned int page_size;
27
28
static int create_memfd_with_seals(off64_t size, bool hpage)
29
{
30
int memfd, ret;
31
unsigned int flags = MFD_ALLOW_SEALING;
32
33
if (hpage)
34
flags |= MFD_HUGETLB;
35
36
memfd = memfd_create("udmabuf-test", flags);
37
if (memfd < 0) {
38
ksft_print_msg("%s: [skip,no-memfd]\n", TEST_PREFIX);
39
exit(KSFT_SKIP);
40
}
41
42
ret = fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK);
43
if (ret < 0) {
44
ksft_print_msg("%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);
45
exit(KSFT_SKIP);
46
}
47
48
ret = ftruncate(memfd, size);
49
if (ret == -1) {
50
ksft_print_msg("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);
51
exit(KSFT_FAIL);
52
}
53
54
return memfd;
55
}
56
57
static int create_udmabuf_list(int devfd, int memfd, off64_t memfd_size)
58
{
59
struct udmabuf_create_list *list;
60
int ubuf_fd, i;
61
62
list = malloc(sizeof(struct udmabuf_create_list) +
63
sizeof(struct udmabuf_create_item) * NUM_ENTRIES);
64
if (!list) {
65
ksft_print_msg("%s: [FAIL, udmabuf-malloc]\n", TEST_PREFIX);
66
exit(KSFT_FAIL);
67
}
68
69
for (i = 0; i < NUM_ENTRIES; i++) {
70
list->list[i].memfd = memfd;
71
list->list[i].offset = i * (memfd_size / NUM_ENTRIES);
72
list->list[i].size = getpagesize() * NUM_PAGES;
73
}
74
75
list->count = NUM_ENTRIES;
76
list->flags = UDMABUF_FLAGS_CLOEXEC;
77
ubuf_fd = ioctl(devfd, UDMABUF_CREATE_LIST, list);
78
free(list);
79
if (ubuf_fd < 0) {
80
ksft_print_msg("%s: [FAIL, udmabuf-create]\n", TEST_PREFIX);
81
exit(KSFT_FAIL);
82
}
83
84
return ubuf_fd;
85
}
86
87
static void write_to_memfd(void *addr, off64_t size, char chr)
88
{
89
int i;
90
91
for (i = 0; i < size / page_size; i++) {
92
*((char *)addr + (i * page_size)) = chr;
93
}
94
}
95
96
static void *mmap_fd(int fd, off64_t size)
97
{
98
void *addr;
99
100
addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
101
if (addr == MAP_FAILED) {
102
ksft_print_msg("%s: ubuf_fd mmap fail\n", TEST_PREFIX);
103
exit(KSFT_FAIL);
104
}
105
106
return addr;
107
}
108
109
static int compare_chunks(void *addr1, void *addr2, off64_t memfd_size)
110
{
111
off64_t off;
112
int i = 0, j, k = 0, ret = 0;
113
char char1, char2;
114
115
while (i < NUM_ENTRIES) {
116
off = i * (memfd_size / NUM_ENTRIES);
117
for (j = 0; j < NUM_PAGES; j++, k++) {
118
char1 = *((char *)addr1 + off + (j * getpagesize()));
119
char2 = *((char *)addr2 + (k * getpagesize()));
120
if (char1 != char2) {
121
ret = -1;
122
goto err;
123
}
124
}
125
i++;
126
}
127
err:
128
munmap(addr1, memfd_size);
129
munmap(addr2, NUM_ENTRIES * NUM_PAGES * getpagesize());
130
return ret;
131
}
132
133
int main(int argc, char *argv[])
134
{
135
struct udmabuf_create create;
136
int devfd, memfd, buf, ret;
137
off64_t size;
138
void *addr1, *addr2;
139
140
ksft_print_header();
141
ksft_set_plan(7);
142
143
devfd = open("/dev/udmabuf", O_RDWR);
144
if (devfd < 0) {
145
ksft_print_msg(
146
"%s: [skip,no-udmabuf: Unable to access DMA buffer device file]\n",
147
TEST_PREFIX);
148
exit(KSFT_SKIP);
149
}
150
151
memfd = memfd_create("udmabuf-test", MFD_ALLOW_SEALING);
152
if (memfd < 0) {
153
ksft_print_msg("%s: [skip,no-memfd]\n", TEST_PREFIX);
154
exit(KSFT_SKIP);
155
}
156
157
ret = fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK);
158
if (ret < 0) {
159
ksft_print_msg("%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);
160
exit(KSFT_SKIP);
161
}
162
163
size = getpagesize() * NUM_PAGES;
164
ret = ftruncate(memfd, size);
165
if (ret == -1) {
166
ksft_print_msg("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);
167
exit(KSFT_FAIL);
168
}
169
170
memset(&create, 0, sizeof(create));
171
172
/* should fail (offset not page aligned) */
173
create.memfd = memfd;
174
create.offset = getpagesize()/2;
175
create.size = getpagesize();
176
buf = ioctl(devfd, UDMABUF_CREATE, &create);
177
if (buf >= 0)
178
ksft_test_result_fail("%s: [FAIL,test-1]\n", TEST_PREFIX);
179
else
180
ksft_test_result_pass("%s: [PASS,test-1]\n", TEST_PREFIX);
181
182
/* should fail (size not multiple of page) */
183
create.memfd = memfd;
184
create.offset = 0;
185
create.size = getpagesize()/2;
186
buf = ioctl(devfd, UDMABUF_CREATE, &create);
187
if (buf >= 0)
188
ksft_test_result_fail("%s: [FAIL,test-2]\n", TEST_PREFIX);
189
else
190
ksft_test_result_pass("%s: [PASS,test-2]\n", TEST_PREFIX);
191
192
/* should fail (not memfd) */
193
create.memfd = 0; /* stdin */
194
create.offset = 0;
195
create.size = size;
196
buf = ioctl(devfd, UDMABUF_CREATE, &create);
197
if (buf >= 0)
198
ksft_test_result_fail("%s: [FAIL,test-3]\n", TEST_PREFIX);
199
else
200
ksft_test_result_pass("%s: [PASS,test-3]\n", TEST_PREFIX);
201
202
/* should work */
203
page_size = getpagesize();
204
addr1 = mmap_fd(memfd, size);
205
write_to_memfd(addr1, size, 'a');
206
create.memfd = memfd;
207
create.offset = 0;
208
create.size = size;
209
buf = ioctl(devfd, UDMABUF_CREATE, &create);
210
if (buf < 0)
211
ksft_test_result_fail("%s: [FAIL,test-4]\n", TEST_PREFIX);
212
else
213
ksft_test_result_pass("%s: [PASS,test-4]\n", TEST_PREFIX);
214
215
munmap(addr1, size);
216
close(buf);
217
close(memfd);
218
219
/* should work (migration of 4k size pages)*/
220
size = MEMFD_SIZE * page_size;
221
memfd = create_memfd_with_seals(size, false);
222
addr1 = mmap_fd(memfd, size);
223
write_to_memfd(addr1, size, 'a');
224
buf = create_udmabuf_list(devfd, memfd, size);
225
addr2 = mmap_fd(buf, NUM_PAGES * NUM_ENTRIES * getpagesize());
226
write_to_memfd(addr1, size, 'b');
227
ret = compare_chunks(addr1, addr2, size);
228
if (ret < 0)
229
ksft_test_result_fail("%s: [FAIL,test-5]\n", TEST_PREFIX);
230
else
231
ksft_test_result_pass("%s: [PASS,test-5]\n", TEST_PREFIX);
232
233
close(buf);
234
close(memfd);
235
236
/* should work (migration of 2MB size huge pages)*/
237
page_size = getpagesize() * 512; /* 2 MB */
238
size = MEMFD_SIZE * page_size;
239
memfd = create_memfd_with_seals(size, true);
240
addr1 = mmap_fd(memfd, size);
241
write_to_memfd(addr1, size, 'a');
242
buf = create_udmabuf_list(devfd, memfd, size);
243
addr2 = mmap_fd(buf, NUM_PAGES * NUM_ENTRIES * getpagesize());
244
write_to_memfd(addr1, size, 'b');
245
ret = compare_chunks(addr1, addr2, size);
246
if (ret < 0)
247
ksft_test_result_fail("%s: [FAIL,test-6]\n", TEST_PREFIX);
248
else
249
ksft_test_result_pass("%s: [PASS,test-6]\n", TEST_PREFIX);
250
251
close(buf);
252
close(memfd);
253
254
/* same test as above but we pin first before writing to memfd */
255
page_size = getpagesize() * 512; /* 2 MB */
256
size = MEMFD_SIZE * page_size;
257
memfd = create_memfd_with_seals(size, true);
258
buf = create_udmabuf_list(devfd, memfd, size);
259
addr2 = mmap_fd(buf, NUM_PAGES * NUM_ENTRIES * getpagesize());
260
addr1 = mmap_fd(memfd, size);
261
write_to_memfd(addr1, size, 'a');
262
write_to_memfd(addr1, size, 'b');
263
ret = compare_chunks(addr1, addr2, size);
264
if (ret < 0)
265
ksft_test_result_fail("%s: [FAIL,test-7]\n", TEST_PREFIX);
266
else
267
ksft_test_result_pass("%s: [PASS,test-7]\n", TEST_PREFIX);
268
269
close(buf);
270
close(memfd);
271
close(devfd);
272
273
ksft_print_msg("%s: ok\n", TEST_PREFIX);
274
ksft_print_cnts();
275
276
return 0;
277
}
278
279