Blame test/io_uring_register.c

Packit d3489f
/* SPDX-License-Identifier: MIT */
Packit d3489f
/*
Packit d3489f
 * io_uring_register.c
Packit d3489f
 *
Packit d3489f
 * Description: Unit tests for the io_uring_register system call.
Packit d3489f
 *
Packit d3489f
 * Copyright 2019, Red Hat, Inc.
Packit d3489f
 * Author: Jeff Moyer <jmoyer@redhat.com>
Packit d3489f
 */
Packit d3489f
#include <stdio.h>
Packit d3489f
#include <fcntl.h>
Packit d3489f
#include <string.h>
Packit d3489f
#include <stdlib.h>
Packit d3489f
#include <unistd.h>
Packit d3489f
#include <errno.h>
Packit d3489f
#include <sys/sysinfo.h>
Packit d3489f
#include <poll.h>
Packit d3489f
#include <assert.h>
Packit d3489f
#include <sys/uio.h>
Packit d3489f
#include <sys/mman.h>
Packit d3489f
#include <linux/mman.h>
Packit d3489f
#include <sys/time.h>
Packit d3489f
#include <sys/resource.h>
Packit d3489f
#include <limits.h>
Packit d3489f
#include "liburing.h"
Packit d3489f
#include "../src/syscall.h"
Packit d3489f
Packit d3489f
static int pagesize;
Packit d3489f
static rlim_t mlock_limit;
Packit d3489f
static int devnull;
Packit d3489f
Packit d3489f
int
Packit d3489f
expect_fail(int fd, unsigned int opcode, void *arg,
Packit d3489f
	    unsigned int nr_args, int error)
Packit d3489f
{
Packit d3489f
	int ret;
Packit d3489f
Packit d3489f
	printf("io_uring_register(%d, %u, %p, %u)\n",
Packit d3489f
	       fd, opcode, arg, nr_args);
Packit d3489f
	ret = __sys_io_uring_register(fd, opcode, arg, nr_args);
Packit d3489f
	if (ret != -1) {
Packit d3489f
		int ret2 = 0;
Packit d3489f
Packit d3489f
		printf("expected %s, but call succeeded\n", strerror(error));
Packit d3489f
		if (opcode == IORING_REGISTER_BUFFERS) {
Packit d3489f
			ret2 = __sys_io_uring_register(fd,
Packit d3489f
					IORING_UNREGISTER_BUFFERS, 0, 0);
Packit d3489f
		} else if (opcode == IORING_REGISTER_FILES) {
Packit d3489f
			ret2 = __sys_io_uring_register(fd,
Packit d3489f
					IORING_UNREGISTER_FILES, 0, 0);
Packit d3489f
		}
Packit d3489f
		if (ret2) {
Packit d3489f
			printf("internal error: failed to unregister\n");
Packit d3489f
			exit(1);
Packit d3489f
		}
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	if (errno != error) {
Packit d3489f
		printf("expected %d, got %d\n", error, errno);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
	return 0;
Packit d3489f
}
Packit d3489f
Packit d3489f
int
Packit d3489f
new_io_uring(int entries, struct io_uring_params *p)
Packit d3489f
{
Packit d3489f
	int fd;
Packit d3489f
Packit d3489f
	fd = __sys_io_uring_setup(entries, p);
Packit d3489f
	if (fd < 0) {
Packit d3489f
		perror("io_uring_setup");
Packit d3489f
		exit(1);
Packit d3489f
	}
Packit d3489f
	return fd;
Packit d3489f
}
Packit d3489f
Packit d3489f
#define MAXFDS (UINT_MAX * sizeof(int))
Packit d3489f
Packit d3489f
void *
Packit d3489f
map_filebacked(size_t size)
Packit d3489f
{
Packit d3489f
	int fd, ret;
Packit d3489f
	void *addr;
Packit d3489f
	char template[32] = "io_uring_register-test-XXXXXXXX";
Packit d3489f
Packit d3489f
	fd = mkstemp(template);
Packit d3489f
	if (fd < 0) {
Packit d3489f
		perror("mkstemp");
Packit d3489f
		return NULL;
Packit d3489f
	}
Packit d3489f
	unlink(template);
Packit d3489f
Packit d3489f
	ret = ftruncate(fd, size);
Packit d3489f
	if (ret < 0) {
Packit d3489f
		perror("ftruncate");
Packit d3489f
		close(fd);
Packit d3489f
		return NULL;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
Packit d3489f
	if (addr == MAP_FAILED) {
Packit d3489f
		perror("mmap");
Packit d3489f
		close(fd);
Packit d3489f
		return NULL;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	close(fd);
Packit d3489f
	return addr;
Packit d3489f
}
Packit d3489f
Packit d3489f
/*
Packit d3489f
 * NOTE: this is now limited by SCM_MAX_FD (253).  Keep the code for now,
Packit d3489f
 * but probably should augment it to test 253 and 254, specifically.
Packit d3489f
 */
Packit d3489f
int
Packit d3489f
test_max_fds(int uring_fd)
Packit d3489f
{
Packit d3489f
	int status = 1;
Packit d3489f
	int ret;
Packit d3489f
	void *fd_as; /* file descriptor address space */
Packit d3489f
	int fdtable_fd; /* fd for the file that will be mapped over and over */
Packit d3489f
	int io_fd; /* the valid fd for I/O -- /dev/null */
Packit d3489f
	int *fds; /* used to map the file into the address space */
Packit d3489f
	char template[32] = "io_uring_register-test-XXXXXXXX";
Packit d3489f
	unsigned long long i, nr_maps, nr_fds;
Packit d3489f
Packit d3489f
	/*
Packit d3489f
	 * First, mmap anonymous the full size.  That will guarantee the
Packit d3489f
	 * mapping will fit in the memory area selected by mmap.  Then,
Packit d3489f
	 * over-write that mapping using a file-backed mapping, 128MiB at
Packit d3489f
	 * a time using MAP_FIXED.
Packit d3489f
	 */
Packit d3489f
	fd_as = mmap(NULL, UINT_MAX * sizeof(int), PROT_READ|PROT_WRITE,
Packit d3489f
		     MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
Packit d3489f
	if (fd_as == MAP_FAILED) {
Packit d3489f
		if (errno == ENOMEM) {
Packit d3489f
			printf("Not enough memory for this test, skipping\n");
Packit d3489f
			return 0;
Packit d3489f
		}
Packit d3489f
		perror("mmap fd_as");
Packit d3489f
		exit(1);
Packit d3489f
	}
Packit d3489f
	printf("allocated %zu bytes of address space\n", UINT_MAX * sizeof(int));
Packit d3489f
Packit d3489f
	fdtable_fd = mkstemp(template);
Packit d3489f
	if (fdtable_fd < 0) {
Packit d3489f
		perror("mkstemp");
Packit d3489f
		exit(1);
Packit d3489f
	}
Packit d3489f
	unlink(template);
Packit d3489f
	ret = ftruncate(fdtable_fd, 128*1024*1024);
Packit d3489f
	if (ret < 0) {
Packit d3489f
		perror("ftruncate");
Packit d3489f
		exit(1);
Packit d3489f
	}
Packit d3489f
Packit d3489f
	io_fd = open("/dev/null", O_RDWR);
Packit d3489f
	if (io_fd < 0) {
Packit d3489f
		perror("open /dev/null");
Packit d3489f
		exit(1);
Packit d3489f
	}
Packit d3489f
	fds = mmap(fd_as, 128*1024*1024, PROT_READ|PROT_WRITE,
Packit d3489f
		   MAP_SHARED|MAP_FIXED, fdtable_fd, 0);
Packit d3489f
	if (fds == MAP_FAILED) {
Packit d3489f
		perror("mmap fdtable");
Packit d3489f
		exit(1);
Packit d3489f
	}
Packit d3489f
Packit d3489f
	/* fill the fd table */
Packit d3489f
	nr_fds = 128*1024*1024 / sizeof(int);
Packit d3489f
	for (i = 0; i < nr_fds; i++)
Packit d3489f
		fds[i] = io_fd;
Packit d3489f
Packit d3489f
	/* map the file through the rest of the address space */
Packit d3489f
	nr_maps = (UINT_MAX * sizeof(int)) / (128*1024*1024);
Packit d3489f
	for (i = 0; i < nr_maps; i++) {
Packit d3489f
		fds = &fds[nr_fds]; /* advance fds by 128MiB */
Packit d3489f
		fds = mmap(fds, 128*1024*1024, PROT_READ|PROT_WRITE,
Packit d3489f
			   MAP_SHARED|MAP_FIXED, fdtable_fd, 0);
Packit d3489f
		if (fds == MAP_FAILED) {
Packit d3489f
			printf("mmap failed at offset %lu\n",
Packit d3489f
			       (unsigned long)((char *)fd_as - (char *)fds));
Packit d3489f
			exit(1);
Packit d3489f
		}
Packit d3489f
	}
Packit d3489f
Packit d3489f
	/* Now fd_as points to the file descriptor array. */
Packit d3489f
	/*
Packit d3489f
	 * We may not be able to map all of these files.  Let's back off
Packit d3489f
	 * until success.
Packit d3489f
	 */
Packit d3489f
	nr_fds = UINT_MAX;
Packit d3489f
	while (nr_fds) {
Packit d3489f
		ret = __sys_io_uring_register(uring_fd, IORING_REGISTER_FILES,
Packit d3489f
						fd_as, nr_fds);
Packit d3489f
		if (ret != 0) {
Packit d3489f
			nr_fds /= 2;
Packit d3489f
			continue;
Packit d3489f
		}
Packit d3489f
		printf("io_uring_register(%d, IORING_REGISTER_FILES, %p, %llu)"
Packit d3489f
		       "...succeeded\n", uring_fd, fd_as, nr_fds);
Packit d3489f
		status = 0;
Packit d3489f
		printf("io_uring_register(%d, IORING_UNREGISTER_FILES, 0, 0)...",
Packit d3489f
		       uring_fd);
Packit d3489f
		ret = __sys_io_uring_register(uring_fd, IORING_UNREGISTER_FILES,
Packit d3489f
						0, 0);
Packit d3489f
		if (ret < 0) {
Packit d3489f
			ret = errno;
Packit d3489f
			printf("failed\n");
Packit d3489f
			errno = ret;
Packit d3489f
			perror("io_uring_register UNREGISTER_FILES");
Packit d3489f
			exit(1);
Packit d3489f
		}
Packit d3489f
		printf("succeeded\n");
Packit d3489f
		break;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	close(io_fd);
Packit d3489f
	close(fdtable_fd);
Packit d3489f
	ret = munmap(fd_as, UINT_MAX * sizeof(int));
Packit d3489f
	if (ret != 0) {
Packit d3489f
		printf("munmap(%zu) failed\n", UINT_MAX * sizeof(int));
Packit d3489f
		exit(1);
Packit d3489f
	}
Packit d3489f
Packit d3489f
	return status;
Packit d3489f
}
Packit d3489f
Packit d3489f
int
Packit d3489f
test_memlock_exceeded(int fd)
Packit d3489f
{
Packit d3489f
	int ret;
Packit d3489f
	void *buf;
Packit d3489f
	struct iovec iov;
Packit d3489f
Packit d3489f
	/* if limit is larger than 2gb, just skip this test */
Packit d3489f
	if (mlock_limit >= 2 * 1024 * 1024 * 1024ULL)
Packit d3489f
		return 0;
Packit d3489f
Packit d3489f
	iov.iov_len = mlock_limit * 2;
Packit d3489f
	buf = malloc(iov.iov_len);
Packit d3489f
	assert(buf);
Packit d3489f
	iov.iov_base = buf;
Packit d3489f
Packit d3489f
	while (iov.iov_len) {
Packit d3489f
		ret = __sys_io_uring_register(fd, IORING_REGISTER_BUFFERS, &iov, 1);
Packit d3489f
		if (ret < 0) {
Packit d3489f
			if (errno == ENOMEM) {
Packit d3489f
				printf("io_uring_register of %zu bytes failed "
Packit d3489f
				       "with ENOMEM (expected).\n", iov.iov_len);
Packit d3489f
				iov.iov_len /= 2;
Packit d3489f
				continue;
Packit d3489f
			}
Packit d3489f
			printf("expected success or EFAULT, got %d\n", errno);
Packit d3489f
			free(buf);
Packit d3489f
			return 1;
Packit d3489f
		}
Packit d3489f
		printf("successfully registered %zu bytes (%d).\n",
Packit d3489f
		       iov.iov_len, ret);
Packit d3489f
		ret = __sys_io_uring_register(fd, IORING_UNREGISTER_BUFFERS,
Packit d3489f
						NULL, 0);
Packit d3489f
		if (ret != 0) {
Packit d3489f
			printf("error: unregister failed with %d\n", errno);
Packit d3489f
			free(buf);
Packit d3489f
			return 1;
Packit d3489f
		}
Packit d3489f
		break;
Packit d3489f
	}
Packit d3489f
	if (!iov.iov_len)
Packit d3489f
		printf("Unable to register buffers.  Check memlock rlimit.\n");
Packit d3489f
Packit d3489f
	free(buf);
Packit d3489f
	return 0;
Packit d3489f
}
Packit d3489f
Packit d3489f
int
Packit d3489f
test_iovec_nr(int fd)
Packit d3489f
{
Packit d3489f
	int i, ret, status = 0;
Packit d3489f
	unsigned int nr = UIO_MAXIOV + 1;
Packit d3489f
	struct iovec *iovs;
Packit d3489f
	void *buf;
Packit d3489f
Packit d3489f
	buf = malloc(pagesize);
Packit d3489f
	assert(buf);
Packit d3489f
Packit d3489f
	iovs = malloc(nr * sizeof(struct iovec));
Packit d3489f
	assert(iovs);
Packit d3489f
Packit d3489f
	for (i = 0; i < nr; i++) {
Packit d3489f
		iovs[i].iov_base = buf;
Packit d3489f
		iovs[i].iov_len = pagesize;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	status |= expect_fail(fd, IORING_REGISTER_BUFFERS, iovs, nr, EINVAL);
Packit d3489f
Packit d3489f
	/* reduce to UIO_MAXIOV */
Packit d3489f
	nr--;
Packit d3489f
	printf("io_uring_register(%d, %u, %p, %u)\n",
Packit d3489f
	       fd, IORING_REGISTER_BUFFERS, iovs, nr);
Packit d3489f
	ret = __sys_io_uring_register(fd, IORING_REGISTER_BUFFERS, iovs, nr);
Packit d3489f
	if (ret != 0) {
Packit d3489f
		printf("expected success, got %d\n", errno);
Packit d3489f
		status = 1;
Packit d3489f
	} else
Packit d3489f
		__sys_io_uring_register(fd, IORING_UNREGISTER_BUFFERS, 0, 0);
Packit d3489f
Packit d3489f
	free(buf);
Packit d3489f
	free(iovs);
Packit d3489f
	return status;
Packit d3489f
}
Packit d3489f
Packit d3489f
/*
Packit d3489f
 * io_uring limit is 1G.  iov_len limit is ~OUL, I think
Packit d3489f
 */
Packit d3489f
int
Packit d3489f
test_iovec_size(int fd)
Packit d3489f
{
Packit d3489f
	unsigned int status = 0;
Packit d3489f
	int ret;
Packit d3489f
	struct iovec iov;
Packit d3489f
	void *buf;
Packit d3489f
Packit d3489f
	/* NULL pointer for base */
Packit d3489f
	iov.iov_base = 0;
Packit d3489f
	iov.iov_len = 4096;
Packit d3489f
	status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, EFAULT);
Packit d3489f
Packit d3489f
	/* valid base, 0 length */
Packit d3489f
	iov.iov_base = &buf;
Packit d3489f
	iov.iov_len = 0;
Packit d3489f
	status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, EFAULT);
Packit d3489f
Packit d3489f
	/* valid base, length exceeds size */
Packit d3489f
	/* this requires an unampped page directly after buf */
Packit d3489f
	buf = mmap(NULL, 2 * pagesize, PROT_READ|PROT_WRITE,
Packit d3489f
		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Packit d3489f
	assert(buf != MAP_FAILED);
Packit d3489f
	ret = munmap(buf + pagesize, pagesize);
Packit d3489f
	assert(ret == 0);
Packit d3489f
	iov.iov_base = buf;
Packit d3489f
	iov.iov_len = 2 * pagesize;
Packit d3489f
	status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, EFAULT);
Packit d3489f
	munmap(buf, pagesize);
Packit d3489f
Packit d3489f
	/* huge page */
Packit d3489f
	buf = mmap(NULL, 2*1024*1024, PROT_READ|PROT_WRITE,
Packit d3489f
		   MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_2MB | MAP_ANONYMOUS,
Packit d3489f
		   -1, 0);
Packit d3489f
	if (buf == MAP_FAILED) {
Packit d3489f
		printf("Unable to map a huge page.  Try increasing "
Packit d3489f
		       "/proc/sys/vm/nr_hugepages by at least 1.\n");
Packit d3489f
		printf("Skipping the hugepage test\n");
Packit d3489f
	} else {
Packit d3489f
		/*
Packit d3489f
		 * This should succeed, so long as RLIMIT_MEMLOCK is
Packit d3489f
		 * not exceeded
Packit d3489f
		 */
Packit d3489f
		iov.iov_base = buf;
Packit d3489f
		iov.iov_len = 2*1024*1024;
Packit d3489f
		ret = __sys_io_uring_register(fd, IORING_REGISTER_BUFFERS, &iov, 1);
Packit d3489f
		if (ret < 0) {
Packit d3489f
			if (errno == ENOMEM)
Packit d3489f
				printf("Unable to test registering of a huge "
Packit d3489f
				       "page.  Try increasing the "
Packit d3489f
				       "RLIMIT_MEMLOCK resource limit by at "
Packit d3489f
				       "least 2MB.");
Packit d3489f
			else {
Packit d3489f
				printf("expected success, got %d\n", errno);
Packit d3489f
				status = 1;
Packit d3489f
			}
Packit d3489f
		} else {
Packit d3489f
			printf("Success!\n");
Packit d3489f
			ret = __sys_io_uring_register(fd,
Packit d3489f
					IORING_UNREGISTER_BUFFERS, 0, 0);
Packit d3489f
			if (ret < 0) {
Packit d3489f
				perror("io_uring_unregister");
Packit d3489f
				status = 1;
Packit d3489f
			}
Packit d3489f
		}
Packit d3489f
	}
Packit d3489f
	ret = munmap(iov.iov_base, iov.iov_len);
Packit d3489f
	assert(ret == 0);
Packit d3489f
Packit d3489f
	/* file-backed buffers -- not supported */
Packit d3489f
	buf = map_filebacked(2*1024*1024);
Packit d3489f
	if (!buf)
Packit d3489f
		status = 1;
Packit d3489f
	iov.iov_base = buf;
Packit d3489f
	iov.iov_len = 2*1024*1024;
Packit d3489f
	printf("reserve file-backed buffers\n");
Packit d3489f
	status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, EOPNOTSUPP);
Packit d3489f
	munmap(buf, 2*1024*1024);
Packit d3489f
Packit d3489f
	/* bump up against the soft limit and make sure we get EFAULT
Packit d3489f
	 * or whatever we're supposed to get.  NOTE: this requires
Packit d3489f
	 * running the test as non-root. */
Packit d3489f
	if (getuid() != 0)
Packit d3489f
		status |= test_memlock_exceeded(fd);
Packit d3489f
Packit d3489f
	return status;
Packit d3489f
}
Packit d3489f
Packit d3489f
void
Packit d3489f
dump_sqe(struct io_uring_sqe *sqe)
Packit d3489f
{
Packit d3489f
	printf("\topcode: %d\n", sqe->opcode);
Packit d3489f
	printf("\tflags:  0x%.8x\n", sqe->flags);
Packit d3489f
	printf("\tfd:     %d\n", sqe->fd);
Packit d3489f
	if (sqe->opcode == IORING_OP_POLL_ADD)
Packit d3489f
		printf("\tpoll_events: 0x%.8x\n", sqe->poll_events);
Packit d3489f
}
Packit d3489f
Packit d3489f
int
Packit d3489f
ioring_poll(struct io_uring *ring, int fd, int fixed)
Packit d3489f
{
Packit d3489f
	int ret;
Packit d3489f
	struct io_uring_sqe *sqe;
Packit d3489f
	struct io_uring_cqe *cqe;
Packit d3489f
Packit d3489f
	sqe = io_uring_get_sqe(ring);
Packit d3489f
	memset(sqe, 0, sizeof(*sqe));
Packit d3489f
	sqe->opcode = IORING_OP_POLL_ADD;
Packit d3489f
	if (fixed)
Packit d3489f
		sqe->flags = IOSQE_FIXED_FILE;
Packit d3489f
	sqe->fd = fd;
Packit d3489f
	sqe->poll_events = POLLIN|POLLOUT;
Packit d3489f
Packit d3489f
	printf("io_uring_submit:\n");
Packit d3489f
	dump_sqe(sqe);
Packit d3489f
	ret = io_uring_submit(ring);
Packit d3489f
	if (ret != 1) {
Packit d3489f
		printf("failed to submit poll sqe: %d.\n", errno);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = io_uring_wait_cqe(ring, &cqe);
Packit d3489f
	if (ret < 0) {
Packit d3489f
		printf("io_uring_wait_cqe failed with %d\n", ret);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
	ret = 0;
Packit d3489f
	if (cqe->res != POLLOUT) {
Packit d3489f
		printf("io_uring_wait_cqe: expected 0x%.8x, got 0x%.8x\n",
Packit d3489f
		       POLLOUT, cqe->res);
Packit d3489f
		ret = 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	io_uring_cqe_seen(ring, cqe);
Packit d3489f
	return ret;
Packit d3489f
}
Packit d3489f
Packit d3489f
int
Packit d3489f
test_poll_ringfd(void)
Packit d3489f
{
Packit d3489f
	int status = 0;
Packit d3489f
	int ret;
Packit d3489f
	int fd;
Packit d3489f
	struct io_uring ring;
Packit d3489f
Packit d3489f
	ret = io_uring_queue_init(1, &ring, 0);
Packit d3489f
	if (ret) {
Packit d3489f
		perror("io_uring_queue_init");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
	fd = ring.ring_fd;
Packit d3489f
Packit d3489f
	/* try polling the ring fd */
Packit d3489f
	status = ioring_poll(&ring, fd, 0);
Packit d3489f
Packit d3489f
	/*
Packit d3489f
	 * now register the ring fd, and try the poll again.  This should
Packit d3489f
	 * fail, because the kernel does not allow registering of the
Packit d3489f
	 * ring_fd.
Packit d3489f
	 */
Packit d3489f
	status |= expect_fail(fd, IORING_REGISTER_FILES, &fd, 1, EBADF);
Packit d3489f
Packit d3489f
	/* tear down queue */
Packit d3489f
	io_uring_queue_exit(&ring);
Packit d3489f
Packit d3489f
	return status;
Packit d3489f
}
Packit d3489f
Packit d3489f
int
Packit d3489f
main(int argc, char **argv)
Packit d3489f
{
Packit d3489f
	int fd, ret;
Packit d3489f
	unsigned int status = 0;
Packit d3489f
	struct io_uring_params p;
Packit d3489f
	struct rlimit rlim;
Packit d3489f
Packit d3489f
	if (argc > 1)
Packit d3489f
		return 0;
Packit d3489f
Packit d3489f
	/* setup globals */
Packit d3489f
	pagesize = getpagesize();
Packit d3489f
	ret = getrlimit(RLIMIT_MEMLOCK, &rlim);
Packit d3489f
	if (ret < 0) {
Packit d3489f
		perror("getrlimit");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
	mlock_limit = rlim.rlim_cur;
Packit d3489f
	printf("RELIMIT_MEMLOCK: %lu (%lu)\n", rlim.rlim_cur, rlim.rlim_max);
Packit d3489f
	devnull = open("/dev/null", O_RDWR);
Packit d3489f
	if (devnull < 0) {
Packit d3489f
		perror("open /dev/null");
Packit d3489f
		exit(1);
Packit d3489f
	}
Packit d3489f
Packit d3489f
	/* invalid fd */
Packit d3489f
	status |= expect_fail(-1, 0, NULL, 0, EBADF);
Packit d3489f
	/* valid fd that is not an io_uring fd */
Packit d3489f
	status |= expect_fail(devnull, 0, NULL, 0, EOPNOTSUPP);
Packit d3489f
Packit d3489f
	/* invalid opcode */
Packit d3489f
	memset(&p, 0, sizeof(p));
Packit d3489f
	fd = new_io_uring(1, &p);
Packit d3489f
	ret = expect_fail(fd, ~0U, NULL, 0, EINVAL);
Packit d3489f
	if (ret) {
Packit d3489f
		/* if this succeeds, tear down the io_uring instance
Packit d3489f
		 * and start clean for the next test. */
Packit d3489f
		close(fd);
Packit d3489f
		fd = new_io_uring(1, &p);
Packit d3489f
	}
Packit d3489f
Packit d3489f
	/* IORING_REGISTER_BUFFERS */
Packit d3489f
	status |= test_iovec_size(fd);
Packit d3489f
	status |= test_iovec_nr(fd);
Packit d3489f
	/* IORING_REGISTER_FILES */
Packit d3489f
	status |= test_max_fds(fd);
Packit d3489f
	close(fd);
Packit d3489f
	/* uring poll on the uring fd */
Packit d3489f
	status |= test_poll_ringfd();
Packit d3489f
Packit d3489f
	if (!status)
Packit d3489f
		printf("PASS\n");
Packit d3489f
	else
Packit d3489f
		printf("FAIL\n");
Packit d3489f
Packit d3489f
	return status;
Packit d3489f
}