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>
This commit is contained in:
parent
83f7bc6fdf
commit
fa1ffdb9e2
|
@ -17,6 +17,7 @@ enum {
|
|||
IOMMU_TEST_OP_ACCESS_PAGES,
|
||||
IOMMU_TEST_OP_ACCESS_RW,
|
||||
IOMMU_TEST_OP_SET_TEMP_MEMORY_LIMIT,
|
||||
IOMMU_TEST_OP_MOCK_DOMAIN_REPLACE,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -52,6 +53,9 @@ struct iommu_test_cmd {
|
|||
__u32 out_stdev_id;
|
||||
__u32 out_hwpt_id;
|
||||
} mock_domain;
|
||||
struct {
|
||||
__u32 pt_id;
|
||||
} mock_domain_replace;
|
||||
struct {
|
||||
__aligned_u64 iova;
|
||||
__aligned_u64 length;
|
||||
|
|
|
@ -455,6 +455,42 @@ out_sobj:
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* Replace the mock domain with a manually allocated hw_pagetable */
|
||||
static int iommufd_test_mock_domain_replace(struct iommufd_ucmd *ucmd,
|
||||
unsigned int device_id, u32 pt_id,
|
||||
struct iommu_test_cmd *cmd)
|
||||
{
|
||||
struct iommufd_object *dev_obj;
|
||||
struct selftest_obj *sobj;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Prefer to use the OBJ_SELFTEST because the destroy_rwsem will ensure
|
||||
* it doesn't race with detach, which is not allowed.
|
||||
*/
|
||||
dev_obj =
|
||||
iommufd_get_object(ucmd->ictx, device_id, IOMMUFD_OBJ_SELFTEST);
|
||||
if (IS_ERR(dev_obj))
|
||||
return PTR_ERR(dev_obj);
|
||||
|
||||
sobj = container_of(dev_obj, struct selftest_obj, obj);
|
||||
if (sobj->type != TYPE_IDEV) {
|
||||
rc = -EINVAL;
|
||||
goto out_dev_obj;
|
||||
}
|
||||
|
||||
rc = iommufd_device_replace(sobj->idev.idev, &pt_id);
|
||||
if (rc)
|
||||
goto out_dev_obj;
|
||||
|
||||
cmd->mock_domain_replace.pt_id = pt_id;
|
||||
rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
|
||||
|
||||
out_dev_obj:
|
||||
iommufd_put_object(dev_obj);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Add an additional reserved IOVA to the IOAS */
|
||||
static int iommufd_test_add_reserved(struct iommufd_ucmd *ucmd,
|
||||
unsigned int mockpt_id,
|
||||
|
@ -948,6 +984,9 @@ int iommufd_test(struct iommufd_ucmd *ucmd)
|
|||
cmd->add_reserved.length);
|
||||
case IOMMU_TEST_OP_MOCK_DOMAIN:
|
||||
return iommufd_test_mock_domain(ucmd, cmd);
|
||||
case IOMMU_TEST_OP_MOCK_DOMAIN_REPLACE:
|
||||
return iommufd_test_mock_domain_replace(
|
||||
ucmd, cmd->id, cmd->mock_domain_replace.pt_id, cmd);
|
||||
case IOMMU_TEST_OP_MD_CHECK_MAP:
|
||||
return iommufd_test_md_check_pa(
|
||||
ucmd, cmd->id, cmd->check_map.iova,
|
||||
|
|
|
@ -23,6 +23,7 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,
|
|||
void iommufd_device_unbind(struct iommufd_device *idev);
|
||||
|
||||
int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id);
|
||||
int iommufd_device_replace(struct iommufd_device *idev, u32 *pt_id);
|
||||
void iommufd_device_detach(struct iommufd_device *idev);
|
||||
|
||||
struct iommufd_ctx *iommufd_device_to_ictx(struct iommufd_device *idev);
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
|
||||
#include "iommufd_utils.h"
|
||||
|
||||
static void *buffer;
|
||||
|
||||
static unsigned long PAGE_SIZE;
|
||||
static unsigned long HUGEPAGE_SIZE;
|
||||
|
||||
#define MOCK_PAGE_SIZE (PAGE_SIZE / 2)
|
||||
|
@ -1035,6 +1032,7 @@ FIXTURE(iommufd_mock_domain)
|
|||
uint32_t ioas_id;
|
||||
uint32_t hwpt_id;
|
||||
uint32_t hwpt_ids[2];
|
||||
uint32_t stdev_ids[2];
|
||||
int mmap_flags;
|
||||
size_t mmap_buf_size;
|
||||
};
|
||||
|
@ -1056,7 +1054,8 @@ FIXTURE_SETUP(iommufd_mock_domain)
|
|||
ASSERT_GE(ARRAY_SIZE(self->hwpt_ids), variant->mock_domains);
|
||||
|
||||
for (i = 0; i != variant->mock_domains; i++)
|
||||
test_cmd_mock_domain(self->ioas_id, NULL, &self->hwpt_ids[i]);
|
||||
test_cmd_mock_domain(self->ioas_id, &self->stdev_ids[i],
|
||||
&self->hwpt_ids[i]);
|
||||
self->hwpt_id = self->hwpt_ids[0];
|
||||
|
||||
self->mmap_flags = MAP_SHARED | MAP_ANONYMOUS;
|
||||
|
@ -1308,6 +1307,36 @@ TEST_F(iommufd_mock_domain, user_copy)
|
|||
test_ioctl_destroy(ioas_id);
|
||||
}
|
||||
|
||||
TEST_F(iommufd_mock_domain, replace)
|
||||
{
|
||||
uint32_t ioas_id;
|
||||
|
||||
test_ioctl_ioas_alloc(&ioas_id);
|
||||
|
||||
test_cmd_mock_domain_replace(self->stdev_ids[0], ioas_id);
|
||||
|
||||
/*
|
||||
* Replacing the IOAS causes the prior HWPT to be deallocated, thus we
|
||||
* should get enoent when we try to use it.
|
||||
*/
|
||||
if (variant->mock_domains == 1)
|
||||
test_err_mock_domain_replace(ENOENT, self->stdev_ids[0],
|
||||
self->hwpt_ids[0]);
|
||||
|
||||
test_cmd_mock_domain_replace(self->stdev_ids[0], ioas_id);
|
||||
if (variant->mock_domains >= 2) {
|
||||
test_cmd_mock_domain_replace(self->stdev_ids[0],
|
||||
self->hwpt_ids[1]);
|
||||
test_cmd_mock_domain_replace(self->stdev_ids[0],
|
||||
self->hwpt_ids[1]);
|
||||
test_cmd_mock_domain_replace(self->stdev_ids[0],
|
||||
self->hwpt_ids[0]);
|
||||
}
|
||||
|
||||
test_cmd_mock_domain_replace(self->stdev_ids[0], self->ioas_id);
|
||||
test_ioctl_destroy(ioas_id);
|
||||
}
|
||||
|
||||
/* VFIO compatibility IOCTLs */
|
||||
|
||||
TEST_F(iommufd, simple_ioctls)
|
||||
|
|
|
@ -41,6 +41,8 @@ static int writeat(int dfd, const char *fn, const char *val)
|
|||
|
||||
static __attribute__((constructor)) void setup_buffer(void)
|
||||
{
|
||||
PAGE_SIZE = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
BUFFER_SIZE = 2*1024*1024;
|
||||
|
||||
buffer = mmap(0, BUFFER_SIZE, PROT_READ | PROT_WRITE,
|
||||
|
@ -569,4 +571,44 @@ TEST_FAIL_NTH(basic_fail_nth, access_pin_domain)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* device.c */
|
||||
TEST_FAIL_NTH(basic_fail_nth, device)
|
||||
{
|
||||
uint32_t ioas_id;
|
||||
uint32_t ioas_id2;
|
||||
uint32_t stdev_id;
|
||||
__u64 iova;
|
||||
|
||||
self->fd = open("/dev/iommu", O_RDWR);
|
||||
if (self->fd == -1)
|
||||
return -1;
|
||||
|
||||
if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
|
||||
return -1;
|
||||
|
||||
if (_test_ioctl_ioas_alloc(self->fd, &ioas_id2))
|
||||
return -1;
|
||||
|
||||
iova = MOCK_APERTURE_START;
|
||||
if (_test_ioctl_ioas_map(self->fd, ioas_id, buffer, PAGE_SIZE, &iova,
|
||||
IOMMU_IOAS_MAP_FIXED_IOVA |
|
||||
IOMMU_IOAS_MAP_WRITEABLE |
|
||||
IOMMU_IOAS_MAP_READABLE))
|
||||
return -1;
|
||||
if (_test_ioctl_ioas_map(self->fd, ioas_id2, buffer, PAGE_SIZE, &iova,
|
||||
IOMMU_IOAS_MAP_FIXED_IOVA |
|
||||
IOMMU_IOAS_MAP_WRITEABLE |
|
||||
IOMMU_IOAS_MAP_READABLE))
|
||||
return -1;
|
||||
|
||||
fail_nth_enable();
|
||||
|
||||
if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, NULL))
|
||||
return -1;
|
||||
|
||||
if (_test_cmd_mock_domain_replace(self->fd, stdev_id, ioas_id2, NULL))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
static void *buffer;
|
||||
static unsigned long BUFFER_SIZE;
|
||||
|
||||
static unsigned long PAGE_SIZE;
|
||||
|
||||
/*
|
||||
* Have the kernel check the refcount on pages. I don't know why a freshly
|
||||
* 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,
|
|||
EXPECT_ERRNO(_errno, _test_cmd_mock_domain(self->fd, ioas_id, \
|
||||
stdev_id, hwpt_id))
|
||||
|
||||
static int _test_cmd_mock_domain_replace(int fd, __u32 stdev_id, __u32 pt_id,
|
||||
__u32 *hwpt_id)
|
||||
{
|
||||
struct iommu_test_cmd cmd = {
|
||||
.size = sizeof(cmd),
|
||||
.op = IOMMU_TEST_OP_MOCK_DOMAIN_REPLACE,
|
||||
.id = stdev_id,
|
||||
.mock_domain_replace = {
|
||||
.pt_id = pt_id,
|
||||
},
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = ioctl(fd, IOMMU_TEST_CMD, &cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (hwpt_id)
|
||||
*hwpt_id = cmd.mock_domain_replace.pt_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define test_cmd_mock_domain_replace(stdev_id, pt_id) \
|
||||
ASSERT_EQ(0, _test_cmd_mock_domain_replace(self->fd, stdev_id, pt_id, \
|
||||
NULL))
|
||||
#define test_err_mock_domain_replace(_errno, stdev_id, pt_id) \
|
||||
EXPECT_ERRNO(_errno, _test_cmd_mock_domain_replace(self->fd, stdev_id, \
|
||||
pt_id, NULL))
|
||||
|
||||
static int _test_cmd_create_access(int fd, unsigned int ioas_id,
|
||||
__u32 *access_id, unsigned int flags)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue