260 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3#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 423#define NUM_ENTRIES 424#define MEMFD_SIZE 1024 /* in pages */25 26static unsigned int page_size;27 28static 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 57static 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 87static 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 96static 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 109static 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 }127err:128 munmap(addr1, memfd_size);129 munmap(addr2, NUM_ENTRIES * NUM_PAGES * getpagesize());130 return ret;131}132 133int 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(6);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 else180 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 else190 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 else200 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 else213 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 else231 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 else249 ksft_test_result_pass("%s: [PASS,test-6]\n", TEST_PREFIX);250 251 close(buf);252 close(memfd);253 close(devfd);254 255 ksft_print_msg("%s: ok\n", TEST_PREFIX);256 ksft_print_cnts();257 258 return 0;259}260