Skip to content

Commit 0bcceb1

Browse files
Steve Sistarejgunthorpe
authored andcommitted
iommufd: Selftest coverage for IOMMU_IOAS_MAP_FILE
Add test cases to exercise IOMMU_IOAS_MAP_FILE. Link: https://patch.msgid.link/r/[email protected] Signed-off-by: Steve Sistare <[email protected]> Reviewed-by: Nicolin Chen <[email protected]> Tested-by: Nicolin Chen <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 976a40c commit 0bcceb1

File tree

3 files changed

+205
-15
lines changed

3 files changed

+205
-15
lines changed

tools/testing/selftests/iommu/iommufd.c

Lines changed: 109 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES */
3+
#include <asm/unistd.h>
34
#include <stdlib.h>
45
#include <sys/mman.h>
56
#include <sys/eventfd.h>
@@ -49,6 +50,9 @@ static __attribute__((constructor)) void setup_sizes(void)
4950
vrc = mmap(buffer, BUFFER_SIZE, PROT_READ | PROT_WRITE,
5051
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
5152
assert(vrc == buffer);
53+
54+
mfd_buffer = memfd_mmap(BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
55+
&mfd);
5256
}
5357

5458
FIXTURE(iommufd)
@@ -128,6 +132,7 @@ TEST_F(iommufd, cmd_length)
128132
TEST_LENGTH(iommu_ioas_unmap, IOMMU_IOAS_UNMAP, length);
129133
TEST_LENGTH(iommu_option, IOMMU_OPTION, val64);
130134
TEST_LENGTH(iommu_vfio_ioas, IOMMU_VFIO_IOAS, __reserved);
135+
TEST_LENGTH(iommu_ioas_map_file, IOMMU_IOAS_MAP_FILE, iova);
131136
#undef TEST_LENGTH
132137
}
133138

@@ -1372,6 +1377,7 @@ FIXTURE_VARIANT(iommufd_mock_domain)
13721377
{
13731378
unsigned int mock_domains;
13741379
bool hugepages;
1380+
bool file;
13751381
};
13761382

13771383
FIXTURE_SETUP(iommufd_mock_domain)
@@ -1410,26 +1416,45 @@ FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain)
14101416
{
14111417
.mock_domains = 1,
14121418
.hugepages = false,
1419+
.file = false,
14131420
};
14141421

14151422
FIXTURE_VARIANT_ADD(iommufd_mock_domain, two_domains)
14161423
{
14171424
.mock_domains = 2,
14181425
.hugepages = false,
1426+
.file = false,
14191427
};
14201428

14211429
FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain_hugepage)
14221430
{
14231431
.mock_domains = 1,
14241432
.hugepages = true,
1433+
.file = false,
14251434
};
14261435

14271436
FIXTURE_VARIANT_ADD(iommufd_mock_domain, two_domains_hugepage)
14281437
{
14291438
.mock_domains = 2,
14301439
.hugepages = true,
1440+
.file = false,
1441+
};
1442+
1443+
FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain_file)
1444+
{
1445+
.mock_domains = 1,
1446+
.hugepages = false,
1447+
.file = true,
1448+
};
1449+
1450+
FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain_file_hugepage)
1451+
{
1452+
.mock_domains = 1,
1453+
.hugepages = true,
1454+
.file = true,
14311455
};
14321456

1457+
14331458
/* Have the kernel check that the user pages made it to the iommu_domain */
14341459
#define check_mock_iova(_ptr, _iova, _length) \
14351460
({ \
@@ -1455,7 +1480,10 @@ FIXTURE_VARIANT_ADD(iommufd_mock_domain, two_domains_hugepage)
14551480
} \
14561481
})
14571482

1458-
TEST_F(iommufd_mock_domain, basic)
1483+
static void
1484+
test_basic_mmap(struct __test_metadata *_metadata,
1485+
struct _test_data_iommufd_mock_domain *self,
1486+
const struct _fixture_variant_iommufd_mock_domain *variant)
14591487
{
14601488
size_t buf_size = self->mmap_buf_size;
14611489
uint8_t *buf;
@@ -1478,6 +1506,40 @@ TEST_F(iommufd_mock_domain, basic)
14781506
test_err_ioctl_ioas_map(EFAULT, buf, buf_size, &iova);
14791507
}
14801508

1509+
static void
1510+
test_basic_file(struct __test_metadata *_metadata,
1511+
struct _test_data_iommufd_mock_domain *self,
1512+
const struct _fixture_variant_iommufd_mock_domain *variant)
1513+
{
1514+
size_t buf_size = self->mmap_buf_size;
1515+
uint8_t *buf;
1516+
__u64 iova;
1517+
int mfd_tmp;
1518+
int prot = PROT_READ | PROT_WRITE;
1519+
1520+
/* Simple one page map */
1521+
test_ioctl_ioas_map_file(mfd, 0, PAGE_SIZE, &iova);
1522+
check_mock_iova(mfd_buffer, iova, PAGE_SIZE);
1523+
1524+
buf = memfd_mmap(buf_size, prot, MAP_SHARED, &mfd_tmp);
1525+
ASSERT_NE(MAP_FAILED, buf);
1526+
1527+
test_err_ioctl_ioas_map_file(EINVAL, mfd_tmp, 0, buf_size + 1, &iova);
1528+
1529+
ASSERT_EQ(0, ftruncate(mfd_tmp, 0));
1530+
test_err_ioctl_ioas_map_file(EINVAL, mfd_tmp, 0, buf_size, &iova);
1531+
1532+
close(mfd_tmp);
1533+
}
1534+
1535+
TEST_F(iommufd_mock_domain, basic)
1536+
{
1537+
if (variant->file)
1538+
test_basic_file(_metadata, self, variant);
1539+
else
1540+
test_basic_mmap(_metadata, self, variant);
1541+
}
1542+
14811543
TEST_F(iommufd_mock_domain, ro_unshare)
14821544
{
14831545
uint8_t *buf;
@@ -1513,9 +1575,13 @@ TEST_F(iommufd_mock_domain, all_aligns)
15131575
unsigned int start;
15141576
unsigned int end;
15151577
uint8_t *buf;
1578+
int prot = PROT_READ | PROT_WRITE;
1579+
int mfd;
15161580

1517-
buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, self->mmap_flags, -1,
1518-
0);
1581+
if (variant->file)
1582+
buf = memfd_mmap(buf_size, prot, MAP_SHARED, &mfd);
1583+
else
1584+
buf = mmap(0, buf_size, prot, self->mmap_flags, -1, 0);
15191585
ASSERT_NE(MAP_FAILED, buf);
15201586
check_refs(buf, buf_size, 0);
15211587

@@ -1532,7 +1598,12 @@ TEST_F(iommufd_mock_domain, all_aligns)
15321598
size_t length = end - start;
15331599
__u64 iova;
15341600

1535-
test_ioctl_ioas_map(buf + start, length, &iova);
1601+
if (variant->file) {
1602+
test_ioctl_ioas_map_file(mfd, start, length,
1603+
&iova);
1604+
} else {
1605+
test_ioctl_ioas_map(buf + start, length, &iova);
1606+
}
15361607
check_mock_iova(buf + start, iova, length);
15371608
check_refs(buf + start / PAGE_SIZE * PAGE_SIZE,
15381609
end / PAGE_SIZE * PAGE_SIZE -
@@ -1544,6 +1615,8 @@ TEST_F(iommufd_mock_domain, all_aligns)
15441615
}
15451616
check_refs(buf, buf_size, 0);
15461617
ASSERT_EQ(0, munmap(buf, buf_size));
1618+
if (variant->file)
1619+
close(mfd);
15471620
}
15481621

15491622
TEST_F(iommufd_mock_domain, all_aligns_copy)
@@ -1554,9 +1627,13 @@ TEST_F(iommufd_mock_domain, all_aligns_copy)
15541627
unsigned int start;
15551628
unsigned int end;
15561629
uint8_t *buf;
1630+
int prot = PROT_READ | PROT_WRITE;
1631+
int mfd;
15571632

1558-
buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, self->mmap_flags, -1,
1559-
0);
1633+
if (variant->file)
1634+
buf = memfd_mmap(buf_size, prot, MAP_SHARED, &mfd);
1635+
else
1636+
buf = mmap(0, buf_size, prot, self->mmap_flags, -1, 0);
15601637
ASSERT_NE(MAP_FAILED, buf);
15611638
check_refs(buf, buf_size, 0);
15621639

@@ -1575,7 +1652,12 @@ TEST_F(iommufd_mock_domain, all_aligns_copy)
15751652
uint32_t mock_stdev_id;
15761653
__u64 iova;
15771654

1578-
test_ioctl_ioas_map(buf + start, length, &iova);
1655+
if (variant->file) {
1656+
test_ioctl_ioas_map_file(mfd, start, length,
1657+
&iova);
1658+
} else {
1659+
test_ioctl_ioas_map(buf + start, length, &iova);
1660+
}
15791661

15801662
/* Add and destroy a domain while the area exists */
15811663
old_id = self->hwpt_ids[1];
@@ -1596,15 +1678,18 @@ TEST_F(iommufd_mock_domain, all_aligns_copy)
15961678
}
15971679
check_refs(buf, buf_size, 0);
15981680
ASSERT_EQ(0, munmap(buf, buf_size));
1681+
if (variant->file)
1682+
close(mfd);
15991683
}
16001684

16011685
TEST_F(iommufd_mock_domain, user_copy)
16021686
{
1687+
void *buf = variant->file ? mfd_buffer : buffer;
16031688
struct iommu_test_cmd access_cmd = {
16041689
.size = sizeof(access_cmd),
16051690
.op = IOMMU_TEST_OP_ACCESS_PAGES,
16061691
.access_pages = { .length = BUFFER_SIZE,
1607-
.uptr = (uintptr_t)buffer },
1692+
.uptr = (uintptr_t)buf },
16081693
};
16091694
struct iommu_ioas_copy copy_cmd = {
16101695
.size = sizeof(copy_cmd),
@@ -1623,9 +1708,13 @@ TEST_F(iommufd_mock_domain, user_copy)
16231708

16241709
/* Pin the pages in an IOAS with no domains then copy to an IOAS with domains */
16251710
test_ioctl_ioas_alloc(&ioas_id);
1626-
test_ioctl_ioas_map_id(ioas_id, buffer, BUFFER_SIZE,
1627-
&copy_cmd.src_iova);
1628-
1711+
if (variant->file) {
1712+
test_ioctl_ioas_map_id_file(ioas_id, mfd, 0, BUFFER_SIZE,
1713+
&copy_cmd.src_iova);
1714+
} else {
1715+
test_ioctl_ioas_map_id(ioas_id, buf, BUFFER_SIZE,
1716+
&copy_cmd.src_iova);
1717+
}
16291718
test_cmd_create_access(ioas_id, &access_cmd.id,
16301719
MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES);
16311720

@@ -1635,12 +1724,17 @@ TEST_F(iommufd_mock_domain, user_copy)
16351724
&access_cmd));
16361725
copy_cmd.src_ioas_id = ioas_id;
16371726
ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));
1638-
check_mock_iova(buffer, MOCK_APERTURE_START, BUFFER_SIZE);
1727+
check_mock_iova(buf, MOCK_APERTURE_START, BUFFER_SIZE);
16391728

16401729
/* Now replace the ioas with a new one */
16411730
test_ioctl_ioas_alloc(&new_ioas_id);
1642-
test_ioctl_ioas_map_id(new_ioas_id, buffer, BUFFER_SIZE,
1643-
&copy_cmd.src_iova);
1731+
if (variant->file) {
1732+
test_ioctl_ioas_map_id_file(new_ioas_id, mfd, 0, BUFFER_SIZE,
1733+
&copy_cmd.src_iova);
1734+
} else {
1735+
test_ioctl_ioas_map_id(new_ioas_id, buf, BUFFER_SIZE,
1736+
&copy_cmd.src_iova);
1737+
}
16441738
test_cmd_access_replace_ioas(access_cmd.id, new_ioas_id);
16451739

16461740
/* Destroy the old ioas and cleanup copied mapping */
@@ -1654,7 +1748,7 @@ TEST_F(iommufd_mock_domain, user_copy)
16541748
&access_cmd));
16551749
copy_cmd.src_ioas_id = new_ioas_id;
16561750
ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));
1657-
check_mock_iova(buffer, MOCK_APERTURE_START, BUFFER_SIZE);
1751+
check_mock_iova(buf, MOCK_APERTURE_START, BUFFER_SIZE);
16581752

16591753
test_cmd_destroy_access_pages(
16601754
access_cmd.id, access_cmd.access_pages.out_access_pages_id);

tools/testing/selftests/iommu/iommufd_fail_nth.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ static __attribute__((constructor)) void setup_buffer(void)
4747

4848
buffer = mmap(0, BUFFER_SIZE, PROT_READ | PROT_WRITE,
4949
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
50+
51+
mfd_buffer = memfd_mmap(BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
52+
&mfd);
5053
}
5154

5255
/*
@@ -331,6 +334,42 @@ TEST_FAIL_NTH(basic_fail_nth, map_domain)
331334
return 0;
332335
}
333336

337+
/* iopt_area_fill_domains() and iopt_area_fill_domain() */
338+
TEST_FAIL_NTH(basic_fail_nth, map_file_domain)
339+
{
340+
uint32_t ioas_id;
341+
__u32 stdev_id;
342+
__u32 hwpt_id;
343+
__u64 iova;
344+
345+
self->fd = open("/dev/iommu", O_RDWR);
346+
if (self->fd == -1)
347+
return -1;
348+
349+
if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
350+
return -1;
351+
352+
if (_test_ioctl_set_temp_memory_limit(self->fd, 32))
353+
return -1;
354+
355+
fail_nth_enable();
356+
357+
if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
358+
return -1;
359+
360+
if (_test_ioctl_ioas_map_file(self->fd, ioas_id, mfd, 0, 262144, &iova,
361+
IOMMU_IOAS_MAP_WRITEABLE |
362+
IOMMU_IOAS_MAP_READABLE))
363+
return -1;
364+
365+
if (_test_ioctl_destroy(self->fd, stdev_id))
366+
return -1;
367+
368+
if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
369+
return -1;
370+
return 0;
371+
}
372+
334373
TEST_FAIL_NTH(basic_fail_nth, map_two_domains)
335374
{
336375
uint32_t ioas_id;

tools/testing/selftests/iommu/iommufd_utils.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,28 @@ static inline bool test_bit(unsigned int nr, unsigned long *addr)
4040
static void *buffer;
4141
static unsigned long BUFFER_SIZE;
4242

43+
static void *mfd_buffer;
44+
static int mfd;
45+
4346
static unsigned long PAGE_SIZE;
4447

4548
#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
4649
#define offsetofend(TYPE, MEMBER) \
4750
(offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER))
4851

52+
static inline void *memfd_mmap(size_t length, int prot, int flags, int *mfd_p)
53+
{
54+
int mfd_flags = (flags & MAP_HUGETLB) ? MFD_HUGETLB : 0;
55+
int mfd = memfd_create("buffer", mfd_flags);
56+
57+
if (mfd <= 0)
58+
return MAP_FAILED;
59+
if (ftruncate(mfd, length))
60+
return MAP_FAILED;
61+
*mfd_p = mfd;
62+
return mmap(0, length, prot, flags, mfd, 0);
63+
}
64+
4965
/*
5066
* Have the kernel check the refcount on pages. I don't know why a freshly
5167
* mmap'd anon non-compound page starts out with a ref of 3
@@ -589,6 +605,47 @@ static int _test_ioctl_ioas_unmap(int fd, unsigned int ioas_id, uint64_t iova,
589605
EXPECT_ERRNO(_errno, _test_ioctl_ioas_unmap(self->fd, self->ioas_id, \
590606
iova, length, NULL))
591607

608+
static int _test_ioctl_ioas_map_file(int fd, unsigned int ioas_id, int mfd,
609+
size_t start, size_t length, __u64 *iova,
610+
unsigned int flags)
611+
{
612+
struct iommu_ioas_map_file cmd = {
613+
.size = sizeof(cmd),
614+
.flags = flags,
615+
.ioas_id = ioas_id,
616+
.fd = mfd,
617+
.start = start,
618+
.length = length,
619+
};
620+
int ret;
621+
622+
if (flags & IOMMU_IOAS_MAP_FIXED_IOVA)
623+
cmd.iova = *iova;
624+
625+
ret = ioctl(fd, IOMMU_IOAS_MAP_FILE, &cmd);
626+
*iova = cmd.iova;
627+
return ret;
628+
}
629+
630+
#define test_ioctl_ioas_map_file(mfd, start, length, iova_p) \
631+
ASSERT_EQ(0, \
632+
_test_ioctl_ioas_map_file( \
633+
self->fd, self->ioas_id, mfd, start, length, iova_p, \
634+
IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_READABLE))
635+
636+
#define test_err_ioctl_ioas_map_file(_errno, mfd, start, length, iova_p) \
637+
EXPECT_ERRNO( \
638+
_errno, \
639+
_test_ioctl_ioas_map_file( \
640+
self->fd, self->ioas_id, mfd, start, length, iova_p, \
641+
IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_READABLE))
642+
643+
#define test_ioctl_ioas_map_id_file(ioas_id, mfd, start, length, iova_p) \
644+
ASSERT_EQ(0, \
645+
_test_ioctl_ioas_map_file( \
646+
self->fd, ioas_id, mfd, start, length, iova_p, \
647+
IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_READABLE))
648+
592649
static int _test_ioctl_set_temp_memory_limit(int fd, unsigned int limit)
593650
{
594651
struct iommu_test_cmd memlimit_cmd = {

0 commit comments

Comments
 (0)