On 23/10/2023 21:37, Nicolin Chen wrote: > On Mon, Oct 23, 2023 at 09:15:32PM +0100, Joao Martins wrote: >> External email: Use caution opening links or attachments >> >> >> On 23/10/2023 21:08, Nicolin Chen wrote: >>> On Fri, Oct 20, 2023 at 11:28:02PM +0100, Joao Martins wrote: >>> >>>> +static int iommufd_test_dirty(struct iommufd_ucmd *ucmd, >>>> + unsigned int mockpt_id, unsigned long iova, >>>> + size_t length, unsigned long page_size, >>>> + void __user *uptr, u32 flags) >>>> +{ >>>> + unsigned long i, max = length / page_size; >>>> + struct iommu_test_cmd *cmd = ucmd->cmd; >>>> + struct iommufd_hw_pagetable *hwpt; >>>> + struct mock_iommu_domain *mock; >>>> + int rc, count = 0; >>>> + >>>> + if (iova % page_size || length % page_size || >>>> + (uintptr_t)uptr % page_size) >>>> + return -EINVAL; >>>> + >>>> + hwpt = get_md_pagetable(ucmd, mockpt_id, &mock); >>>> + if (IS_ERR(hwpt)) >>>> + return PTR_ERR(hwpt); >>>> + >>>> + if (!(mock->flags & MOCK_DIRTY_TRACK)) { >>>> + rc = -EINVAL; >>>> + goto out_put; >>>> + } >>>> + >>>> + for (i = 0; i < max; i++) { >>>> + unsigned long cur = iova + i * page_size; >>>> + void *ent, *old; >>>> + >>>> + if (!test_bit(i, (unsigned long *) uptr)) >>>> + continue; >>> >>> Is it okay to test_bit on a user pointer/page? Should we call >>> get_user_pages or so? >>> >> Arggh, let me fix that. >> >> This is where it is failing the selftest for you? >> >> If so, I should paste a snippet for you to test. > > Yea, the crash seems to be caused by this. Possibly some memory > debugging feature that I turned on caught this? > > I tried a test fix and the crash is gone (attaching at EOM). > > However, I still see other failures: > # # RUN iommufd_dirty_tracking.domain_dirty128M.get_dirty_bitmap ... > # # iommufd_utils.h:292:get_dirty_bitmap:Expected nr (32768) == out_dirty (13648) > # # get_dirty_bitmap: Test terminated by assertion > # # FAIL iommufd_dirty_tracking.domain_dirty128M.get_dirty_bitmap > # not ok 147 iommufd_dirty_tracking.domain_dirty128M.get_dirty_bitmap > # # RUN iommufd_dirty_tracking.domain_dirty256M.enforce_dirty ... > # # OK iommufd_dirty_tracking.domain_dirty256M.enforce_dirty > # ok 148 iommufd_dirty_tracking.domain_dirty256M.enforce_dirty > # # RUN iommufd_dirty_tracking.domain_dirty256M.set_dirty_tracking ... > # # OK iommufd_dirty_tracking.domain_dirty256M.set_dirty_tracking > # ok 149 iommufd_dirty_tracking.domain_dirty256M.set_dirty_tracking > # # RUN iommufd_dirty_tracking.domain_dirty256M.device_dirty_capability ... > # # OK iommufd_dirty_tracking.domain_dirty256M.device_dirty_capability > # ok 150 iommufd_dirty_tracking.domain_dirty256M.device_dirty_capability > # # RUN iommufd_dirty_tracking.domain_dirty256M.get_dirty_bitmap ... > # # iommufd_utils.h:292:get_dirty_bitmap:Expected nr (65536) == out_dirty (8923) > > > Maybe page_size isn't the right size? > You are probably just not copying it right. The bitmap APIs treat the pointer as one big array of ulongs and set the right word of it, so your copy_from_user needs to make sure it is copying from the right offset. Given that the tests (of different sizes) exercise the boundaries of the bitmap it eventually exposes. The 256M specifically it could be that I an testing the 2 PAGE_SIZE bitmap, that I offset on purpose (as part of the test). Let me play with it in the meantime and I will paste an diff based on yours. Thanks a lot for digging it through > -------------attaching copy_from_user------------ > diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c > index 8a2c7df85441..daa198809d61 100644 > --- a/drivers/iommu/iommufd/selftest.c > +++ b/drivers/iommu/iommufd/selftest.c > @@ -1103,8 +1103,9 @@ static int iommufd_test_dirty(struct iommufd_ucmd *ucmd, unsigned int mockpt_id, > struct iommufd_hw_pagetable *hwpt; > struct mock_iommu_domain *mock; > int rc, count = 0; > + void *tmp; > > - if (iova % page_size || length % page_size || > + if (iova % page_size || length % page_size || !uptr || > (uintptr_t)uptr % page_size) > return -EINVAL; > > @@ -1117,11 +1118,22 @@ static int iommufd_test_dirty(struct iommufd_ucmd *ucmd, unsigned int mockpt_id, > goto out_put; > } > > + tmp = kvzalloc(page_size, GFP_KERNEL_ACCOUNT); > + if (!tmp) { > + rc = -ENOMEM; > + goto out_put; > + } > + > for (i = 0; i < max; i++) { > unsigned long cur = iova + i * page_size; > void *ent, *old; > > - if (!test_bit(i, (unsigned long *)uptr)) > + if (copy_from_user(tmp, uptr, page_size)) { > + rc = -EFAULT; > + goto out_free; > + } > + > + if (!test_bit(i, (unsigned long *)tmp)) > continue; > > ent = xa_load(&mock->pfns, cur / page_size); > @@ -1138,6 +1150,8 @@ static int iommufd_test_dirty(struct iommufd_ucmd *ucmd, unsigned int mockpt_id, > > cmd->dirty.out_nr_dirty = count; > rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); > +out_free: > + kvfree(tmp); > out_put: > iommufd_put_object(&hwpt->obj); > return rc;