Path: blob/master/tools/testing/selftests/drivers/dma-buf/udmabuf.c
26292 views
// SPDX-License-Identifier: GPL-2.01#define _GNU_SOURCE2#define __EXPORTED_HEADERS__34#include <stdio.h>5#include <stdlib.h>6#include <unistd.h>7#include <string.h>8#include <errno.h>9#include <fcntl.h>10#include <malloc.h>11#include <stdbool.h>1213#include <sys/ioctl.h>14#include <sys/syscall.h>15#include <sys/mman.h>16#include <linux/memfd.h>17#include <linux/udmabuf.h>18#include "../../kselftest.h"1920#define TEST_PREFIX "drivers/dma-buf/udmabuf"21#define NUM_PAGES 422#define NUM_ENTRIES 423#define MEMFD_SIZE 1024 /* in pages */2425static unsigned int page_size;2627static int create_memfd_with_seals(off64_t size, bool hpage)28{29int memfd, ret;30unsigned int flags = MFD_ALLOW_SEALING;3132if (hpage)33flags |= MFD_HUGETLB;3435memfd = memfd_create("udmabuf-test", flags);36if (memfd < 0) {37ksft_print_msg("%s: [skip,no-memfd]\n", TEST_PREFIX);38exit(KSFT_SKIP);39}4041ret = fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK);42if (ret < 0) {43ksft_print_msg("%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);44exit(KSFT_SKIP);45}4647ret = ftruncate(memfd, size);48if (ret == -1) {49ksft_print_msg("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);50exit(KSFT_FAIL);51}5253return memfd;54}5556static int create_udmabuf_list(int devfd, int memfd, off64_t memfd_size)57{58struct udmabuf_create_list *list;59int ubuf_fd, i;6061list = malloc(sizeof(struct udmabuf_create_list) +62sizeof(struct udmabuf_create_item) * NUM_ENTRIES);63if (!list) {64ksft_print_msg("%s: [FAIL, udmabuf-malloc]\n", TEST_PREFIX);65exit(KSFT_FAIL);66}6768for (i = 0; i < NUM_ENTRIES; i++) {69list->list[i].memfd = memfd;70list->list[i].offset = i * (memfd_size / NUM_ENTRIES);71list->list[i].size = getpagesize() * NUM_PAGES;72}7374list->count = NUM_ENTRIES;75list->flags = UDMABUF_FLAGS_CLOEXEC;76ubuf_fd = ioctl(devfd, UDMABUF_CREATE_LIST, list);77free(list);78if (ubuf_fd < 0) {79ksft_print_msg("%s: [FAIL, udmabuf-create]\n", TEST_PREFIX);80exit(KSFT_FAIL);81}8283return ubuf_fd;84}8586static void write_to_memfd(void *addr, off64_t size, char chr)87{88int i;8990for (i = 0; i < size / page_size; i++) {91*((char *)addr + (i * page_size)) = chr;92}93}9495static void *mmap_fd(int fd, off64_t size)96{97void *addr;9899addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);100if (addr == MAP_FAILED) {101ksft_print_msg("%s: ubuf_fd mmap fail\n", TEST_PREFIX);102exit(KSFT_FAIL);103}104105return addr;106}107108static int compare_chunks(void *addr1, void *addr2, off64_t memfd_size)109{110off64_t off;111int i = 0, j, k = 0, ret = 0;112char char1, char2;113114while (i < NUM_ENTRIES) {115off = i * (memfd_size / NUM_ENTRIES);116for (j = 0; j < NUM_PAGES; j++, k++) {117char1 = *((char *)addr1 + off + (j * getpagesize()));118char2 = *((char *)addr2 + (k * getpagesize()));119if (char1 != char2) {120ret = -1;121goto err;122}123}124i++;125}126err:127munmap(addr1, memfd_size);128munmap(addr2, NUM_ENTRIES * NUM_PAGES * getpagesize());129return ret;130}131132int main(int argc, char *argv[])133{134struct udmabuf_create create;135int devfd, memfd, buf, ret;136off64_t size;137void *addr1, *addr2;138139ksft_print_header();140ksft_set_plan(7);141142devfd = open("/dev/udmabuf", O_RDWR);143if (devfd < 0) {144ksft_print_msg(145"%s: [skip,no-udmabuf: Unable to access DMA buffer device file]\n",146TEST_PREFIX);147exit(KSFT_SKIP);148}149150memfd = memfd_create("udmabuf-test", MFD_ALLOW_SEALING);151if (memfd < 0) {152ksft_print_msg("%s: [skip,no-memfd]\n", TEST_PREFIX);153exit(KSFT_SKIP);154}155156ret = fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK);157if (ret < 0) {158ksft_print_msg("%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);159exit(KSFT_SKIP);160}161162size = getpagesize() * NUM_PAGES;163ret = ftruncate(memfd, size);164if (ret == -1) {165ksft_print_msg("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);166exit(KSFT_FAIL);167}168169memset(&create, 0, sizeof(create));170171/* should fail (offset not page aligned) */172create.memfd = memfd;173create.offset = getpagesize()/2;174create.size = getpagesize();175buf = ioctl(devfd, UDMABUF_CREATE, &create);176if (buf >= 0)177ksft_test_result_fail("%s: [FAIL,test-1]\n", TEST_PREFIX);178else179ksft_test_result_pass("%s: [PASS,test-1]\n", TEST_PREFIX);180181/* should fail (size not multiple of page) */182create.memfd = memfd;183create.offset = 0;184create.size = getpagesize()/2;185buf = ioctl(devfd, UDMABUF_CREATE, &create);186if (buf >= 0)187ksft_test_result_fail("%s: [FAIL,test-2]\n", TEST_PREFIX);188else189ksft_test_result_pass("%s: [PASS,test-2]\n", TEST_PREFIX);190191/* should fail (not memfd) */192create.memfd = 0; /* stdin */193create.offset = 0;194create.size = size;195buf = ioctl(devfd, UDMABUF_CREATE, &create);196if (buf >= 0)197ksft_test_result_fail("%s: [FAIL,test-3]\n", TEST_PREFIX);198else199ksft_test_result_pass("%s: [PASS,test-3]\n", TEST_PREFIX);200201/* should work */202page_size = getpagesize();203addr1 = mmap_fd(memfd, size);204write_to_memfd(addr1, size, 'a');205create.memfd = memfd;206create.offset = 0;207create.size = size;208buf = ioctl(devfd, UDMABUF_CREATE, &create);209if (buf < 0)210ksft_test_result_fail("%s: [FAIL,test-4]\n", TEST_PREFIX);211else212ksft_test_result_pass("%s: [PASS,test-4]\n", TEST_PREFIX);213214munmap(addr1, size);215close(buf);216close(memfd);217218/* should work (migration of 4k size pages)*/219size = MEMFD_SIZE * page_size;220memfd = create_memfd_with_seals(size, false);221addr1 = mmap_fd(memfd, size);222write_to_memfd(addr1, size, 'a');223buf = create_udmabuf_list(devfd, memfd, size);224addr2 = mmap_fd(buf, NUM_PAGES * NUM_ENTRIES * getpagesize());225write_to_memfd(addr1, size, 'b');226ret = compare_chunks(addr1, addr2, size);227if (ret < 0)228ksft_test_result_fail("%s: [FAIL,test-5]\n", TEST_PREFIX);229else230ksft_test_result_pass("%s: [PASS,test-5]\n", TEST_PREFIX);231232close(buf);233close(memfd);234235/* should work (migration of 2MB size huge pages)*/236page_size = getpagesize() * 512; /* 2 MB */237size = MEMFD_SIZE * page_size;238memfd = create_memfd_with_seals(size, true);239addr1 = mmap_fd(memfd, size);240write_to_memfd(addr1, size, 'a');241buf = create_udmabuf_list(devfd, memfd, size);242addr2 = mmap_fd(buf, NUM_PAGES * NUM_ENTRIES * getpagesize());243write_to_memfd(addr1, size, 'b');244ret = compare_chunks(addr1, addr2, size);245if (ret < 0)246ksft_test_result_fail("%s: [FAIL,test-6]\n", TEST_PREFIX);247else248ksft_test_result_pass("%s: [PASS,test-6]\n", TEST_PREFIX);249250close(buf);251close(memfd);252253/* same test as above but we pin first before writing to memfd */254page_size = getpagesize() * 512; /* 2 MB */255size = MEMFD_SIZE * page_size;256memfd = create_memfd_with_seals(size, true);257buf = create_udmabuf_list(devfd, memfd, size);258addr2 = mmap_fd(buf, NUM_PAGES * NUM_ENTRIES * getpagesize());259addr1 = mmap_fd(memfd, size);260write_to_memfd(addr1, size, 'a');261write_to_memfd(addr1, size, 'b');262ret = compare_chunks(addr1, addr2, size);263if (ret < 0)264ksft_test_result_fail("%s: [FAIL,test-7]\n", TEST_PREFIX);265else266ksft_test_result_pass("%s: [PASS,test-7]\n", TEST_PREFIX);267268close(buf);269close(memfd);270close(devfd);271272ksft_print_msg("%s: ok\n", TEST_PREFIX);273ksft_print_cnts();274275return 0;276}277278279