Align down walk_data->addr before the increment by page size to prevent the missing dirty pages on IOMMU_HWPT_GET_DIRTY_BITMAP ioctl. As Commit e21952d72b47 ("iommufd/iova_bitmap: Ensure that iova_bitmap_set() handles the full IOVA") mentioned, the requested iova range can begin in the middle of the large page (e.g., 2MB page block). So incrementing walk address by large page size (e.g., 2M) could bypass next dirty'd small pages. Fixes: 4fe88fd8b4ae ("iommu/io-pgtable-arm: Add read_and_clear_dirty() support") Cc: stable@vger.kernel.org Signed-off-by: Seongjun Hong --- drivers/iommu/io-pgtable-arm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 476c0e25631a..01c3f9cd5d9c 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -821,7 +821,7 @@ static int io_pgtable_visit(struct arm_lpae_io_pgtable *data, return ret; if (iopte_leaf(pte, lvl, iop->fmt)) { - walk_data->addr += size; + walk_data->addr = ALIGN_DOWN(walk_data->addr, size) + size; return 0; } @@ -868,7 +868,9 @@ static int visit_dirty(struct io_pgtable_walk_data *walk_data, int lvl, return 0; if (iopte_writeable_dirty(*ptep)) { - iommu_dirty_bitmap_record(dirty, walk_data->addr, size); + u64 iova = ALIGN_DOWN(walk_data->addr, size); + + iommu_dirty_bitmap_record(dirty, iova, size); if (!(walk_data->flags & IOMMU_DIRTY_NO_CLEAR)) iopte_set_writeable_clean(ptep); } -- 2.43.0