Commit fa1ffdb9 authored by Nicolin Chen's avatar Nicolin Chen Committed by Jason Gunthorpe
Browse files

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: default avatarKevin Tian <kevin.tian@intel.com>
Tested-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarYi Liu <yi.l.liu@intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 83f7bc6f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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;
+39 −0
Original line number Diff line number Diff line
@@ -455,6 +455,42 @@ static int iommufd_test_mock_domain(struct iommufd_ucmd *ucmd,
	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,
+1 −0
Original line number Diff line number Diff line
@@ -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);
+33 −4
Original line number Diff line number Diff line
@@ -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)
+42 −0
Original line number Diff line number Diff line
@@ -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
Loading