On Mon, Oct 28, 2024 at 07:52:10AM -0700, Nicolin Chen wrote: > On Mon, Oct 28, 2024 at 10:03:09AM -0300, Jason Gunthorpe wrote: > > On Mon, Oct 28, 2024 at 11:24:10AM +0800, Zhangfei Gao wrote: > > > > > > +/** > > > > + * iommufd_viommu_alloc_hwpt_nested() - Get a hwpt_nested for a vIOMMU > > > > + * @viommu: vIOMMU ojbect to associate the hwpt_nested/domain with > > > > + * @user_data: user_data pointer. Must be valid > > > > + * > > > > + * Allocate a new IOMMU_DOMAIN_NESTED for a vIOMMU and return it as a NESTED > > > > + * hw_pagetable. > > > > + */ > > > > +static struct iommufd_hwpt_nested * > > > > +iommufd_viommu_alloc_hwpt_nested(struct iommufd_viommu *viommu, u32 flags, > > > > + const struct iommu_user_data *user_data) > > > > +{ > > > > + struct iommufd_hwpt_nested *hwpt_nested; > > > > + struct iommufd_hw_pagetable *hwpt; > > > > + int rc; > > > > + > > > > + if (flags) > > > > + return ERR_PTR(-EOPNOTSUPP); > > > > > > This check should be removed. > > > > > > When a user page fault is required, IOMMU_HWPT_FAULT_ID_VALID is set. > > > if (cmd->flags & IOMMU_HWPT_FAULT_ID_VALID) { > > > > It can't just be removed.. > > > > I suspect that IOMMU_HWPT_FAULT_ID_VALID should not be set on the > > nested domain but on the parent? > > By giving another look, > > In iommufd_hwpt_paging_alloc(), we reject IOMMU_HWPT_FAULT_ID_VALID: > const u32 valid_flags = IOMMU_HWPT_ALLOC_NEST_PARENT | > IOMMU_HWPT_ALLOC_DIRTY_TRACKING; > ... > if (flags & ~valid_flags) > return ERR_PTR(-EOPNOTSUPP); > > In iommufd_hwpt_nested_alloc(), we mask the flag away: > if ((flags & ~IOMMU_HWPT_FAULT_ID_VALID) || > !user_data->len || !ops->domain_alloc_user) > return ERR_PTR(-EOPNOTSUPP); > ... > hwpt->domain = ops->domain_alloc_user(idev->dev, > flags & ~IOMMU_HWPT_FAULT_ID_VALID, > parent->common.domain, user_data); > > Then, in the common function it has a section of > if (cmd->flags & IOMMU_HWPT_FAULT_ID_VALID) { > ... > > It seems that this IOMMU_HWPT_FAULT_ID_VALID is for nested domains? > > So, aligning with that, here we need: > if ((flags & ~IOMMU_HWPT_FAULT_ID_VALID) || !user_data->len) > return ERR_PTR(-EOPNOTSUPP); I added a TEST_F for the coverage: +TEST_F(iommufd_viommu, viommu_alloc_nested_iopf) +{ + struct iommu_hwpt_selftest data = { + .iotlb = IOMMU_TEST_IOTLB_DEFAULT, + }; + uint32_t viommu_id = self->viommu_id; + uint32_t dev_id = self->device_id; + uint32_t iopf_hwpt_id; + uint32_t fault_id; + uint32_t fault_fd; + + if (self->device_id) { + test_ioctl_fault_alloc(&fault_id, &fault_fd); + test_err_hwpt_alloc_iopf( + ENOENT, dev_id, viommu_id, UINT32_MAX, + IOMMU_HWPT_FAULT_ID_VALID, &iopf_hwpt_id, + IOMMU_HWPT_DATA_SELFTEST, &data, sizeof(data)); + test_err_hwpt_alloc_iopf( + EOPNOTSUPP, dev_id, viommu_id, fault_id, + IOMMU_HWPT_FAULT_ID_VALID | (1 << 31), &iopf_hwpt_id, + IOMMU_HWPT_DATA_SELFTEST, &data, sizeof(data)); + test_cmd_hwpt_alloc_iopf( + dev_id, viommu_id, fault_id, IOMMU_HWPT_FAULT_ID_VALID, + &iopf_hwpt_id, IOMMU_HWPT_DATA_SELFTEST, &data, + sizeof(data)); + + test_cmd_mock_domain_replace(self->stdev_id, iopf_hwpt_id); + EXPECT_ERRNO(EBUSY, + _test_ioctl_destroy(self->fd, iopf_hwpt_id)); + test_cmd_trigger_iopf(dev_id, fault_fd); + + test_cmd_mock_domain_replace(self->stdev_id, self->ioas_id); + test_ioctl_destroy(iopf_hwpt_id); + close(fault_fd); + test_ioctl_destroy(fault_id); + } +} Thanks Nicolin