On Fri, Apr 21, 2023 at 10:09:35AM -0300, Jason Gunthorpe wrote: > On Fri, Apr 21, 2023 at 01:20:13AM -0700, Nicolin Chen wrote: > > > +/** > > + * struct iommufd_device_set_data - ioctl(IOMMU_DEVICE_SET_DATA) > > + * @size: sizeof(struct iommufd_device_set_data) > > + * @dev_id: The device to set a device data > > + * @data_uptr: User pointer of the device user data. > > + * @data_len: Length of the device user data. > > + */ > > +struct iommufd_device_set_data { > > + __u32 size; > > + __u32 dev_id; > > + __aligned_u64 data_uptr; > > + __u32 data_len; > > +}; > > +#define IOMMU_DEVICE_SET_DATA _IO(IOMMUFD_TYPE, IOMMUFD_CMD_DEVICE_SET_DATA) > > + > > +/** > > + * struct iommufd_device_unset_data - ioctl(IOMMU_DEVICE_UNSET_DATA) > > + * @size: sizeof(struct iommufd_device_unset_data) > > + * @dev_id: The device to unset its device data > > + */ > > +struct iommufd_device_unset_data { > > + __u32 size; > > + __u32 dev_id; > > +}; > > +#define IOMMU_DEVICE_UNSET_DATA _IO(IOMMUFD_TYPE, IOMMUFD_CMD_DEVICE_UNSET_DATA) > > > > Maybe just like this? > > How would the iommu_ops backing this work? How about the following piece? Needs a test with QEMU though.. static const size_t iommufd_device_data_size[] = { [IOMMU_HW_INFO_TYPE_NONE] = 0, [IOMMU_HW_INFO_TYPE_INTEL_VTD] = 0, [IOMMU_HW_INFO_TYPE_ARM_SMMUV3] = sizeof(struct iommu_device_data_arm_smmuv3), }; int iommufd_device_set_data(struct iommufd_ucmd *ucmd) { struct iommufd_device_set_data *cmd = ucmd->cmd; struct iommufd_device *idev; const struct iommu_ops *ops; void *data = NULL; u32 klen = 0; int rc; if (!cmd->data_uptr || !cmd->data_len) return -EINVAL; idev = iommufd_get_device(ucmd, cmd->dev_id); if (IS_ERR(idev)) return PTR_ERR(idev); ops = dev_iommu_ops(idev->dev); if (!ops || !ops->set_dev_data_user || !ops->unset_dev_data_user || ops->hw_info_type >= ARRAY_SIZE(iommufd_device_data_size)) { rc = -EOPNOTSUPP; goto out_put_idev; } klen = iommufd_device_data_size[ops->hw_info_type]; if (!klen) { rc = -EOPNOTSUPP; goto out_put_idev; } data = kzalloc(klen, GFP_KERNEL); if (!data) { rc = -ENOMEM; goto out_put_idev; } if (copy_struct_from_user(data, klen, u64_to_user_ptr(cmd->data_uptr), cmd->data_len)) { rc = -EFAULT; goto out_free_data; } rc = ops->set_dev_data_user(idev->dev, data); out_free_data: kfree(data); out_put_idev: iommufd_put_object(&idev->obj); return rc; }