blob: 549f5e5cf2f1b564c47e4363de72ebf0f5613342 [file]
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2025 Google LLC.
* Author: Suren Baghdasaryan <surenb@google.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* WrapFD API tests
*/
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <linux/dma-buf.h>
#include <linux/dma-heap.h>
#include <linux/wrapfd.h>
#include "../../kselftest_harness.h"
/* ioctl wrappers */
static inline int wrapfd_wrap(int dev_fd, int fd, int prot)
{
struct wrapfd_wrap wrap = {
.fd = fd,
.prot = prot,
};
return ioctl(dev_fd, WRAPFD_DEV_IOC_WRAP, &wrap);
}
static inline int wrapfd_get_state(int wrapfd, unsigned int *state)
{
struct wrapfd_get_state wrap_state = { 0 };
int ret;
ret = ioctl(wrapfd, WRAPFD_DEV_IOC_GET_STATE, &wrap_state);
if (!ret && state)
*state = wrap_state.state;
return ret;
}
static inline int wrapfd_acquire_ownership(int wrapfd)
{
return ioctl(wrapfd, WRAPFD_DEV_IOC_ACQUIRE_OWNERSHIP, NULL);
}
static inline int wrapfd_release_ownership(int wrapfd)
{
return ioctl(wrapfd, WRAPFD_DEV_IOC_RELEASE_OWNERSHIP, NULL);
}
static inline int wrapfd_load(int wrapfd, int fd, unsigned long file_offs,
unsigned long buf_offs, unsigned long len)
{
struct wrapfd_load load = {
.fd = fd,
.file_offs = file_offs,
.buf_offs = buf_offs,
.len = len,
};
return ioctl(wrapfd, WRAPFD_DEV_IOC_LOAD, &load);
}
static inline int wrapfd_rewrap(int wrapfd, int prot)
{
struct wrapfd_rewrap rewrap = {
.prot = prot,
};
return ioctl(wrapfd, WRAPFD_DEV_IOC_REWRAP, &rewrap);
}
static inline int wrapfd_empty(int wrapfd)
{
return ioctl(wrapfd, WRAPFD_DEV_IOC_EMPTY, NULL);
}
static inline int wrapfd_allow_guests(int wrapfd)
{
return ioctl(wrapfd, WRAPFD_DEV_IOC_ALLOW_GUESTS, NULL);
}
static inline int wrapfd_prohibit_guests(int wrapfd)
{
return ioctl(wrapfd, WRAPFD_DEV_IOC_PROHIBIT_GUESTS, NULL);
}
/* test utility functions */
static int dmabuf_heap_alloc(int heap_fd, size_t len)
{
struct dma_heap_allocation_data data = {
.len = len,
.fd = 0,
.fd_flags = O_RDWR | O_CLOEXEC,
.heap_flags = 0,
};
int ret = ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &data);
return ret < 0 ? ret : data.fd;
}
static void generate_file_content(char *content, size_t size)
{
srand(time(NULL));
/* Generate only printable characters in the range of [32, 126] */
for (size_t i = 0; i < size; i++)
content[i] = 32 + rand() % 95;
}
FIXTURE(wrapfd_tests)
{
size_t page_size;
char *content;
size_t size;
int dev_fd;
int fd;
};
#define FILE_SZ_PAGES 100
FIXTURE_SETUP(wrapfd_tests)
{
ssize_t total_wr;
FILE *ftmp;
EXPECT_EQ(getuid(), 0)
SKIP(return, "Skipping all tests as non-root");
self->page_size = (size_t)sysconf(_SC_PAGESIZE);
self->size = self->page_size * FILE_SZ_PAGES;
self->dev_fd = open("/dev/wrapfd", O_RDONLY);
ASSERT_TRUE(self->dev_fd >= 0);
/* Prepare random content buffer */
self->content = malloc(self->size);
generate_file_content(self->content, self->size);
/* Prepare temporary file with the same content */
ftmp = tmpfile();
ASSERT_NE(ftmp, NULL);
self->fd = dup(fileno(ftmp));
fclose(ftmp);
total_wr = 0;
do {
ssize_t wr = write(self->fd, self->content + total_wr,
self->size - total_wr);
ASSERT_TRUE(wr >= 0);
total_wr += wr;
} while (total_wr < self->size);
}
FIXTURE_TEARDOWN(wrapfd_tests)
{
close(self->fd);
close(self->dev_fd);
}
static int cmp_content(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int wrapfd)
{
char *ptr;
int ret;
ptr = mmap(NULL, self->size, PROT_READ, MAP_SHARED, wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
ret = memcmp(self->content, ptr, self->size);
ASSERT_EQ(munmap(ptr, self->size), 0);
return ret;
}
static void clear_content(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int wrapfd)
{
char *ptr;
ptr = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_SHARED,
wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
memset(ptr, 0, self->size);
ASSERT_EQ(munmap(ptr, self->size), 0);
}
static void test_wrap(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int wrapfd;
struct stat sb;
/* Get state of a non-wrapped fd */
ASSERT_TRUE(wrapfd_get_state(fd, NULL) &&
errno == ENOTTY);
ASSERT_TRUE(wrapfd_get_state(self->dev_fd, NULL) &&
errno == ENOTTY);
/* Wrap and get state of a wrapped fd */
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ);
ASSERT_TRUE(wrapfd >= 0);
ASSERT_EQ(wrapfd_get_state(wrapfd, NULL), 0);
/* Ensure that the size of the wrapfd matches the size of the underlying buffer. */
ASSERT_EQ(fstat(wrapfd, &sb), 0);
ASSERT_EQ(sb.st_size, self->size);
close(wrapfd);
}
static void test_load(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int wrapfd;
/* Load the file content first */
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ | PROT_WRITE);
ASSERT_TRUE(wrapfd >= 0);
ASSERT_EQ(wrapfd_acquire_ownership(wrapfd), 0);
clear_content(_metadata, self, wrapfd);
ASSERT_NE(cmp_content(_metadata, self, wrapfd), 0);
ASSERT_EQ(wrapfd_load(wrapfd, self->fd, 0, 0, self->size), 0);
ASSERT_EQ(cmp_content(_metadata, self, wrapfd), 0);
/* TODO: test more load offsets */
ASSERT_EQ(wrapfd_release_ownership(wrapfd), 0);
close(wrapfd);
}
static void test_wrap_rdonly(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int wrapfd;
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ);
ASSERT_TRUE(wrapfd >= 0);
/* Check content of the buffer */
ASSERT_EQ(cmp_content(_metadata, self, wrapfd), 0);
/* Try mapping as writable */
ASSERT_EQ(mmap(NULL, self->size, PROT_READ | PROT_WRITE,
MAP_SHARED, wrapfd, 0), MAP_FAILED);
ASSERT_EQ(errno, EACCES);
close(wrapfd);
}
static void test_wrap_rdwr(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int wrapfd;
char *ptr;
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ | PROT_WRITE);
ASSERT_TRUE(wrapfd >= 0);
/* Check content of the buffer before modification */
ASSERT_EQ(cmp_content(_metadata, self, wrapfd), 0);
/* Modify buffer content */
ptr = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_SHARED,
wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
ptr[0]++;
/* Check content of the buffer after modification */
ASSERT_NE(cmp_content(_metadata, self, wrapfd), 0);
/* Restore buffer content */
ptr[0]--;
/* Confirm the final content */
ASSERT_EQ(cmp_content(_metadata, self, wrapfd), 0);
ASSERT_EQ(munmap(ptr, self->size), 0);
close(wrapfd);
}
static void test_remap_file_pages(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int wrapfd;
char *ptr;
/* remap_file_pages() on the content should succeed */
ptr = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0);
ASSERT_NE(ptr, MAP_FAILED);
ASSERT_EQ(remap_file_pages(ptr, self->page_size, 0, 1, 0), 0);
ASSERT_EQ(munmap(ptr, self->size), 0);
/* remap_file_pages() on the wrapfd should fail with EINVAL error */
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ | PROT_WRITE);
ASSERT_TRUE(wrapfd >= 0);
ptr = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_SHARED,
wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
ASSERT_EQ(remap_file_pages(ptr, self->page_size, 0, 1, 0), -1);
ASSERT_EQ(errno, EINVAL);
ASSERT_EQ(munmap(ptr, self->size), 0);
close(wrapfd);
}
static void test_wrap_remap(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
char *ptr, *new_ptr;
int wrapfd;
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ | PROT_WRITE);
ASSERT_TRUE(wrapfd >= 0);
/* Check content of the buffer before modification */
ASSERT_EQ(cmp_content(_metadata, self, wrapfd), 0);
/* Modify buffer content */
ptr = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_SHARED,
wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
/* Remap to a new address */
new_ptr = mremap(ptr, self->size, self->size, MREMAP_MAYMOVE);
ASSERT_NE(new_ptr, MAP_FAILED);
ASSERT_EQ(memcmp(self->content, new_ptr, self->size), 0);
ptr = new_ptr;
/* Resize the mapping */
new_ptr = mremap(ptr, self->size, self->size / 2, MREMAP_MAYMOVE);
ASSERT_NE(new_ptr, MAP_FAILED);
ASSERT_EQ(memcmp(self->content, new_ptr, self->size / 2), 0);
ptr = new_ptr;
ASSERT_EQ(munmap(ptr, self->size / 2), 0);
close(wrapfd);
}
static void test_wrap_fork(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int wrapfd, status;
char *ptr;
pid_t pid;
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ | PROT_WRITE);
ASSERT_TRUE(wrapfd >= 0);
/* Check content of the buffer before modification */
ASSERT_EQ(cmp_content(_metadata, self, wrapfd), 0);
/* Modify buffer content */
ptr = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_SHARED,
wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
pid = fork();
ASSERT_FALSE(pid < 0);
if (pid == 0) {
/* Check the content from the child */
ASSERT_EQ(memcmp(self->content, ptr, self->size), 0);
exit(EXIT_SUCCESS);
} else {
ASSERT_NE(wait(&status), -1);
ASSERT_TRUE(WIFEXITED(status));
ASSERT_EQ(WEXITSTATUS(status), 0);
}
ASSERT_EQ(munmap(ptr, self->size), 0);
close(wrapfd);
}
static void test_dup(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int wrapfd, wrapfd2;
char *ptr;
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ);
ASSERT_TRUE(wrapfd >= 0);
wrapfd2 = dup(wrapfd);
ASSERT_TRUE(wrapfd2 >= 0);
/* Check content of the buffer using both fds */
ASSERT_EQ(cmp_content(_metadata, self, wrapfd), 0);
ASSERT_EQ(cmp_content(_metadata, self, wrapfd2), 0);
close(wrapfd2);
close(wrapfd);
}
static void test_owner(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int wrapfd;
char *ptr;
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ);
ASSERT_TRUE(wrapfd >= 0);
/* Try taking ownership of a mapped wrapfd */
ptr = mmap(NULL, self->size, PROT_READ, MAP_SHARED | MAP_POPULATE,
wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
ASSERT_TRUE(wrapfd_acquire_ownership(wrapfd) && errno == EINVAL);
ASSERT_EQ(munmap(ptr, self->size), 0);
/* Take ownership of an unmapped wrapfd */
ASSERT_EQ(wrapfd_acquire_ownership(wrapfd), 0);
/* Map owned wrapfd */
ptr = mmap(NULL, self->size, PROT_READ, MAP_SHARED | MAP_POPULATE,
wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
/* Try releasing ownership while still mapped */
ASSERT_TRUE(wrapfd_release_ownership(wrapfd) && errno == EINVAL);
ASSERT_EQ(munmap(ptr, self->size), 0);
/* Release ownership of an unmapped wrapfd */
ASSERT_EQ(wrapfd_release_ownership(wrapfd), 0);
close(wrapfd);
}
static void test_rewrap(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int wrapfd, wrapfd2, wrapfd3;
unsigned int state;
char *ptr;
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ);
ASSERT_TRUE(wrapfd >= 0);
ASSERT_TRUE(wrapfd_get_state(wrapfd, &state) == 0 &&
state == WRAPFD_CONTENT_RDONLY);
/* Try rewrapping unowned buffer */
wrapfd2 = wrapfd_rewrap(wrapfd, PROT_WRITE);
ASSERT_TRUE(wrapfd2 < 0 && errno == EBUSY);
/* Take buffer ownership */
ASSERT_EQ(wrapfd_acquire_ownership(wrapfd), 0);
/* Try rewrapping a mapped buffer */
ptr = mmap(NULL, self->size, PROT_READ, MAP_SHARED | MAP_POPULATE,
wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
wrapfd2 = wrapfd_rewrap(wrapfd, PROT_WRITE);
ASSERT_TRUE(wrapfd2 < 0 && errno == EINVAL);
ASSERT_EQ(munmap(ptr, self->size), 0);
/* Rewrap the buffer to writable */
wrapfd2 = wrapfd_rewrap(wrapfd, PROT_WRITE);
ASSERT_TRUE(wrapfd2 >= 0);
/* Check the states of the new and original buffers */
ASSERT_TRUE(wrapfd_get_state(wrapfd2, &state) == 0 &&
state == WRAPFD_CONTENT_RDWR);
ASSERT_TRUE(wrapfd_get_state(wrapfd, &state) == 0 &&
state == WRAPFD_CONTENT_EMPTY);
/* Check rewrapped content */
ASSERT_EQ(cmp_content(_metadata, self, wrapfd2), 0);
/* Take ownership of the rewrapped buffer */
ASSERT_EQ(wrapfd_acquire_ownership(wrapfd2), 0);
/* Convert back to read-only */
wrapfd3 = wrapfd_rewrap(wrapfd2, PROT_READ);
ASSERT_TRUE(wrapfd3 >= 0);
ASSERT_TRUE(wrapfd_get_state(wrapfd3, &state) == 0 &&
state == WRAPFD_CONTENT_RDONLY);
ASSERT_TRUE(wrapfd_get_state(wrapfd2, &state) == 0 &&
state == WRAPFD_CONTENT_EMPTY);
/* Try mapping as writable */
ptr = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_SHARED,
wrapfd3, 0);
ASSERT_TRUE(ptr == MAP_FAILED && errno == EACCES);
/* Check rewrapped content */
ASSERT_EQ(cmp_content(_metadata, self, wrapfd3), 0);
/* Try mapping the original empty wrap file */
ptr = mmap(NULL, self->size, PROT_READ, MAP_SHARED,
wrapfd, 0);
ASSERT_TRUE(ptr == MAP_FAILED && errno == ENOENT);
/* Release ownership of the buffers */
ASSERT_EQ(wrapfd_release_ownership(wrapfd2), 0);
ASSERT_EQ(wrapfd_release_ownership(wrapfd), 0);
close(wrapfd3);
close(wrapfd2);
close(wrapfd);
}
static void test_empty(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
unsigned int state;
int wrapfd;
char *ptr;
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ | PROT_WRITE);
ASSERT_TRUE(wrapfd >= 0);
/* Try emptying unowned buffer */
ASSERT_TRUE(wrapfd_empty(wrapfd) < 0 && errno == EBUSY);
/* Take buffer ownership */
ASSERT_EQ(wrapfd_acquire_ownership(wrapfd), 0);
/* Try emptying a mapped buffer */
ptr = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_SHARED,
wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
ASSERT_TRUE(wrapfd_empty(wrapfd) < 0 && errno == EINVAL);
ASSERT_EQ(munmap(ptr, self->size), 0);
/* Empty the buffer */
ASSERT_EQ(wrapfd_empty(wrapfd), 0);
ASSERT_TRUE(wrapfd_get_state(wrapfd, &state) == 0 &&
state == WRAPFD_CONTENT_EMPTY);
/* Try mapping the empty wrap file */
ptr = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_SHARED,
wrapfd, 0);
ASSERT_TRUE(ptr == MAP_FAILED && errno == ENOENT);
/* Release buffer ownership */
ASSERT_EQ(wrapfd_release_ownership(wrapfd), 0);
close(wrapfd);
}
static int is_close_on_exec(int fd) {
int flags;
flags = fcntl(fd, F_GETFD);
if (flags == -1)
return -1;
return (flags & FD_CLOEXEC) ? 1 : 0;
}
static int set_close_on_exec(int fd, bool set) {
int flags;
flags = fcntl(fd, F_GETFD);
if (flags == -1)
return -1;
if (set)
flags |= FD_CLOEXEC;
else
flags &= ~FD_CLOEXEC;
return fcntl(fd, F_SETFD, flags);
}
static void __test_close_on_exec(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self,
int fd, int close_on_exec)
{
int wrapfd, wrapfd2;
/* Wrap's attribute should match its content */
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ | PROT_WRITE);
ASSERT_TRUE(wrapfd >= 0);
ASSERT_EQ(close_on_exec, is_close_on_exec(wrapfd));
/* Rewrapping should preserve the attribute */
ASSERT_EQ(wrapfd_acquire_ownership(wrapfd), 0);
wrapfd2 = wrapfd_rewrap(wrapfd, PROT_WRITE);
ASSERT_TRUE(wrapfd2 >= 0);
ASSERT_EQ(close_on_exec, is_close_on_exec(wrapfd2));
close(wrapfd2);
close(wrapfd);
}
static void test_close_on_exec(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int close_on_exec;
close_on_exec = is_close_on_exec(fd);
ASSERT_NE(close_on_exec, -1);
/* Test FD_CLOEXEC inheritance */
__test_close_on_exec(_metadata, self, fd, close_on_exec);
/* Test FD_CLOEXEC inheritance after toggling the attribute */
set_close_on_exec(fd, !close_on_exec);
__test_close_on_exec(_metadata, self, fd, !close_on_exec);
/* Reset attribute to the original value */
set_close_on_exec(fd, close_on_exec);
}
static void test_guests(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
int wrapfd;
char *ptr;
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ | PROT_WRITE);
ASSERT_TRUE(wrapfd >= 0);
/* Try allowing guests for unowned buffer */
ASSERT_TRUE(wrapfd_allow_guests(wrapfd) < 0 && errno == EBUSY);
/* Take buffer ownership */
ASSERT_EQ(wrapfd_acquire_ownership(wrapfd), 0);
/* Try allowing guests for a mapped buffer */
ptr = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_SHARED,
wrapfd, 0);
ASSERT_NE(ptr, MAP_FAILED);
ASSERT_TRUE(wrapfd_allow_guests(wrapfd) < 0 && errno == EINVAL);
ASSERT_EQ(munmap(ptr, self->size), 0);
/* Allow guests */
ASSERT_EQ(wrapfd_allow_guests(wrapfd), 0);
ASSERT_EQ(wrapfd_prohibit_guests(wrapfd), 0);
ASSERT_EQ(wrapfd_allow_guests(wrapfd), 0);
/* Release buffer ownership */
ASSERT_EQ(wrapfd_release_ownership(wrapfd), 0);
close(wrapfd);
}
#define FDINFO_BUF_SIZE 4096
static void test_ioctl(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
const char *buf_name = "test_dmabuf";
char str[FDINFO_BUF_SIZE];
char fdinfo_name[64];
int fdinfo_fd;
int wrapfd;
wrapfd = wrapfd_wrap(self->dev_fd, fd, PROT_READ | PROT_WRITE);
ASSERT_TRUE(wrapfd >= 0);
ASSERT_EQ(ioctl(wrapfd, DMA_BUF_SET_NAME, buf_name), 0);
/* Verify the dmabuf name is changed */
sprintf(fdinfo_name, "/proc/%d/fdinfo/%d", getpid(), fd);
fdinfo_fd = open(fdinfo_name, O_RDONLY);
ASSERT_TRUE(fdinfo_fd >= 0);
ASSERT_TRUE(read(fdinfo_fd, str, FDINFO_BUF_SIZE) > 0);
ASSERT_NE(strstr(str, buf_name), NULL);
close(fdinfo_fd);
/* Verify the dmabuf name is changed in wrapfd fdinfo too */
sprintf(fdinfo_name, "/proc/%d/fdinfo/%d", getpid(), wrapfd);
fdinfo_fd = open(fdinfo_name, O_RDONLY);
ASSERT_TRUE(fdinfo_fd >= 0);
ASSERT_TRUE(read(fdinfo_fd, str, FDINFO_BUF_SIZE) > 0);
ASSERT_NE(strstr(str, buf_name), NULL);
close(fdinfo_fd);
close(wrapfd);
}
static void run_tests(struct __test_metadata *_metadata,
FIXTURE_DATA(wrapfd_tests) *self, int fd)
{
test_wrap(_metadata, self, fd);
test_load(_metadata, self, fd);
test_wrap_rdonly(_metadata, self, fd);
test_wrap_rdwr(_metadata, self, fd);
test_remap_file_pages(_metadata, self, fd);
test_wrap_remap(_metadata, self, fd);
test_wrap_fork(_metadata, self, fd);
test_dup(_metadata, self, fd);
test_owner(_metadata, self, fd);
test_rewrap(_metadata, self, fd);
test_empty(_metadata, self, fd);
test_close_on_exec(_metadata, self, fd);
test_guests(_metadata, self, fd);
test_ioctl(_metadata, self, fd);
}
TEST_F(wrapfd_tests, wrapfd_test_dmabuf_system_heap)
{
int dmabuf_fd;
int heap_fd;
heap_fd = open("/dev/dma_heap/system", O_RDONLY);
ASSERT_TRUE(heap_fd >= 0);
dmabuf_fd = dmabuf_heap_alloc(heap_fd, self->size);
ASSERT_TRUE(dmabuf_fd >= 0);
close(heap_fd);
run_tests(_metadata, self, dmabuf_fd);
close(dmabuf_fd);
}
TEST_F(wrapfd_tests, wrapfd_test_dmabuf_cma_heap)
{
int dmabuf_fd;
int heap_fd;
heap_fd = open("/dev/dma_heap/default_cma_region", O_RDONLY);
if (heap_fd < 0 && errno == ENOENT)
SKIP(return, "Skipping CMA tests as the CMA heap is missing");
ASSERT_TRUE(heap_fd >= 0);
dmabuf_fd = dmabuf_heap_alloc(heap_fd, self->size);
ASSERT_TRUE(dmabuf_fd >= 0);
close(heap_fd);
run_tests(_metadata, self, dmabuf_fd);
close(dmabuf_fd);
}
TEST_HARNESS_MAIN