Skip to content

Commit c0dec4b

Browse files
Steve Sistarejgunthorpe
authored andcommitted
iommufd: IOMMU_IOAS_CHANGE_PROCESS selftest
Add selftest cases for IOMMU_IOAS_CHANGE_PROCESS. Link: https://patch.msgid.link/r/[email protected] Signed-off-by: Steve Sistare <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 829ed62 commit c0dec4b

File tree

3 files changed

+148
-0
lines changed

3 files changed

+148
-0
lines changed

tools/testing/selftests/iommu/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
CFLAGS += -Wall -O2 -Wno-unused-function
33
CFLAGS += $(KHDR_INCLUDES)
4+
LDLIBS += -lcap
45

56
TEST_GEN_PROGS :=
67
TEST_GEN_PROGS += iommufd

tools/testing/selftests/iommu/iommufd.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES */
33
#include <asm/unistd.h>
44
#include <stdlib.h>
5+
#include <sys/capability.h>
56
#include <sys/mman.h>
67
#include <sys/eventfd.h>
78

@@ -135,6 +136,8 @@ TEST_F(iommufd, cmd_length)
135136
TEST_LENGTH(iommu_ioas_map_file, IOMMU_IOAS_MAP_FILE, iova);
136137
TEST_LENGTH(iommu_viommu_alloc, IOMMU_VIOMMU_ALLOC, out_viommu_id);
137138
TEST_LENGTH(iommu_vdevice_alloc, IOMMU_VDEVICE_ALLOC, virt_id);
139+
TEST_LENGTH(iommu_ioas_change_process, IOMMU_IOAS_CHANGE_PROCESS,
140+
__reserved);
138141
#undef TEST_LENGTH
139142
}
140143

@@ -193,6 +196,144 @@ TEST_F(iommufd, global_options)
193196
EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_OPTION, &cmd));
194197
}
195198

199+
static void drop_cap_ipc_lock(struct __test_metadata *_metadata)
200+
{
201+
cap_t caps;
202+
cap_value_t cap_list[1] = { CAP_IPC_LOCK };
203+
204+
caps = cap_get_proc();
205+
ASSERT_NE(caps, NULL);
206+
ASSERT_NE(-1,
207+
cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_CLEAR));
208+
ASSERT_NE(-1, cap_set_proc(caps));
209+
cap_free(caps);
210+
}
211+
212+
static long get_proc_status_value(pid_t pid, const char *var)
213+
{
214+
FILE *fp;
215+
char buf[80], tag[80];
216+
long val = -1;
217+
218+
snprintf(buf, sizeof(buf), "/proc/%d/status", pid);
219+
fp = fopen(buf, "r");
220+
if (!fp)
221+
return val;
222+
223+
while (fgets(buf, sizeof(buf), fp))
224+
if (fscanf(fp, "%s %ld\n", tag, &val) == 2 && !strcmp(tag, var))
225+
break;
226+
227+
fclose(fp);
228+
return val;
229+
}
230+
231+
static long get_vm_pinned(pid_t pid)
232+
{
233+
return get_proc_status_value(pid, "VmPin:");
234+
}
235+
236+
static long get_vm_locked(pid_t pid)
237+
{
238+
return get_proc_status_value(pid, "VmLck:");
239+
}
240+
241+
FIXTURE(change_process)
242+
{
243+
int fd;
244+
uint32_t ioas_id;
245+
};
246+
247+
FIXTURE_VARIANT(change_process)
248+
{
249+
int accounting;
250+
};
251+
252+
FIXTURE_SETUP(change_process)
253+
{
254+
self->fd = open("/dev/iommu", O_RDWR);
255+
ASSERT_NE(-1, self->fd);
256+
257+
drop_cap_ipc_lock(_metadata);
258+
if (variant->accounting != IOPT_PAGES_ACCOUNT_NONE) {
259+
struct iommu_option set_limit_cmd = {
260+
.size = sizeof(set_limit_cmd),
261+
.option_id = IOMMU_OPTION_RLIMIT_MODE,
262+
.op = IOMMU_OPTION_OP_SET,
263+
.val64 = (variant->accounting == IOPT_PAGES_ACCOUNT_MM),
264+
};
265+
ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &set_limit_cmd));
266+
}
267+
268+
test_ioctl_ioas_alloc(&self->ioas_id);
269+
test_cmd_mock_domain(self->ioas_id, NULL, NULL, NULL);
270+
}
271+
272+
FIXTURE_TEARDOWN(change_process)
273+
{
274+
teardown_iommufd(self->fd, _metadata);
275+
}
276+
277+
FIXTURE_VARIANT_ADD(change_process, account_none)
278+
{
279+
.accounting = IOPT_PAGES_ACCOUNT_NONE,
280+
};
281+
282+
FIXTURE_VARIANT_ADD(change_process, account_user)
283+
{
284+
.accounting = IOPT_PAGES_ACCOUNT_USER,
285+
};
286+
287+
FIXTURE_VARIANT_ADD(change_process, account_mm)
288+
{
289+
.accounting = IOPT_PAGES_ACCOUNT_MM,
290+
};
291+
292+
TEST_F(change_process, basic)
293+
{
294+
pid_t parent = getpid();
295+
pid_t child;
296+
__u64 iova;
297+
struct iommu_ioas_change_process cmd = {
298+
.size = sizeof(cmd),
299+
};
300+
301+
/* Expect failure if non-file maps exist */
302+
test_ioctl_ioas_map(buffer, PAGE_SIZE, &iova);
303+
EXPECT_ERRNO(EINVAL, ioctl(self->fd, IOMMU_IOAS_CHANGE_PROCESS, &cmd));
304+
test_ioctl_ioas_unmap(iova, PAGE_SIZE);
305+
306+
/* Change process works in current process. */
307+
test_ioctl_ioas_map_file(mfd, 0, PAGE_SIZE, &iova);
308+
ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_CHANGE_PROCESS, &cmd));
309+
310+
/* Change process works in another process */
311+
child = fork();
312+
if (!child) {
313+
int nlock = PAGE_SIZE / 1024;
314+
315+
/* Parent accounts for locked memory before */
316+
ASSERT_EQ(nlock, get_vm_pinned(parent));
317+
if (variant->accounting == IOPT_PAGES_ACCOUNT_MM)
318+
ASSERT_EQ(nlock, get_vm_locked(parent));
319+
ASSERT_EQ(0, get_vm_pinned(getpid()));
320+
ASSERT_EQ(0, get_vm_locked(getpid()));
321+
322+
ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_CHANGE_PROCESS, &cmd));
323+
324+
/* Child accounts for locked memory after */
325+
ASSERT_EQ(0, get_vm_pinned(parent));
326+
ASSERT_EQ(0, get_vm_locked(parent));
327+
ASSERT_EQ(nlock, get_vm_pinned(getpid()));
328+
if (variant->accounting == IOPT_PAGES_ACCOUNT_MM)
329+
ASSERT_EQ(nlock, get_vm_locked(getpid()));
330+
331+
exit(0);
332+
}
333+
ASSERT_NE(-1, child);
334+
ASSERT_EQ(child, waitpid(child, NULL, 0));
335+
}
336+
196337
FIXTURE(iommufd_ioas)
197338
{
198339
int fd;

tools/testing/selftests/iommu/iommufd_utils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
#define BIT_MASK(nr) (1UL << ((nr) % __BITS_PER_LONG))
2323
#define BIT_WORD(nr) ((nr) / __BITS_PER_LONG)
2424

25+
enum {
26+
IOPT_PAGES_ACCOUNT_NONE = 0,
27+
IOPT_PAGES_ACCOUNT_USER = 1,
28+
IOPT_PAGES_ACCOUNT_MM = 2,
29+
};
30+
2531
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
2632

2733
static inline void set_bit(unsigned int nr, unsigned long *addr)

0 commit comments

Comments
 (0)