iommufd: IOMMU_IOAS_CHANGE_PROCESS selftest

Add selftest cases for IOMMU_IOAS_CHANGE_PROCESS.

Link: https://patch.msgid.link/r/1731527497-16091-5-git-send-email-steven.sistare@oracle.com
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
Steve Sistare
2024-11-13 11:51:37 -08:00
committed by Jason Gunthorpe
parent 829ed62649
commit c0dec4b848
3 changed files with 148 additions and 0 deletions
+1
View File
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
CFLAGS += -Wall -O2 -Wno-unused-function
CFLAGS += $(KHDR_INCLUDES)
LDLIBS += -lcap
TEST_GEN_PROGS :=
TEST_GEN_PROGS += iommufd
+141
View File
@@ -2,6 +2,7 @@
/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES */
#include <asm/unistd.h>
#include <stdlib.h>
#include <sys/capability.h>
#include <sys/mman.h>
#include <sys/eventfd.h>
@@ -135,6 +136,8 @@ TEST_F(iommufd, cmd_length)
TEST_LENGTH(iommu_ioas_map_file, IOMMU_IOAS_MAP_FILE, iova);
TEST_LENGTH(iommu_viommu_alloc, IOMMU_VIOMMU_ALLOC, out_viommu_id);
TEST_LENGTH(iommu_vdevice_alloc, IOMMU_VDEVICE_ALLOC, virt_id);
TEST_LENGTH(iommu_ioas_change_process, IOMMU_IOAS_CHANGE_PROCESS,
__reserved);
#undef TEST_LENGTH
}
@@ -193,6 +196,144 @@ TEST_F(iommufd, global_options)
EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_OPTION, &cmd));
}
static void drop_cap_ipc_lock(struct __test_metadata *_metadata)
{
cap_t caps;
cap_value_t cap_list[1] = { CAP_IPC_LOCK };
caps = cap_get_proc();
ASSERT_NE(caps, NULL);
ASSERT_NE(-1,
cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_CLEAR));
ASSERT_NE(-1, cap_set_proc(caps));
cap_free(caps);
}
static long get_proc_status_value(pid_t pid, const char *var)
{
FILE *fp;
char buf[80], tag[80];
long val = -1;
snprintf(buf, sizeof(buf), "/proc/%d/status", pid);
fp = fopen(buf, "r");
if (!fp)
return val;
while (fgets(buf, sizeof(buf), fp))
if (fscanf(fp, "%s %ld\n", tag, &val) == 2 && !strcmp(tag, var))
break;
fclose(fp);
return val;
}
static long get_vm_pinned(pid_t pid)
{
return get_proc_status_value(pid, "VmPin:");
}
static long get_vm_locked(pid_t pid)
{
return get_proc_status_value(pid, "VmLck:");
}
FIXTURE(change_process)
{
int fd;
uint32_t ioas_id;
};
FIXTURE_VARIANT(change_process)
{
int accounting;
};
FIXTURE_SETUP(change_process)
{
self->fd = open("/dev/iommu", O_RDWR);
ASSERT_NE(-1, self->fd);
drop_cap_ipc_lock(_metadata);
if (variant->accounting != IOPT_PAGES_ACCOUNT_NONE) {
struct iommu_option set_limit_cmd = {
.size = sizeof(set_limit_cmd),
.option_id = IOMMU_OPTION_RLIMIT_MODE,
.op = IOMMU_OPTION_OP_SET,
.val64 = (variant->accounting == IOPT_PAGES_ACCOUNT_MM),
};
ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &set_limit_cmd));
}
test_ioctl_ioas_alloc(&self->ioas_id);
test_cmd_mock_domain(self->ioas_id, NULL, NULL, NULL);
}
FIXTURE_TEARDOWN(change_process)
{
teardown_iommufd(self->fd, _metadata);
}
FIXTURE_VARIANT_ADD(change_process, account_none)
{
.accounting = IOPT_PAGES_ACCOUNT_NONE,
};
FIXTURE_VARIANT_ADD(change_process, account_user)
{
.accounting = IOPT_PAGES_ACCOUNT_USER,
};
FIXTURE_VARIANT_ADD(change_process, account_mm)
{
.accounting = IOPT_PAGES_ACCOUNT_MM,
};
TEST_F(change_process, basic)
{
pid_t parent = getpid();
pid_t child;
__u64 iova;
struct iommu_ioas_change_process cmd = {
.size = sizeof(cmd),
};
/* Expect failure if non-file maps exist */
test_ioctl_ioas_map(buffer, PAGE_SIZE, &iova);
EXPECT_ERRNO(EINVAL, ioctl(self->fd, IOMMU_IOAS_CHANGE_PROCESS, &cmd));
test_ioctl_ioas_unmap(iova, PAGE_SIZE);
/* Change process works in current process. */
test_ioctl_ioas_map_file(mfd, 0, PAGE_SIZE, &iova);
ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_CHANGE_PROCESS, &cmd));
/* Change process works in another process */
child = fork();
if (!child) {
int nlock = PAGE_SIZE / 1024;
/* Parent accounts for locked memory before */
ASSERT_EQ(nlock, get_vm_pinned(parent));
if (variant->accounting == IOPT_PAGES_ACCOUNT_MM)
ASSERT_EQ(nlock, get_vm_locked(parent));
ASSERT_EQ(0, get_vm_pinned(getpid()));
ASSERT_EQ(0, get_vm_locked(getpid()));
ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_CHANGE_PROCESS, &cmd));
/* Child accounts for locked memory after */
ASSERT_EQ(0, get_vm_pinned(parent));
ASSERT_EQ(0, get_vm_locked(parent));
ASSERT_EQ(nlock, get_vm_pinned(getpid()));
if (variant->accounting == IOPT_PAGES_ACCOUNT_MM)
ASSERT_EQ(nlock, get_vm_locked(getpid()));
exit(0);
}
ASSERT_NE(-1, child);
ASSERT_EQ(child, waitpid(child, NULL, 0));
}
FIXTURE(iommufd_ioas)
{
int fd;
@@ -22,6 +22,12 @@
#define BIT_MASK(nr) (1UL << ((nr) % __BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / __BITS_PER_LONG)
enum {
IOPT_PAGES_ACCOUNT_NONE = 0,
IOPT_PAGES_ACCOUNT_USER = 1,
IOPT_PAGES_ACCOUNT_MM = 2,
};
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
static inline void set_bit(unsigned int nr, unsigned long *addr)