1 // SPDX-License-Identifier: GPL-2.0
3 #define __EXPORTED_HEADERS__
14 #include <sys/ioctl.h>
15 #include <sys/syscall.h>
17 #include <linux/memfd.h>
18 #include <linux/udmabuf.h>
19 #include "../../kselftest.h"
21 #define TEST_PREFIX "drivers/dma-buf/udmabuf"
24 #define MEMFD_SIZE 1024 /* in pages */
26 static unsigned int page_size
;
28 static int create_memfd_with_seals(off64_t size
, bool hpage
)
31 unsigned int flags
= MFD_ALLOW_SEALING
;
36 memfd
= memfd_create("udmabuf-test", flags
);
38 ksft_print_msg("%s: [skip,no-memfd]\n", TEST_PREFIX
);
42 ret
= fcntl(memfd
, F_ADD_SEALS
, F_SEAL_SHRINK
);
44 ksft_print_msg("%s: [skip,fcntl-add-seals]\n", TEST_PREFIX
);
48 ret
= ftruncate(memfd
, size
);
50 ksft_print_msg("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX
);
57 static int create_udmabuf_list(int devfd
, int memfd
, off64_t memfd_size
)
59 struct udmabuf_create_list
*list
;
62 list
= malloc(sizeof(struct udmabuf_create_list
) +
63 sizeof(struct udmabuf_create_item
) * NUM_ENTRIES
);
65 ksft_print_msg("%s: [FAIL, udmabuf-malloc]\n", TEST_PREFIX
);
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
;
75 list
->count
= NUM_ENTRIES
;
76 list
->flags
= UDMABUF_FLAGS_CLOEXEC
;
77 ubuf_fd
= ioctl(devfd
, UDMABUF_CREATE_LIST
, list
);
80 ksft_print_msg("%s: [FAIL, udmabuf-create]\n", TEST_PREFIX
);
87 static void write_to_memfd(void *addr
, off64_t size
, char chr
)
91 for (i
= 0; i
< size
/ page_size
; i
++) {
92 *((char *)addr
+ (i
* page_size
)) = chr
;
96 static void *mmap_fd(int fd
, off64_t size
)
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
);
109 static int compare_chunks(void *addr1
, void *addr2
, off64_t memfd_size
)
112 int i
= 0, j
, k
= 0, ret
= 0;
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
) {
128 munmap(addr1
, memfd_size
);
129 munmap(addr2
, NUM_ENTRIES
* NUM_PAGES
* getpagesize());
133 int main(int argc
, char *argv
[])
135 struct udmabuf_create create
;
136 int devfd
, memfd
, buf
, ret
;
143 devfd
= open("/dev/udmabuf", O_RDWR
);
146 "%s: [skip,no-udmabuf: Unable to access DMA buffer device file]\n",
151 memfd
= memfd_create("udmabuf-test", MFD_ALLOW_SEALING
);
153 ksft_print_msg("%s: [skip,no-memfd]\n", TEST_PREFIX
);
157 ret
= fcntl(memfd
, F_ADD_SEALS
, F_SEAL_SHRINK
);
159 ksft_print_msg("%s: [skip,fcntl-add-seals]\n", TEST_PREFIX
);
163 size
= getpagesize() * NUM_PAGES
;
164 ret
= ftruncate(memfd
, size
);
166 ksft_print_msg("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX
);
170 memset(&create
, 0, sizeof(create
));
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
);
178 ksft_test_result_fail("%s: [FAIL,test-1]\n", TEST_PREFIX
);
180 ksft_test_result_pass("%s: [PASS,test-1]\n", TEST_PREFIX
);
182 /* should fail (size not multiple of page) */
183 create
.memfd
= memfd
;
185 create
.size
= getpagesize()/2;
186 buf
= ioctl(devfd
, UDMABUF_CREATE
, &create
);
188 ksft_test_result_fail("%s: [FAIL,test-2]\n", TEST_PREFIX
);
190 ksft_test_result_pass("%s: [PASS,test-2]\n", TEST_PREFIX
);
192 /* should fail (not memfd) */
193 create
.memfd
= 0; /* stdin */
196 buf
= ioctl(devfd
, UDMABUF_CREATE
, &create
);
198 ksft_test_result_fail("%s: [FAIL,test-3]\n", TEST_PREFIX
);
200 ksft_test_result_pass("%s: [PASS,test-3]\n", TEST_PREFIX
);
203 page_size
= getpagesize();
204 addr1
= mmap_fd(memfd
, size
);
205 write_to_memfd(addr1
, size
, 'a');
206 create
.memfd
= memfd
;
209 buf
= ioctl(devfd
, UDMABUF_CREATE
, &create
);
211 ksft_test_result_fail("%s: [FAIL,test-4]\n", TEST_PREFIX
);
213 ksft_test_result_pass("%s: [PASS,test-4]\n", TEST_PREFIX
);
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
);
229 ksft_test_result_fail("%s: [FAIL,test-5]\n", TEST_PREFIX
);
231 ksft_test_result_pass("%s: [PASS,test-5]\n", TEST_PREFIX
);
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
);
247 ksft_test_result_fail("%s: [FAIL,test-6]\n", TEST_PREFIX
);
249 ksft_test_result_pass("%s: [PASS,test-6]\n", TEST_PREFIX
);
255 ksft_print_msg("%s: ok\n", TEST_PREFIX
);