Commit d8086722 authored by Joao Martins's avatar Joao Martins Committed by Jason Zeng
Browse files

iommufd/selftest: Test IOMMU_HWPT_ALLOC_DIRTY_TRACKING

mainline inclusion
from mainline-v6.7-rc1
commit 266ce58989ba05e2a24460fdbf402d766c2e3870
category: feature
bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I8Y6AM
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?266ce58989ba05e2a24460fdbf402d766c2e3870

--------------------------------

In order to selftest the iommu domain dirty enforcing implement the
mock_domain necessary support and add a new dev_flags to test that the
hwpt_alloc/attach_device fails as expected.

Expand the existing mock_domain fixture with a enforce_dirty test that
exercises the hwpt_alloc and device attachment.

Intel-SIG: 266ce58989ba iommufd/selftest: Test IOMMU_HWPT_ALLOC_DIRTY_TRACKING
Backport IOMMUFD Dirty Tracking

Link: https://lore.kernel.org/r/20231024135109.73787-15-joao.m.martins@oracle.com


Signed-off-by: default avatarJoao Martins <joao.m.martins@oracle.com>
Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
[ jz: amend commit log ]
Signed-off-by: default avatarJason Zeng <jason.zeng@intel.com>
parent 3e1b6103
Loading
Loading
Loading
Loading
+36 −1
Original line number Diff line number Diff line
@@ -119,6 +119,11 @@ static void mock_domain_blocking_free(struct iommu_domain *domain)
static int mock_domain_nop_attach(struct iommu_domain *domain,
				  struct device *dev)
{
	struct mock_dev *mdev = container_of(dev, struct mock_dev, dev);

	if (domain->dirty_ops && (mdev->flags & MOCK_FLAGS_DEVICE_NO_DIRTY))
		return -EINVAL;

	return 0;
}

@@ -147,6 +152,25 @@ static void *mock_domain_hw_info(struct device *dev, u32 *length, u32 *type)
	return info;
}

static int mock_domain_set_dirty_tracking(struct iommu_domain *domain,
					  bool enable)
{
	return 0;
}

static int mock_domain_read_and_clear_dirty(struct iommu_domain *domain,
					    unsigned long iova, size_t size,
					    unsigned long flags,
					    struct iommu_dirty_bitmap *dirty)
{
	return 0;
}

const struct iommu_dirty_ops dirty_ops = {
	.set_dirty_tracking = mock_domain_set_dirty_tracking,
	.read_and_clear_dirty = mock_domain_read_and_clear_dirty,
};

static const struct iommu_ops mock_ops;

static struct iommu_domain *mock_domain_alloc(unsigned int iommu_domain_type)
@@ -174,12 +198,20 @@ static struct iommu_domain *mock_domain_alloc(unsigned int iommu_domain_type)
static struct iommu_domain *
mock_domain_alloc_user(struct device *dev, u32 flags)
{
	struct mock_dev *mdev = container_of(dev, struct mock_dev, dev);
	struct iommu_domain *domain;

	if (flags & (~IOMMU_HWPT_ALLOC_NEST_PARENT))
	if (flags &
	    (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING)))
		return ERR_PTR(-EOPNOTSUPP);

	if ((flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING) &&
	    (mdev->flags & MOCK_FLAGS_DEVICE_NO_DIRTY))
		return ERR_PTR(-EOPNOTSUPP);

	domain = mock_domain_alloc(IOMMU_DOMAIN_UNMANAGED);
	if (domain && !(mdev->flags & MOCK_FLAGS_DEVICE_NO_DIRTY))
		domain->dirty_ops = &dirty_ops;
	if (!domain)
		domain = ERR_PTR(-ENOMEM);
	return domain;
@@ -387,6 +419,9 @@ static struct mock_dev *mock_dev_create(unsigned long dev_flags)
	struct mock_dev *mdev;
	int rc;

	if (dev_flags & ~(MOCK_FLAGS_DEVICE_NO_DIRTY))
		return ERR_PTR(-EINVAL);

	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
	if (!mdev)
		return ERR_PTR(-ENOMEM);
+49 −0
Original line number Diff line number Diff line
@@ -1433,6 +1433,55 @@ TEST_F(iommufd_mock_domain, alloc_hwpt)
	}
}

FIXTURE(iommufd_dirty_tracking)
{
	int fd;
	uint32_t ioas_id;
	uint32_t hwpt_id;
	uint32_t stdev_id;
	uint32_t idev_id;
};

FIXTURE_SETUP(iommufd_dirty_tracking)
{
	self->fd = open("/dev/iommu", O_RDWR);
	ASSERT_NE(-1, self->fd);

	test_ioctl_ioas_alloc(&self->ioas_id);
	test_cmd_mock_domain(self->ioas_id, &self->stdev_id, &self->hwpt_id,
			     &self->idev_id);
}

FIXTURE_TEARDOWN(iommufd_dirty_tracking)
{
	teardown_iommufd(self->fd, _metadata);
}

TEST_F(iommufd_dirty_tracking, enforce_dirty)
{
	uint32_t ioas_id, stddev_id, idev_id;
	uint32_t hwpt_id, _hwpt_id;
	uint32_t dev_flags;

	/* Regular case */
	dev_flags = MOCK_FLAGS_DEVICE_NO_DIRTY;
	test_cmd_hwpt_alloc(self->idev_id, self->ioas_id,
			    IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);
	test_cmd_mock_domain(hwpt_id, &stddev_id, NULL, NULL);
	test_err_mock_domain_flags(EINVAL, hwpt_id, dev_flags, &stddev_id,
				   NULL);
	test_ioctl_destroy(stddev_id);
	test_ioctl_destroy(hwpt_id);

	/* IOMMU device does not support dirty tracking */
	test_ioctl_ioas_alloc(&ioas_id);
	test_cmd_mock_domain_flags(ioas_id, dev_flags, &stddev_id, &_hwpt_id,
				   &idev_id);
	test_err_hwpt_alloc(EOPNOTSUPP, idev_id, ioas_id,
			    IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);
	test_ioctl_destroy(stddev_id);
}

/* VFIO compatibility IOCTLs */

TEST_F(iommufd, simple_ioctls)
+3 −0
Original line number Diff line number Diff line
@@ -98,6 +98,9 @@ static int _test_cmd_mock_domain_flags(int fd, unsigned int ioas_id,
		*idev_id = cmd.mock_domain_flags.out_idev_id;
	return 0;
}
#define test_cmd_mock_domain_flags(ioas_id, flags, stdev_id, hwpt_id, idev_id) \
	ASSERT_EQ(0, _test_cmd_mock_domain_flags(self->fd, ioas_id, flags,     \
						 stdev_id, hwpt_id, idev_id))
#define test_err_mock_domain_flags(_errno, ioas_id, flags, stdev_id, hwpt_id) \
	EXPECT_ERRNO(_errno,                                                  \
		     _test_cmd_mock_domain_flags(self->fd, ioas_id, flags,    \