Skip to content

Commit fa1ffdb

Browse files
nicolincjgunthorpe
authored andcommitted
iommufd/selftest: Test iommufd_device_replace()
Allow the selftest to call the function on the mock idev, add some tests to exercise it. Link: https://lore.kernel.org/r/16-v8-6659224517ea+532-iommufd_alloc_jgg@nvidia.com Reviewed-by: Kevin Tian <kevin.tian@intel.com> Tested-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Yi Liu <yi.l.liu@intel.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
1 parent 83f7bc6 commit fa1ffdb

File tree

6 files changed

+149
-4
lines changed

6 files changed

+149
-4
lines changed

drivers/iommu/iommufd/iommufd_test.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ enum {
1717
IOMMU_TEST_OP_ACCESS_PAGES,
1818
IOMMU_TEST_OP_ACCESS_RW,
1919
IOMMU_TEST_OP_SET_TEMP_MEMORY_LIMIT,
20+
IOMMU_TEST_OP_MOCK_DOMAIN_REPLACE,
2021
};
2122

2223
enum {
@@ -52,6 +53,9 @@ struct iommu_test_cmd {
5253
__u32 out_stdev_id;
5354
__u32 out_hwpt_id;
5455
} mock_domain;
56+
struct {
57+
__u32 pt_id;
58+
} mock_domain_replace;
5559
struct {
5660
__aligned_u64 iova;
5761
__aligned_u64 length;

drivers/iommu/iommufd/selftest.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,42 @@ static int iommufd_test_mock_domain(struct iommufd_ucmd *ucmd,
455455
return rc;
456456
}
457457

458+
/* Replace the mock domain with a manually allocated hw_pagetable */
459+
static int iommufd_test_mock_domain_replace(struct iommufd_ucmd *ucmd,
460+
unsigned int device_id, u32 pt_id,
461+
struct iommu_test_cmd *cmd)
462+
{
463+
struct iommufd_object *dev_obj;
464+
struct selftest_obj *sobj;
465+
int rc;
466+
467+
/*
468+
* Prefer to use the OBJ_SELFTEST because the destroy_rwsem will ensure
469+
* it doesn't race with detach, which is not allowed.
470+
*/
471+
dev_obj =
472+
iommufd_get_object(ucmd->ictx, device_id, IOMMUFD_OBJ_SELFTEST);
473+
if (IS_ERR(dev_obj))
474+
return PTR_ERR(dev_obj);
475+
476+
sobj = container_of(dev_obj, struct selftest_obj, obj);
477+
if (sobj->type != TYPE_IDEV) {
478+
rc = -EINVAL;
479+
goto out_dev_obj;
480+
}
481+
482+
rc = iommufd_device_replace(sobj->idev.idev, &pt_id);
483+
if (rc)
484+
goto out_dev_obj;
485+
486+
cmd->mock_domain_replace.pt_id = pt_id;
487+
rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
488+
489+
out_dev_obj:
490+
iommufd_put_object(dev_obj);
491+
return rc;
492+
}
493+
458494
/* Add an additional reserved IOVA to the IOAS */
459495
static int iommufd_test_add_reserved(struct iommufd_ucmd *ucmd,
460496
unsigned int mockpt_id,
@@ -948,6 +984,9 @@ int iommufd_test(struct iommufd_ucmd *ucmd)
948984
cmd->add_reserved.length);
949985
case IOMMU_TEST_OP_MOCK_DOMAIN:
950986
return iommufd_test_mock_domain(ucmd, cmd);
987+
case IOMMU_TEST_OP_MOCK_DOMAIN_REPLACE:
988+
return iommufd_test_mock_domain_replace(
989+
ucmd, cmd->id, cmd->mock_domain_replace.pt_id, cmd);
951990
case IOMMU_TEST_OP_MD_CHECK_MAP:
952991
return iommufd_test_md_check_pa(
953992
ucmd, cmd->id, cmd->check_map.iova,

include/linux/iommufd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,
2323
void iommufd_device_unbind(struct iommufd_device *idev);
2424

2525
int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id);
26+
int iommufd_device_replace(struct iommufd_device *idev, u32 *pt_id);
2627
void iommufd_device_detach(struct iommufd_device *idev);
2728

2829
struct iommufd_ctx *iommufd_device_to_ictx(struct iommufd_device *idev);

tools/testing/selftests/iommu/iommufd.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99

1010
#include "iommufd_utils.h"
1111

12-
static void *buffer;
13-
14-
static unsigned long PAGE_SIZE;
1512
static unsigned long HUGEPAGE_SIZE;
1613

1714
#define MOCK_PAGE_SIZE (PAGE_SIZE / 2)
@@ -1035,6 +1032,7 @@ FIXTURE(iommufd_mock_domain)
10351032
uint32_t ioas_id;
10361033
uint32_t hwpt_id;
10371034
uint32_t hwpt_ids[2];
1035+
uint32_t stdev_ids[2];
10381036
int mmap_flags;
10391037
size_t mmap_buf_size;
10401038
};
@@ -1056,7 +1054,8 @@ FIXTURE_SETUP(iommufd_mock_domain)
10561054
ASSERT_GE(ARRAY_SIZE(self->hwpt_ids), variant->mock_domains);
10571055

10581056
for (i = 0; i != variant->mock_domains; i++)
1059-
test_cmd_mock_domain(self->ioas_id, NULL, &self->hwpt_ids[i]);
1057+
test_cmd_mock_domain(self->ioas_id, &self->stdev_ids[i],
1058+
&self->hwpt_ids[i]);
10601059
self->hwpt_id = self->hwpt_ids[0];
10611060

10621061
self->mmap_flags = MAP_SHARED | MAP_ANONYMOUS;
@@ -1308,6 +1307,36 @@ TEST_F(iommufd_mock_domain, user_copy)
13081307
test_ioctl_destroy(ioas_id);
13091308
}
13101309

1310+
TEST_F(iommufd_mock_domain, replace)
1311+
{
1312+
uint32_t ioas_id;
1313+
1314+
test_ioctl_ioas_alloc(&ioas_id);
1315+
1316+
test_cmd_mock_domain_replace(self->stdev_ids[0], ioas_id);
1317+
1318+
/*
1319+
* Replacing the IOAS causes the prior HWPT to be deallocated, thus we
1320+
* should get enoent when we try to use it.
1321+
*/
1322+
if (variant->mock_domains == 1)
1323+
test_err_mock_domain_replace(ENOENT, self->stdev_ids[0],
1324+
self->hwpt_ids[0]);
1325+
1326+
test_cmd_mock_domain_replace(self->stdev_ids[0], ioas_id);
1327+
if (variant->mock_domains >= 2) {
1328+
test_cmd_mock_domain_replace(self->stdev_ids[0],
1329+
self->hwpt_ids[1]);
1330+
test_cmd_mock_domain_replace(self->stdev_ids[0],
1331+
self->hwpt_ids[1]);
1332+
test_cmd_mock_domain_replace(self->stdev_ids[0],
1333+
self->hwpt_ids[0]);
1334+
}
1335+
1336+
test_cmd_mock_domain_replace(self->stdev_ids[0], self->ioas_id);
1337+
test_ioctl_destroy(ioas_id);
1338+
}
1339+
13111340
/* VFIO compatibility IOCTLs */
13121341

13131342
TEST_F(iommufd, simple_ioctls)

tools/testing/selftests/iommu/iommufd_fail_nth.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ static int writeat(int dfd, const char *fn, const char *val)
4141

4242
static __attribute__((constructor)) void setup_buffer(void)
4343
{
44+
PAGE_SIZE = sysconf(_SC_PAGE_SIZE);
45+
4446
BUFFER_SIZE = 2*1024*1024;
4547

4648
buffer = mmap(0, BUFFER_SIZE, PROT_READ | PROT_WRITE,
@@ -569,4 +571,44 @@ TEST_FAIL_NTH(basic_fail_nth, access_pin_domain)
569571
return 0;
570572
}
571573

574+
/* device.c */
575+
TEST_FAIL_NTH(basic_fail_nth, device)
576+
{
577+
uint32_t ioas_id;
578+
uint32_t ioas_id2;
579+
uint32_t stdev_id;
580+
__u64 iova;
581+
582+
self->fd = open("/dev/iommu", O_RDWR);
583+
if (self->fd == -1)
584+
return -1;
585+
586+
if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
587+
return -1;
588+
589+
if (_test_ioctl_ioas_alloc(self->fd, &ioas_id2))
590+
return -1;
591+
592+
iova = MOCK_APERTURE_START;
593+
if (_test_ioctl_ioas_map(self->fd, ioas_id, buffer, PAGE_SIZE, &iova,
594+
IOMMU_IOAS_MAP_FIXED_IOVA |
595+
IOMMU_IOAS_MAP_WRITEABLE |
596+
IOMMU_IOAS_MAP_READABLE))
597+
return -1;
598+
if (_test_ioctl_ioas_map(self->fd, ioas_id2, buffer, PAGE_SIZE, &iova,
599+
IOMMU_IOAS_MAP_FIXED_IOVA |
600+
IOMMU_IOAS_MAP_WRITEABLE |
601+
IOMMU_IOAS_MAP_READABLE))
602+
return -1;
603+
604+
fail_nth_enable();
605+
606+
if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, NULL))
607+
return -1;
608+
609+
if (_test_cmd_mock_domain_replace(self->fd, stdev_id, ioas_id2, NULL))
610+
return -1;
611+
return 0;
612+
}
613+
572614
TEST_HARNESS_MAIN

tools/testing/selftests/iommu/iommufd_utils.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
static void *buffer;
2020
static unsigned long BUFFER_SIZE;
2121

22+
static unsigned long PAGE_SIZE;
23+
2224
/*
2325
* Have the kernel check the refcount on pages. I don't know why a freshly
2426
* mmap'd anon non-compound page starts out with a ref of 3
@@ -66,6 +68,34 @@ static int _test_cmd_mock_domain(int fd, unsigned int ioas_id, __u32 *stdev_id,
6668
EXPECT_ERRNO(_errno, _test_cmd_mock_domain(self->fd, ioas_id, \
6769
stdev_id, hwpt_id))
6870

71+
static int _test_cmd_mock_domain_replace(int fd, __u32 stdev_id, __u32 pt_id,
72+
__u32 *hwpt_id)
73+
{
74+
struct iommu_test_cmd cmd = {
75+
.size = sizeof(cmd),
76+
.op = IOMMU_TEST_OP_MOCK_DOMAIN_REPLACE,
77+
.id = stdev_id,
78+
.mock_domain_replace = {
79+
.pt_id = pt_id,
80+
},
81+
};
82+
int ret;
83+
84+
ret = ioctl(fd, IOMMU_TEST_CMD, &cmd);
85+
if (ret)
86+
return ret;
87+
if (hwpt_id)
88+
*hwpt_id = cmd.mock_domain_replace.pt_id;
89+
return 0;
90+
}
91+
92+
#define test_cmd_mock_domain_replace(stdev_id, pt_id) \
93+
ASSERT_EQ(0, _test_cmd_mock_domain_replace(self->fd, stdev_id, pt_id, \
94+
NULL))
95+
#define test_err_mock_domain_replace(_errno, stdev_id, pt_id) \
96+
EXPECT_ERRNO(_errno, _test_cmd_mock_domain_replace(self->fd, stdev_id, \
97+
pt_id, NULL))
98+
6999
static int _test_cmd_create_access(int fd, unsigned int ioas_id,
70100
__u32 *access_id, unsigned int flags)
71101
{

0 commit comments

Comments
 (0)