From nobody Sun Feb 8 07:08:09 2026 Received: from mx0b-00082601.pphosted.com (mx0b-00082601.pphosted.com [67.231.153.30]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9F1091A5B8B for ; Mon, 27 Oct 2025 17:34:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.153.30 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761586443; cv=none; b=mXnU2ltbeCIfO4hZN5JaL37Wl5PxzQFN25Ja6rZAt9iCtFsE1R0Da/KOrHS8MYvnCWyv+aOoCfXDfzSqzWGgxzaAM/x4z7C9bYr6dCa+KUZQEokk4jZmSp95TdltkUDdGK5kOcuj/wYDPmDPo/2oVUiBpHNXUFpOxxGjLKWyAxQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761586443; c=relaxed/simple; bh=Vc/SsYshYgWtGiWBSl00U/cMRy3jFTCaFrXnvpawQLA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=BHV1jSfhC9AMItYtW5E4ZDlErseONFDcxDsl5PqhEIVpm8rRCGQoSPMu7F/JVnjypcgPD/a1LrlkXpNTnftCqEsFUGa3mUI1xoIP+mIY/PBuMFNOBso5RDte3RQXyjNZAXf+Ip38BCmFUZczCDY3TSuEjB6qONKy6dfAj6BivEk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b=u2e13J/1; arc=none smtp.client-ip=67.231.153.30 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b="u2e13J/1" Received: from pps.filterd (m0148460.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 59RF6vYk975897 for ; Mon, 27 Oct 2025 10:34:00 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2025-q2; bh=OzYCMuVBq+ZQIkmYYGsKvAwvz51TdK3SjEwPx+hEItc=; b=u2e13J/17QEg aN6a6/gpIHsiTEC+QcqjSkdHyF2NfGTdRTb62cM8KrgGTcXBmTfK7hHKrMjxDcfq TG42INUWqeSOUtzfmDXwTsldt0kwKyQYU4O5bClr2mp1pWhwrgTdf4ZmsMEh6K3m ev7vJ5V/9AxME5ii+urT3cAdn7bzZP8VtMUYkyQMk7k0wcQtJXDqnJyIsVokBVx2 DkVVTWJ66aNhUd+brRFtWv7pUbhlNDb0PPEqMiHF7r/zanzqFqy6cmkTCGQNpbg5 geYf/LrSDgWvL5QrrDXXujZ0sc/s/sO2MJp13FYw1eOU2ni17v+VNOP2moJlKGlG 8fzNNAzSzA== Received: from maileast.thefacebook.com ([163.114.135.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 4a2b3j9dfc-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Mon, 27 Oct 2025 10:34:00 -0700 (PDT) Received: from twshared13080.31.frc3.facebook.com (2620:10d:c0a8:1b::30) by mail.thefacebook.com (2620:10d:c0a9:6f::237c) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.20; Mon, 27 Oct 2025 17:33:59 +0000 Received: by devgpu012.nha5.facebook.com (Postfix, from userid 28580) id 7A56343E094; Mon, 27 Oct 2025 10:33:57 -0700 (PDT) From: Alex Mastro Date: Mon, 27 Oct 2025 10:33:41 -0700 Subject: [PATCH v5 1/5] vfio/type1: sanitize for overflow using check_*_overflow Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20251027-fix-unmap-v5-1-4f0fcf8ffb7d@fb.com> References: <20251027-fix-unmap-v5-0-4f0fcf8ffb7d@fb.com> In-Reply-To: <20251027-fix-unmap-v5-0-4f0fcf8ffb7d@fb.com> To: Alex Williamson CC: Jason Gunthorpe , Alejandro Jimenez , David Matlack , , , Alex Mastro , Jason Gunthorpe X-Mailer: b4 0.13.0 X-FB-Internal: Safe X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMDI3MDE2MyBTYWx0ZWRfX9FdUl3h66hV5 2qp3ZigOEPQLA+mSyzXyLPmpuP92DrCJCLyJtkHcrfLElVBOEUtbeJ/iJy5XIhk1NjoBYPuA41/ /drIFS5aE71N1n3Ss0teJnntMiTplemGxubzV0SR3vaZ0bao6xPj36WBPIIxerZZWgzxzf0qxbg mxCNRuRT2LM+dxkBkn5EFBjMCcxyalAJ92CpfxQvfZSK60ogDK2M98prpQgAMlxThKUcKICYLFb tvdDc4CPJmJP7pfpK7IlmxgNs6n0SoXCracbkIvXnYnUjTLhlIrbpnsmjxXUSdmIdg1dWNi1UP1 yirYV9KZlw4irYAwshdBKHRe9jhW0sTqHDkA9WIo4HgsOtXL0Un39y2tP29fVQdWJqzBOqiHlxS kAryiEp0WKidObJ5eDADpUaxoe8phA== X-Authority-Analysis: v=2.4 cv=H87WAuYi c=1 sm=1 tr=0 ts=68ffad08 cx=c_pps a=MfjaFnPeirRr97d5FC5oHw==:117 a=MfjaFnPeirRr97d5FC5oHw==:17 a=IkcTkHD0fZMA:10 a=x6icFKpwvdMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=yPCof4ZbAAAA:8 a=Ikd4Dj_1AAAA:8 a=FOH2dFAWAAAA:8 a=kyqc8lFLhbGN_ZoCeBMA:9 a=QEXdDO2ut3YA:10 X-Proofpoint-ORIG-GUID: YEj6uZLAB0yFrRpq_pLVGBl3xHmucmot X-Proofpoint-GUID: YEj6uZLAB0yFrRpq_pLVGBl3xHmucmot X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-10-27_07,2025-10-22_01,2025-03-28_01 Adopt check_*_overflow functions to clearly express overflow check intent. Tested-by: Alejandro Jimenez Fixes: 73fa0d10d077 ("vfio: Type1 IOMMU implementation") Reviewed-by: Jason Gunthorpe Reviewed-by: Alejandro Jimenez Signed-off-by: Alex Mastro --- drivers/vfio/vfio_iommu_type1.c | 86 ++++++++++++++++++++++++++++++-------= ---- 1 file changed, 63 insertions(+), 23 deletions(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type= 1.c index 916cad80941c..91b1480b7a37 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "vfio.h" =20 #define DRIVER_VERSION "0.2" @@ -182,7 +183,7 @@ static struct vfio_dma *vfio_find_dma(struct vfio_iommu= *iommu, } =20 static struct rb_node *vfio_find_dma_first_node(struct vfio_iommu *iommu, - dma_addr_t start, u64 size) + dma_addr_t start, size_t size) { struct rb_node *res =3D NULL; struct rb_node *node =3D iommu->dma_list.rb_node; @@ -895,14 +896,20 @@ static int vfio_iommu_type1_pin_pages(void *iommu_dat= a, unsigned long remote_vaddr; struct vfio_dma *dma; bool do_accounting; + dma_addr_t iova_end; + size_t iova_size; =20 - if (!iommu || !pages) + if (!iommu || !pages || npage <=3D 0) return -EINVAL; =20 /* Supported for v2 version only */ if (!iommu->v2) return -EACCES; =20 + if (check_mul_overflow(npage, PAGE_SIZE, &iova_size) || + check_add_overflow(user_iova, iova_size - 1, &iova_end)) + return -EOVERFLOW; + mutex_lock(&iommu->lock); =20 if (WARN_ONCE(iommu->vaddr_invalid_count, @@ -1008,12 +1015,21 @@ static void vfio_iommu_type1_unpin_pages(void *iomm= u_data, { struct vfio_iommu *iommu =3D iommu_data; bool do_accounting; + dma_addr_t iova_end; + size_t iova_size; int i; =20 /* Supported for v2 version only */ if (WARN_ON(!iommu->v2)) return; =20 + if (WARN_ON(npage <=3D 0)) + return; + + if (WARN_ON(check_mul_overflow(npage, PAGE_SIZE, &iova_size) || + check_add_overflow(user_iova, iova_size - 1, &iova_end))) + return; + mutex_lock(&iommu->lock); =20 do_accounting =3D list_empty(&iommu->domain_list); @@ -1374,7 +1390,8 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, int ret =3D -EINVAL, retries =3D 0; unsigned long pgshift; dma_addr_t iova =3D unmap->iova; - u64 size =3D unmap->size; + dma_addr_t iova_end; + size_t size =3D unmap->size; bool unmap_all =3D unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL; bool invalidate_vaddr =3D unmap->flags & VFIO_DMA_UNMAP_FLAG_VADDR; struct rb_node *n, *first_n; @@ -1387,6 +1404,11 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iomm= u, goto unlock; } =20 + if (iova !=3D unmap->iova || size !=3D unmap->size) { + ret =3D -EOVERFLOW; + goto unlock; + } + pgshift =3D __ffs(iommu->pgsize_bitmap); pgsize =3D (size_t)1 << pgshift; =20 @@ -1396,10 +1418,15 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iom= mu, if (unmap_all) { if (iova || size) goto unlock; - size =3D U64_MAX; - } else if (!size || size & (pgsize - 1) || - iova + size - 1 < iova || size > SIZE_MAX) { - goto unlock; + size =3D SIZE_MAX; + } else { + if (!size || size & (pgsize - 1)) + goto unlock; + + if (check_add_overflow(iova, size - 1, &iova_end)) { + ret =3D -EOVERFLOW; + goto unlock; + } } =20 /* When dirty tracking is enabled, allow only min supported pgsize */ @@ -1446,7 +1473,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, if (dma && dma->iova !=3D iova) goto unlock; =20 - dma =3D vfio_find_dma(iommu, iova + size - 1, 0); + dma =3D vfio_find_dma(iommu, iova_end, 0); if (dma && dma->iova + dma->size !=3D iova + size) goto unlock; } @@ -1648,7 +1675,9 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, { bool set_vaddr =3D map->flags & VFIO_DMA_MAP_FLAG_VADDR; dma_addr_t iova =3D map->iova; + dma_addr_t iova_end; unsigned long vaddr =3D map->vaddr; + unsigned long vaddr_end; size_t size =3D map->size; int ret =3D 0, prot =3D 0; size_t pgsize; @@ -1656,8 +1685,15 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, =20 /* Verify that none of our __u64 fields overflow */ if (map->size !=3D size || map->vaddr !=3D vaddr || map->iova !=3D iova) + return -EOVERFLOW; + + if (!size) return -EINVAL; =20 + if (check_add_overflow(iova, size - 1, &iova_end) || + check_add_overflow(vaddr, size - 1, &vaddr_end)) + return -EOVERFLOW; + /* READ/WRITE from device perspective */ if (map->flags & VFIO_DMA_MAP_FLAG_WRITE) prot |=3D IOMMU_WRITE; @@ -1673,13 +1709,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, =20 WARN_ON((pgsize - 1) & PAGE_MASK); =20 - if (!size || (size | iova | vaddr) & (pgsize - 1)) { - ret =3D -EINVAL; - goto out_unlock; - } - - /* Don't allow IOVA or virtual address wrap */ - if (iova + size - 1 < iova || vaddr + size - 1 < vaddr) { + if ((size | iova | vaddr) & (pgsize - 1)) { ret =3D -EINVAL; goto out_unlock; } @@ -1710,7 +1740,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, goto out_unlock; } =20 - if (!vfio_iommu_iova_dma_valid(iommu, iova, iova + size - 1)) { + if (!vfio_iommu_iova_dma_valid(iommu, iova, iova_end)) { ret =3D -EINVAL; goto out_unlock; } @@ -2977,7 +3007,8 @@ static int vfio_iommu_type1_dirty_pages(struct vfio_i= ommu *iommu, struct vfio_iommu_type1_dirty_bitmap_get range; unsigned long pgshift; size_t data_size =3D dirty.argsz - minsz; - size_t iommu_pgsize; + size_t size, iommu_pgsize; + dma_addr_t iova, iova_end; =20 if (!data_size || data_size < sizeof(range)) return -EINVAL; @@ -2986,14 +3017,24 @@ static int vfio_iommu_type1_dirty_pages(struct vfio= _iommu *iommu, sizeof(range))) return -EFAULT; =20 - if (range.iova + range.size < range.iova) + iova =3D range.iova; + size =3D range.size; + + if (iova !=3D range.iova || size !=3D range.size) + return -EOVERFLOW; + + if (!size) return -EINVAL; + + if (check_add_overflow(iova, size - 1, &iova_end)) + return -EOVERFLOW; + if (!access_ok((void __user *)range.bitmap.data, range.bitmap.size)) return -EINVAL; =20 pgshift =3D __ffs(range.bitmap.pgsize); - ret =3D verify_bitmap_size(range.size >> pgshift, + ret =3D verify_bitmap_size(size >> pgshift, range.bitmap.size); if (ret) return ret; @@ -3007,19 +3048,18 @@ static int vfio_iommu_type1_dirty_pages(struct vfio= _iommu *iommu, ret =3D -EINVAL; goto out_unlock; } - if (range.iova & (iommu_pgsize - 1)) { + if (iova & (iommu_pgsize - 1)) { ret =3D -EINVAL; goto out_unlock; } - if (!range.size || range.size & (iommu_pgsize - 1)) { + if (size & (iommu_pgsize - 1)) { ret =3D -EINVAL; goto out_unlock; } =20 if (iommu->dirty_page_tracking) ret =3D vfio_iova_dirty_bitmap(range.bitmap.data, - iommu, range.iova, - range.size, + iommu, iova, size, range.bitmap.pgsize); else ret =3D -EINVAL; --=20 2.47.3 From nobody Sun Feb 8 07:08:09 2026 Received: from mx0b-00082601.pphosted.com (mx0b-00082601.pphosted.com [67.231.153.30]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 202CB317709 for ; Mon, 27 Oct 2025 17:34:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.153.30 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761586446; cv=none; b=R3JJevHlZMJ4PxQZcpqvST4GQmfRuVPbG/lJLUIcg95yIVPmjYpWv5eptbvh80A+IIXr2uFpvAprQXaYla4pGlwXcj4Rkg9opnXSAcYaXUDzEYZHojUjTwYehj4j8Bv1nCXhqS+DRyRs7LkHJNK5J1RvHSa1w+LHLwcLAvt2BVc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761586446; c=relaxed/simple; bh=zH2bltp5SnxsRbXoUh5UiyX6fJZxfu9t7+eKTgtNKhw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=kmmygkG0F8zbFHqjb19zf5mbmuC3RNUmihlBM8jP2iuer6jSs7B4KC46vjLMETmxEeHkBYGE71IAoDA5tnrlWACkv2BG9u4KpYLcSdMgPygSGOm5chHbCvmFvxskOZRLj5LSTuAoX3b3eBVqsGwY8pTy6SgCLW8f9ecDXQLDq3c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b=nfR6F9ty; arc=none smtp.client-ip=67.231.153.30 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b="nfR6F9ty" Received: from pps.filterd (m0148460.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 59RF6vYs975897 for ; Mon, 27 Oct 2025 10:34:04 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2025-q2; bh=5Xtgh45PqrJXrHbQeeYqpMNjm28cym0+HxoQQ807OaM=; b=nfR6F9tyru1+ v0scJppepDG4pIwNDWL08E8LJkbMvaPDn6tQKh3Puu7R6rgYltOAsuhS0wyUYiTg 5kDfs7ERzouc9DsZp1pHEENRApUsPMyMgNS0LKJ4eY1zjsOI3efvcSYgqFjKrw2D tPMrJ5OgdYSOFjKMgW0eFfORBzLdEYxZxHgW0UaQmOz4fdNANL7a4cOdmcm75XiW yYIq8tPeAye8gGc3bIeCUJdhMJiDXmuNWzaZYhQaFqt+Q0sH+MTKTT7g0ERhjZyf QkPGTs6nyW8nBM3hXxyrcoKMqh99NcbCFx4Lednhut76hdmwmzReLQRNr7kZnwiH rcZYhndjZA== Received: from maileast.thefacebook.com ([163.114.135.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 4a2b3j9dfc-9 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Mon, 27 Oct 2025 10:34:03 -0700 (PDT) Received: from twshared28390.17.frc2.facebook.com (2620:10d:c0a8:fe::f072) by mail.thefacebook.com (2620:10d:c0a9:6f::237c) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.20; Mon, 27 Oct 2025 17:34:03 +0000 Received: by devgpu012.nha5.facebook.com (Postfix, from userid 28580) id 7C38743E096; Mon, 27 Oct 2025 10:33:57 -0700 (PDT) From: Alex Mastro Date: Mon, 27 Oct 2025 10:33:42 -0700 Subject: [PATCH v5 2/5] vfio/type1: move iova increment to unmap_unpin_* caller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20251027-fix-unmap-v5-2-4f0fcf8ffb7d@fb.com> References: <20251027-fix-unmap-v5-0-4f0fcf8ffb7d@fb.com> In-Reply-To: <20251027-fix-unmap-v5-0-4f0fcf8ffb7d@fb.com> To: Alex Williamson CC: Jason Gunthorpe , Alejandro Jimenez , David Matlack , , , Alex Mastro , Jason Gunthorpe X-Mailer: b4 0.13.0 X-FB-Internal: Safe X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMDI3MDE2MyBTYWx0ZWRfX36yKdBi4Cn4e fQutMDCZ/Z9zbwHkiUj4n2ImoMwl+g5MztGJwS2RZRt8PxzpLI5YLHZovWIhqTDwbuvbg/jgDHj 2Bbbo85vpK9YcO01bpJXgAfi4KR7J1qFziygZpkrI+QNQom1KLfW/pgTtIRx/OfidbjhrVGRKOI 9TI2c5r9eRW80vOH0p5GQIt81PhGcnFB7AYdGO8frbLHqGzvWIZuPICrbOsmB0++I+0C5BZwB/q J3dIyJaHXnyD0Bnc3sCDyhZ8jnXR0NcNcAODQhESX7DZvAGF0MwZunzwEwnTleVwCd0qKGvfqZu olgak8liQoWn1rexgwJWkln0kjGaeSUZ+Mtn1JZiMGnMRdnD3AMNfn6kAu2veJolsKN2c59YH37 sjuBfleNbIu/Gvq+r/m8T86o4z7ZQw== X-Authority-Analysis: v=2.4 cv=H87WAuYi c=1 sm=1 tr=0 ts=68ffad0b cx=c_pps a=MfjaFnPeirRr97d5FC5oHw==:117 a=MfjaFnPeirRr97d5FC5oHw==:17 a=IkcTkHD0fZMA:10 a=x6icFKpwvdMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=yPCof4ZbAAAA:8 a=Ikd4Dj_1AAAA:8 a=FOH2dFAWAAAA:8 a=PelP7hj50Gaxf9uocr0A:9 a=QEXdDO2ut3YA:10 X-Proofpoint-ORIG-GUID: dJ7bsfaEn0rd7QF9v-MevW4ED-EgLBLn X-Proofpoint-GUID: dJ7bsfaEn0rd7QF9v-MevW4ED-EgLBLn X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-10-27_07,2025-10-22_01,2025-03-28_01 Move incrementing iova to the caller of these functions as part of preparing to handle end of address space map/unmap. Tested-by: Alejandro Jimenez Fixes: 73fa0d10d077 ("vfio: Type1 IOMMU implementation") Reviewed-by: Jason Gunthorpe Reviewed-by: Alejandro Jimenez Signed-off-by: Alex Mastro --- drivers/vfio/vfio_iommu_type1.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type= 1.c index 91b1480b7a37..48bcc0633d44 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -1083,7 +1083,7 @@ static long vfio_sync_unpin(struct vfio_dma *dma, str= uct vfio_domain *domain, #define VFIO_IOMMU_TLB_SYNC_MAX 512 =20 static size_t unmap_unpin_fast(struct vfio_domain *domain, - struct vfio_dma *dma, dma_addr_t *iova, + struct vfio_dma *dma, dma_addr_t iova, size_t len, phys_addr_t phys, long *unlocked, struct list_head *unmapped_list, int *unmapped_cnt, @@ -1093,18 +1093,17 @@ static size_t unmap_unpin_fast(struct vfio_domain *= domain, struct vfio_regions *entry =3D kzalloc(sizeof(*entry), GFP_KERNEL); =20 if (entry) { - unmapped =3D iommu_unmap_fast(domain->domain, *iova, len, + unmapped =3D iommu_unmap_fast(domain->domain, iova, len, iotlb_gather); =20 if (!unmapped) { kfree(entry); } else { - entry->iova =3D *iova; + entry->iova =3D iova; entry->phys =3D phys; entry->len =3D unmapped; list_add_tail(&entry->list, unmapped_list); =20 - *iova +=3D unmapped; (*unmapped_cnt)++; } } @@ -1123,18 +1122,17 @@ static size_t unmap_unpin_fast(struct vfio_domain *= domain, } =20 static size_t unmap_unpin_slow(struct vfio_domain *domain, - struct vfio_dma *dma, dma_addr_t *iova, + struct vfio_dma *dma, dma_addr_t iova, size_t len, phys_addr_t phys, long *unlocked) { - size_t unmapped =3D iommu_unmap(domain->domain, *iova, len); + size_t unmapped =3D iommu_unmap(domain->domain, iova, len); =20 if (unmapped) { - *unlocked +=3D vfio_unpin_pages_remote(dma, *iova, + *unlocked +=3D vfio_unpin_pages_remote(dma, iova, phys >> PAGE_SHIFT, unmapped >> PAGE_SHIFT, false); - *iova +=3D unmapped; cond_resched(); } return unmapped; @@ -1197,16 +1195,18 @@ static long vfio_unmap_unpin(struct vfio_iommu *iom= mu, struct vfio_dma *dma, * First, try to use fast unmap/unpin. In case of failure, * switch to slow unmap/unpin path. */ - unmapped =3D unmap_unpin_fast(domain, dma, &iova, len, phys, + unmapped =3D unmap_unpin_fast(domain, dma, iova, len, phys, &unlocked, &unmapped_region_list, &unmapped_region_cnt, &iotlb_gather); if (!unmapped) { - unmapped =3D unmap_unpin_slow(domain, dma, &iova, len, + unmapped =3D unmap_unpin_slow(domain, dma, iova, len, phys, &unlocked); if (WARN_ON(!unmapped)) break; } + + iova +=3D unmapped; } =20 dma->iommu_mapped =3D false; --=20 2.47.3 From nobody Sun Feb 8 07:08:09 2026 Received: from mx0a-00082601.pphosted.com (mx0a-00082601.pphosted.com [67.231.145.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9282B318131 for ; Mon, 27 Oct 2025 17:34:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.145.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761586459; cv=none; b=ZB4TQi0TsJtJIWsL2LqbnzkIYYTtD7ensnRWWHsWr6AAOT8wW4WQ/AqXSB1bI0VrY4YgvI2V1/vdgbjGkyaDHAfGz7ynaRT5kSQg8cne314cmNrYUBktllOAijIMIi3CMBbJxIWw6fQKsdr57FtUOhVk/m53igrAm1uzHcWKF7c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761586459; c=relaxed/simple; bh=fsUficWSSEw++WUiZPDFihQGx2cEpjBhzsmEvpxHOpY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=hUJnKvwsYsus4Vg8MlsMJDrzdadPQcJl8a4+i+ko/relsk4qgqcjMCx6G3OpMDpr9YKSX5LyPaZXi7HTvkJBme5gNo/2H/8b67eYqmxeRpiJmYcCeqg4JE0Zey+X9KUe8MFpTwRMlPFarzEtCizXnfHwsAOZbhPhDVQPfA5bZIg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b=7Pzu/Moe; arc=none smtp.client-ip=67.231.145.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b="7Pzu/Moe" Received: from pps.filterd (m0109334.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 59RFrud51234687 for ; Mon, 27 Oct 2025 10:34:15 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2025-q2; bh=17DrIKvHY+S2FDBbrn4h28hnqtK9RN4gXAhW5actuwA=; b=7Pzu/MoeiXGS yCt2LxAVBFstfR4JIJQmKCnHhSqyO2M6F3+P+l9kspcA03pE42L2wppbtw3rKf3v tKKodZE+Id7mZA5JU2Xd0gl3ck0v/V3dqvd4zsuMTeowhrL+LFoBFsw6OqQDodCC KC7OmGpewUNSyERbBW6ICu7HUbMZXM3RIxXYzRkTjBOfiSsQ8lXU7u/CtERSuNAb iCne7g2+NTHQrPr/K4ACXsZos2KUVaJ8159W2oNL4cqjfaj4/+CFfkDnZrrnNG8U AT3URQ/b6Ymj3rcvsxLNHtKwlNNRwG/2vNW0UnRea3KgUSp4MSgRwRbu3HsVllVR 7vrWMxRXvQ== Received: from maileast.thefacebook.com ([163.114.135.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 4a2bsd11em-6 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Mon, 27 Oct 2025 10:34:14 -0700 (PDT) Received: from twshared28390.17.frc2.facebook.com (2620:10d:c0a8:1b::8e35) by mail.thefacebook.com (2620:10d:c0a9:6f::8fd4) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.20; Mon, 27 Oct 2025 17:34:03 +0000 Received: by devgpu012.nha5.facebook.com (Postfix, from userid 28580) id 7E05743E098; Mon, 27 Oct 2025 10:33:57 -0700 (PDT) From: Alex Mastro Date: Mon, 27 Oct 2025 10:33:43 -0700 Subject: [PATCH v5 3/5] vfio/type1: handle DMA map/unmap up to the addressable limit Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20251027-fix-unmap-v5-3-4f0fcf8ffb7d@fb.com> References: <20251027-fix-unmap-v5-0-4f0fcf8ffb7d@fb.com> In-Reply-To: <20251027-fix-unmap-v5-0-4f0fcf8ffb7d@fb.com> To: Alex Williamson CC: Jason Gunthorpe , Alejandro Jimenez , David Matlack , , , Alex Mastro , Jason Gunthorpe X-Mailer: b4 0.13.0 X-FB-Internal: Safe X-Authority-Analysis: v=2.4 cv=LrifC3dc c=1 sm=1 tr=0 ts=68ffad16 cx=c_pps a=MfjaFnPeirRr97d5FC5oHw==:117 a=MfjaFnPeirRr97d5FC5oHw==:17 a=IkcTkHD0fZMA:10 a=x6icFKpwvdMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=yPCof4ZbAAAA:8 a=Ikd4Dj_1AAAA:8 a=FOH2dFAWAAAA:8 a=8P58oYQow4jR27pd84AA:9 a=QEXdDO2ut3YA:10 X-Proofpoint-ORIG-GUID: ywKIguP0fet1K7Id0302rRTs68voE6r2 X-Proofpoint-GUID: ywKIguP0fet1K7Id0302rRTs68voE6r2 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMDI3MDE2MyBTYWx0ZWRfX5oBk7gNOIOO7 kImEHGieHjTDjyBhHcOShtavzTYBb9ooXQZVl7ToQKVv5reXWYlFusPsDo4KXm+or9pbrkGtvTP y8+K+VJ+V10YNZYZ52jxvm1stWiAi6HyiWQa46hMUQsFvVPAjzZn7cBs1MPfc1K6gmzvN0i8caO akutKWRPV0OaKWlnQ7J0aUpIwy5t0lKxNxuOaSLbdBEGtiHZSswuslBYxdIcKQ4nrhcpww9Z0pb Q14Byi/acHHs3tMKkS8BJaJtAH9Dpi6e2EeCvoxP3MRaILkrQhTiCyQUzVDwVR1BM3Yyv/S0T3x 9bI8T/b+REo+NdNbuGNBjTzmBekwPI0Hnddst6dBVZ4skd6DBNa/n6sg+bJcq3+hG59BcrraQQ/ hQ+WRY1AgrQazQ+RZpAgT99mZ9bipg== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-10-27_07,2025-10-22_01,2025-03-28_01 Before this commit, it was possible to create end of address space mappings, but unmapping them via VFIO_IOMMU_UNMAP_DMA, replaying them for newly added iommu domains, and querying their dirty pages via VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP was broken due to bugs caused by comparisons against (iova + size) expressions, which overflow to zero. This commit handles DMA map/unmap operations up to the addressable limit by comparing against inclusive end-of-range limits, and changing iteration to perform relative traversals across range sizes, rather than absolute traversals across addresses. vfio_link_dma inserts a zero-sized vfio_dma into the rb-tree, and is only used for that purpose, so discard the size from consideration for the insertion point. Tested-by: Alejandro Jimenez Fixes: 73fa0d10d077 ("vfio: Type1 IOMMU implementation") Reviewed-by: Jason Gunthorpe Reviewed-by: Alejandro Jimenez Signed-off-by: Alex Mastro --- drivers/vfio/vfio_iommu_type1.c | 77 ++++++++++++++++++++++---------------= ---- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type= 1.c index 48bcc0633d44..5167bec14e36 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -168,12 +168,14 @@ static struct vfio_dma *vfio_find_dma(struct vfio_iom= mu *iommu, { struct rb_node *node =3D iommu->dma_list.rb_node; =20 + WARN_ON(!size); + while (node) { struct vfio_dma *dma =3D rb_entry(node, struct vfio_dma, node); =20 - if (start + size <=3D dma->iova) + if (start + size - 1 < dma->iova) node =3D node->rb_left; - else if (start >=3D dma->iova + dma->size) + else if (start > dma->iova + dma->size - 1) node =3D node->rb_right; else return dma; @@ -183,16 +185,19 @@ static struct vfio_dma *vfio_find_dma(struct vfio_iom= mu *iommu, } =20 static struct rb_node *vfio_find_dma_first_node(struct vfio_iommu *iommu, - dma_addr_t start, size_t size) + dma_addr_t start, + dma_addr_t end) { struct rb_node *res =3D NULL; struct rb_node *node =3D iommu->dma_list.rb_node; struct vfio_dma *dma_res =3D NULL; =20 + WARN_ON(end < start); + while (node) { struct vfio_dma *dma =3D rb_entry(node, struct vfio_dma, node); =20 - if (start < dma->iova + dma->size) { + if (start <=3D dma->iova + dma->size - 1) { res =3D node; dma_res =3D dma; if (start >=3D dma->iova) @@ -202,7 +207,7 @@ static struct rb_node *vfio_find_dma_first_node(struct = vfio_iommu *iommu, node =3D node->rb_right; } } - if (res && size && dma_res->iova >=3D start + size) + if (res && dma_res->iova > end) res =3D NULL; return res; } @@ -212,11 +217,13 @@ static void vfio_link_dma(struct vfio_iommu *iommu, s= truct vfio_dma *new) struct rb_node **link =3D &iommu->dma_list.rb_node, *parent =3D NULL; struct vfio_dma *dma; =20 + WARN_ON(new->size !=3D 0); + while (*link) { parent =3D *link; dma =3D rb_entry(parent, struct vfio_dma, node); =20 - if (new->iova + new->size <=3D dma->iova) + if (new->iova <=3D dma->iova) link =3D &(*link)->rb_left; else link =3D &(*link)->rb_right; @@ -1141,12 +1148,12 @@ static size_t unmap_unpin_slow(struct vfio_domain *= domain, static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dm= a, bool do_accounting) { - dma_addr_t iova =3D dma->iova, end =3D dma->iova + dma->size; struct vfio_domain *domain, *d; LIST_HEAD(unmapped_region_list); struct iommu_iotlb_gather iotlb_gather; int unmapped_region_cnt =3D 0; long unlocked =3D 0; + size_t pos =3D 0; =20 if (!dma->size) return 0; @@ -1170,13 +1177,14 @@ static long vfio_unmap_unpin(struct vfio_iommu *iom= mu, struct vfio_dma *dma, } =20 iommu_iotlb_gather_init(&iotlb_gather); - while (iova < end) { + while (pos < dma->size) { size_t unmapped, len; phys_addr_t phys, next; + dma_addr_t iova =3D dma->iova + pos; =20 phys =3D iommu_iova_to_phys(domain->domain, iova); if (WARN_ON(!phys)) { - iova +=3D PAGE_SIZE; + pos +=3D PAGE_SIZE; continue; } =20 @@ -1185,7 +1193,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu= , struct vfio_dma *dma, * may require hardware cache flushing, try to find the * largest contiguous physical memory chunk to unmap. */ - for (len =3D PAGE_SIZE; iova + len < end; len +=3D PAGE_SIZE) { + for (len =3D PAGE_SIZE; pos + len < dma->size; len +=3D PAGE_SIZE) { next =3D iommu_iova_to_phys(domain->domain, iova + len); if (next !=3D phys + len) break; @@ -1206,7 +1214,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu= , struct vfio_dma *dma, break; } =20 - iova +=3D unmapped; + pos +=3D unmapped; } =20 dma->iommu_mapped =3D false; @@ -1298,7 +1306,7 @@ static int update_user_bitmap(u64 __user *bitmap, str= uct vfio_iommu *iommu, } =20 static int vfio_iova_dirty_bitmap(u64 __user *bitmap, struct vfio_iommu *i= ommu, - dma_addr_t iova, size_t size, size_t pgsize) + dma_addr_t iova, dma_addr_t iova_end, size_t pgsize) { struct vfio_dma *dma; struct rb_node *n; @@ -1315,8 +1323,8 @@ static int vfio_iova_dirty_bitmap(u64 __user *bitmap,= struct vfio_iommu *iommu, if (dma && dma->iova !=3D iova) return -EINVAL; =20 - dma =3D vfio_find_dma(iommu, iova + size - 1, 0); - if (dma && dma->iova + dma->size !=3D iova + size) + dma =3D vfio_find_dma(iommu, iova_end, 1); + if (dma && dma->iova + dma->size - 1 !=3D iova_end) return -EINVAL; =20 for (n =3D rb_first(&iommu->dma_list); n; n =3D rb_next(n)) { @@ -1325,7 +1333,7 @@ static int vfio_iova_dirty_bitmap(u64 __user *bitmap,= struct vfio_iommu *iommu, if (dma->iova < iova) continue; =20 - if (dma->iova > iova + size - 1) + if (dma->iova > iova_end) break; =20 ret =3D update_user_bitmap(bitmap, iommu, dma, iova, pgsize); @@ -1418,7 +1426,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, if (unmap_all) { if (iova || size) goto unlock; - size =3D SIZE_MAX; + iova_end =3D ~(dma_addr_t)0; } else { if (!size || size & (pgsize - 1)) goto unlock; @@ -1473,17 +1481,17 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iom= mu, if (dma && dma->iova !=3D iova) goto unlock; =20 - dma =3D vfio_find_dma(iommu, iova_end, 0); - if (dma && dma->iova + dma->size !=3D iova + size) + dma =3D vfio_find_dma(iommu, iova_end, 1); + if (dma && dma->iova + dma->size - 1 !=3D iova_end) goto unlock; } =20 ret =3D 0; - n =3D first_n =3D vfio_find_dma_first_node(iommu, iova, size); + n =3D first_n =3D vfio_find_dma_first_node(iommu, iova, iova_end); =20 while (n) { dma =3D rb_entry(n, struct vfio_dma, node); - if (dma->iova >=3D iova + size) + if (dma->iova > iova_end) break; =20 if (!iommu->v2 && iova > dma->iova) @@ -1813,12 +1821,12 @@ static int vfio_iommu_replay(struct vfio_iommu *iom= mu, =20 for (; n; n =3D rb_next(n)) { struct vfio_dma *dma; - dma_addr_t iova; + size_t pos =3D 0; =20 dma =3D rb_entry(n, struct vfio_dma, node); - iova =3D dma->iova; =20 - while (iova < dma->iova + dma->size) { + while (pos < dma->size) { + dma_addr_t iova =3D dma->iova + pos; phys_addr_t phys; size_t size; =20 @@ -1834,14 +1842,14 @@ static int vfio_iommu_replay(struct vfio_iommu *iom= mu, phys =3D iommu_iova_to_phys(d->domain, iova); =20 if (WARN_ON(!phys)) { - iova +=3D PAGE_SIZE; + pos +=3D PAGE_SIZE; continue; } =20 size =3D PAGE_SIZE; p =3D phys + size; i =3D iova + size; - while (i < dma->iova + dma->size && + while (pos + size < dma->size && p =3D=3D iommu_iova_to_phys(d->domain, i)) { size +=3D PAGE_SIZE; p +=3D PAGE_SIZE; @@ -1849,9 +1857,8 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu, } } else { unsigned long pfn; - unsigned long vaddr =3D dma->vaddr + - (iova - dma->iova); - size_t n =3D dma->iova + dma->size - iova; + unsigned long vaddr =3D dma->vaddr + pos; + size_t n =3D dma->size - pos; long npage; =20 npage =3D vfio_pin_pages_remote(dma, vaddr, @@ -1882,7 +1889,7 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu, goto unwind; } =20 - iova +=3D size; + pos +=3D size; } } =20 @@ -1899,29 +1906,29 @@ static int vfio_iommu_replay(struct vfio_iommu *iom= mu, unwind: for (; n; n =3D rb_prev(n)) { struct vfio_dma *dma =3D rb_entry(n, struct vfio_dma, node); - dma_addr_t iova; + size_t pos =3D 0; =20 if (dma->iommu_mapped) { iommu_unmap(domain->domain, dma->iova, dma->size); continue; } =20 - iova =3D dma->iova; - while (iova < dma->iova + dma->size) { + while (pos < dma->size) { + dma_addr_t iova =3D dma->iova + pos; phys_addr_t phys, p; size_t size; dma_addr_t i; =20 phys =3D iommu_iova_to_phys(domain->domain, iova); if (!phys) { - iova +=3D PAGE_SIZE; + pos +=3D PAGE_SIZE; continue; } =20 size =3D PAGE_SIZE; p =3D phys + size; i =3D iova + size; - while (i < dma->iova + dma->size && + while (pos + size < dma->size && p =3D=3D iommu_iova_to_phys(domain->domain, i)) { size +=3D PAGE_SIZE; p +=3D PAGE_SIZE; @@ -3059,7 +3066,7 @@ static int vfio_iommu_type1_dirty_pages(struct vfio_i= ommu *iommu, =20 if (iommu->dirty_page_tracking) ret =3D vfio_iova_dirty_bitmap(range.bitmap.data, - iommu, iova, size, + iommu, iova, iova_end, range.bitmap.pgsize); else ret =3D -EINVAL; --=20 2.47.3 From nobody Sun Feb 8 07:08:09 2026 Received: from mx0a-00082601.pphosted.com (mx0a-00082601.pphosted.com [67.231.145.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 611CB3195EB for ; Mon, 27 Oct 2025 17:34:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.145.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761586467; cv=none; b=pAy/Ry16heVQFcVNNRwGKLCDaivCuYkXDZJeJW+vknzB0e204O01+rZEw430kutTYhONUA0JFuS83YKRYiOOngpoLnShONnXh9TTPr9rQg+uoura9z/XhJ0JTu2OKHDtUqKcxmdAjlhUxygKhJdtL0mXl8L9D3daSbQRbEfqev8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761586467; c=relaxed/simple; bh=G24kXUl2/1TAts5Q0ehohqPvN68Ye7VZyo+zXcJ3lsA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=RSgktEQaM9Lvat3jBT0FuG4UI1/5SmIgcFpIQ9fjPYqdUjsYY2TaFb2so3APgPV2QueELj/ZLPgGvG13yucwZzP+wLESj2VSjHBDLHyPTMykncv/viUDw6UnzXltohXdkyLiUGyDM+QCrMJsyigIwpZUQD22ozRJDSeXai0k4l4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b=FIcn9Eca; arc=none smtp.client-ip=67.231.145.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b="FIcn9Eca" Received: from pps.filterd (m0109334.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 59RFrudL1234687 for ; Mon, 27 Oct 2025 10:34:24 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2025-q2; bh=/MbEWdUFJbcP82cLDLSYjE8slJtu9iBACdeQFA1CSI8=; b=FIcn9EcaygkA PhfiNhs33GddbMmYIAvpRSQjxOpmEznTa8EUepxfOlV6HJTUic/11mQBkB2B7a4s qiTGaU5SGitHf+YpCAwD8x3wkykDrR+vPl2ZoDLwfAQZthGkjI239xrzWc5Wlfn7 fNkIsr0A/5CEJHgwx3TU/whPkD7aYvxYq9OC6p9JYYC/o02TQkbkf6UgujVOrjx/ QRln7xLHEzodT7I/mzG08YvLmRzMatqpmm/CiwgVGhqU5nuYV4/LwW7k6By7y5kt uZ8Zu4Vq124/6u8rX058Wl6LwbR1/EI3PWWOduK9XGWlZO/TJ667cp6kNA9gk2vm 05oMGGSrMw== Received: from maileast.thefacebook.com ([163.114.135.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 4a2bsd11em-20 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Mon, 27 Oct 2025 10:34:24 -0700 (PDT) Received: from twshared28390.17.frc2.facebook.com (2620:10d:c0a8:fe::f072) by mail.thefacebook.com (2620:10d:c0a9:6f::8fd4) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.20; Mon, 27 Oct 2025 17:34:03 +0000 Received: by devgpu012.nha5.facebook.com (Postfix, from userid 28580) id 8012F43E09A; Mon, 27 Oct 2025 10:33:57 -0700 (PDT) From: Alex Mastro Date: Mon, 27 Oct 2025 10:33:44 -0700 Subject: [PATCH v5 4/5] vfio: selftests: update DMA map/unmap helpers to support more test kinds Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20251027-fix-unmap-v5-4-4f0fcf8ffb7d@fb.com> References: <20251027-fix-unmap-v5-0-4f0fcf8ffb7d@fb.com> In-Reply-To: <20251027-fix-unmap-v5-0-4f0fcf8ffb7d@fb.com> To: Alex Williamson CC: Jason Gunthorpe , Alejandro Jimenez , David Matlack , , , Alex Mastro X-Mailer: b4 0.13.0 X-FB-Internal: Safe X-Authority-Analysis: v=2.4 cv=LrifC3dc c=1 sm=1 tr=0 ts=68ffad20 cx=c_pps a=MfjaFnPeirRr97d5FC5oHw==:117 a=MfjaFnPeirRr97d5FC5oHw==:17 a=IkcTkHD0fZMA:10 a=x6icFKpwvdMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=FOH2dFAWAAAA:8 a=mN9a-mZmZOQI0s6eON8A:9 a=QEXdDO2ut3YA:10 X-Proofpoint-ORIG-GUID: nVKbAXn-56R-p6M1e4av_sf-gP95IRi6 X-Proofpoint-GUID: nVKbAXn-56R-p6M1e4av_sf-gP95IRi6 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMDI3MDE2MyBTYWx0ZWRfX+2NjINe7Gj50 yKDNN5M/74Iv2FU3Cpm6inSsGacE6tkgVH3cjD+Wtqr9qHTkzVA+h0KUSlkWnWRexlXaonwGkUS 0jWDIJJ1Svic4pIaXFjDh24UGCGYl+RkOgYtRpM3od/UsDpLL3HOuFRK/dFuOAtq+uVQglejNN4 vvLuW2rEXkHcVmuCTQbeJnk+PZNRC75vmmQs+Xx7An8i7tRBpnxEeaVp6XQT81Av30yXA/PFzu8 ROU2SODYICSD93az+0tO0BYyeBsurU1rD5GI4ghEkInYGFLtr/Fx2ngjZYy424Y7jmbHcjf9oho xTL71409RvsihDRGkiZ1VdRQmcXVByIyoA9pX0MGvf9gOELhRcn9UWivPN7v6eaFkwXLNuhdhdP 11w6BgQEhPmynXH69tSOz+5lvU+PeA== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-10-27_07,2025-10-22_01,2025-03-28_01 Add __vfio_pci_dma_* helpers which return -errno from the underlying ioctls. Add __vfio_pci_dma_unmap_all to test more unmapping code paths. Add an out unmapped arg to report the unmapped byte size. The existing vfio_pci_dma_* functions, which are intended for happy-path usage (assert on failure) are now thin wrappers on top of the double-underscore helpers. Signed-off-by: Alex Mastro --- .../testing/selftests/vfio/lib/include/vfio_util.h | 27 +++++- tools/testing/selftests/vfio/lib/vfio_pci_device.c | 105 ++++++++++++++++-= ---- .../testing/selftests/vfio/vfio_dma_mapping_test.c | 5 +- 3 files changed, 109 insertions(+), 28 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/t= esting/selftests/vfio/lib/include/vfio_util.h index ed31606e01b7..240409bf5f8a 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -206,10 +206,29 @@ struct vfio_pci_device *vfio_pci_device_init(const ch= ar *bdf, const char *iommu_ void vfio_pci_device_cleanup(struct vfio_pci_device *device); void vfio_pci_device_reset(struct vfio_pci_device *device); =20 -void vfio_pci_dma_map(struct vfio_pci_device *device, - struct vfio_dma_region *region); -void vfio_pci_dma_unmap(struct vfio_pci_device *device, - struct vfio_dma_region *region); +int __vfio_pci_dma_map(struct vfio_pci_device *device, + struct vfio_dma_region *region); +int __vfio_pci_dma_unmap(struct vfio_pci_device *device, + struct vfio_dma_region *region, + u64 *unmapped); +int __vfio_pci_dma_unmap_all(struct vfio_pci_device *device, u64 *unmapped= ); + +static inline void vfio_pci_dma_map(struct vfio_pci_device *device, + struct vfio_dma_region *region) +{ + VFIO_ASSERT_EQ(__vfio_pci_dma_map(device, region), 0); +} + +static inline void vfio_pci_dma_unmap(struct vfio_pci_device *device, + struct vfio_dma_region *region) +{ + VFIO_ASSERT_EQ(__vfio_pci_dma_unmap(device, region, NULL), 0); +} + +static inline void vfio_pci_dma_unmap_all(struct vfio_pci_device *device) +{ + VFIO_ASSERT_EQ(__vfio_pci_dma_unmap_all(device, NULL), 0); +} =20 void vfio_pci_config_access(struct vfio_pci_device *device, bool write, size_t config, size_t size, void *data); diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/tes= ting/selftests/vfio/lib/vfio_pci_device.c index 0921b2451ba5..af43d8c07199 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -141,7 +142,7 @@ static void vfio_pci_irq_get(struct vfio_pci_device *de= vice, u32 index, ioctl_assert(device->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info); } =20 -static void vfio_iommu_dma_map(struct vfio_pci_device *device, +static int vfio_iommu_dma_map(struct vfio_pci_device *device, struct vfio_dma_region *region) { struct vfio_iommu_type1_dma_map args =3D { @@ -152,10 +153,13 @@ static void vfio_iommu_dma_map(struct vfio_pci_device= *device, .size =3D region->size, }; =20 - ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &args); + if (ioctl(device->container_fd, VFIO_IOMMU_MAP_DMA, &args)) + return -errno; + + return 0; } =20 -static void iommufd_dma_map(struct vfio_pci_device *device, +static int iommufd_dma_map(struct vfio_pci_device *device, struct vfio_dma_region *region) { struct iommu_ioas_map args =3D { @@ -169,54 +173,109 @@ static void iommufd_dma_map(struct vfio_pci_device *= device, .ioas_id =3D device->ioas_id, }; =20 - ioctl_assert(device->iommufd, IOMMU_IOAS_MAP, &args); + if (ioctl(device->iommufd, IOMMU_IOAS_MAP, &args)) + return -errno; + + return 0; } =20 -void vfio_pci_dma_map(struct vfio_pci_device *device, +int __vfio_pci_dma_map(struct vfio_pci_device *device, struct vfio_dma_region *region) { + int ret; + if (device->iommufd) - iommufd_dma_map(device, region); + ret =3D iommufd_dma_map(device, region); else - vfio_iommu_dma_map(device, region); + ret =3D vfio_iommu_dma_map(device, region); + + if (ret) + return ret; =20 list_add(®ion->link, &device->dma_regions); + + return 0; } =20 -static void vfio_iommu_dma_unmap(struct vfio_pci_device *device, - struct vfio_dma_region *region) +static int vfio_iommu_dma_unmap(int fd, u64 iova, u64 size, u32 flags, + u64 *unmapped) { struct vfio_iommu_type1_dma_unmap args =3D { .argsz =3D sizeof(args), - .iova =3D region->iova, - .size =3D region->size, + .iova =3D iova, + .size =3D size, + .flags =3D flags, }; =20 - ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &args); + if (ioctl(fd, VFIO_IOMMU_UNMAP_DMA, &args)) + return -errno; + + if (unmapped) + *unmapped =3D args.size; + + return 0; } =20 -static void iommufd_dma_unmap(struct vfio_pci_device *device, - struct vfio_dma_region *region) +static int iommufd_dma_unmap(int fd, u64 iova, u64 length, u32 ioas_id, + u64 *unmapped) { struct iommu_ioas_unmap args =3D { .size =3D sizeof(args), - .iova =3D region->iova, - .length =3D region->size, - .ioas_id =3D device->ioas_id, + .iova =3D iova, + .length =3D length, + .ioas_id =3D ioas_id, }; =20 - ioctl_assert(device->iommufd, IOMMU_IOAS_UNMAP, &args); + if (ioctl(fd, IOMMU_IOAS_UNMAP, &args)) + return -errno; + + if (unmapped) + *unmapped =3D args.length; + + return 0; } =20 -void vfio_pci_dma_unmap(struct vfio_pci_device *device, - struct vfio_dma_region *region) +int __vfio_pci_dma_unmap(struct vfio_pci_device *device, + struct vfio_dma_region *region, u64 *unmapped) { + int ret; + if (device->iommufd) - iommufd_dma_unmap(device, region); + ret =3D iommufd_dma_unmap(device->iommufd, region->iova, + region->size, device->ioas_id, + unmapped); else - vfio_iommu_dma_unmap(device, region); + ret =3D vfio_iommu_dma_unmap(device->container_fd, region->iova, + region->size, 0, unmapped); + + if (ret) + return ret; + + list_del_init(®ion->link); + + return 0; +} + +int __vfio_pci_dma_unmap_all(struct vfio_pci_device *device, u64 *unmapped) +{ + int ret; + struct vfio_dma_region *curr, *next; + + if (device->iommufd) + ret =3D iommufd_dma_unmap(device->iommufd, 0, UINT64_MAX, + device->ioas_id, unmapped); + else + ret =3D vfio_iommu_dma_unmap(device->container_fd, 0, 0, + VFIO_DMA_UNMAP_FLAG_ALL, unmapped); + + if (ret) + return ret; + + list_for_each_entry_safe(curr, next, &device->dma_regions, link) { + list_del_init(&curr->link); + } =20 - list_del(®ion->link); + return 0; } =20 static void vfio_pci_region_get(struct vfio_pci_device *device, int index, diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/t= esting/selftests/vfio/vfio_dma_mapping_test.c index ab19c54a774d..a38966e8e5a6 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -129,6 +129,7 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) struct vfio_dma_region region; struct iommu_mapping mapping; u64 mapping_size =3D size; + u64 unmapped; int rc; =20 region.vaddr =3D mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); @@ -184,7 +185,9 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) } =20 unmap: - vfio_pci_dma_unmap(self->device, ®ion); + rc =3D __vfio_pci_dma_unmap(self->device, ®ion, &unmapped); + ASSERT_EQ(rc, 0); + ASSERT_EQ(unmapped, region.size); printf("Unmapped IOVA 0x%lx\n", region.iova); ASSERT_EQ(INVALID_IOVA, __to_iova(self->device, region.vaddr)); ASSERT_NE(0, iommu_mapping_get(device_bdf, region.iova, &mapping)); --=20 2.47.3 From nobody Sun Feb 8 07:08:09 2026 Received: from mx0b-00082601.pphosted.com (mx0b-00082601.pphosted.com [67.231.153.30]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CDBD43176E6 for ; Mon, 27 Oct 2025 17:34:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.153.30 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761586455; cv=none; b=r650Dxphl3ebnzMNNFbMN2sVymF81jSaN6zTgL4qsCMvFT4JoQXxDeyN9m50Zrkm/cmynKRjoQkQJkc+nnESS8/T8S18vBeblmjLli5CDGtNUWPAnJn4x4hhyxhJKlgMZgSa0Omi9trGeNICHHqlDqFaeUNmUUU0SDZ0raLr0wA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761586455; c=relaxed/simple; bh=H9IL4XRZ3ZnMteiXQauLbRFmZlQrFK0JU+yM7o2khx0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=EfVY3OqdUrdNEm3qtpK6KQVg1D284O5qCTpwk7k9nWzdYoai9y03Cvpemb69ERJq12ChQu7Ap6ayCOodGwKZefJqdQU9kIn+BzKOj84GnkwcJySfXb9S0AGavAMdp3Dy182fEaT9JSlJTGHVyp4OInp0a6hg19//es0KWThzf5M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b=J3tUBHb4; arc=none smtp.client-ip=67.231.153.30 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b="J3tUBHb4" Received: from pps.filterd (m0109332.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 59RHTWP01219781 for ; Mon, 27 Oct 2025 10:34:12 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2025-q2; bh=pc2Zitp21NxmWPvKCj1mQ9fXN3rBoC1SGqxs7K25EH4=; b=J3tUBHb4iZKK YrGN91JRM8FRkCopM1CteHkSE0fDty1npA5fKtGLBwGmJyzYeo0XKE6vEfuESr99 LgpH1pjGBE14/0Hpc4p3lVMQTtiW7KvJp0A1ztGgXCprgsBubXycsAFcR/oyHPHI 6u0IP9Kms5LZz59tzyhT6yc5LI9lNjAjv0cQK0ro/w3VUNdMurmzNNP0AQ/nCviV 16zTQm/qEp2arxG2fvlzqxK4+Psr3tGLa4kA7+d1BK+YgIZ0zgscFVd/wg8kdwz9 P0AyNhmHTPm09g1WPhKCoX5yDatgyKPvTJNewqOoBaFsDz/wyu3tjHiZI4P8UPHS W/FojrZuvw== Received: from maileast.thefacebook.com ([163.114.135.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 4a284etxgs-3 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Mon, 27 Oct 2025 10:34:12 -0700 (PDT) Received: from twshared125961.16.frc2.facebook.com (2620:10d:c0a8:1b::30) by mail.thefacebook.com (2620:10d:c0a9:6f::237c) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.20; Mon, 27 Oct 2025 17:34:11 +0000 Received: by devgpu012.nha5.facebook.com (Postfix, from userid 28580) id 8211F43E09C; Mon, 27 Oct 2025 10:33:57 -0700 (PDT) From: Alex Mastro Date: Mon, 27 Oct 2025 10:33:45 -0700 Subject: [PATCH v5 5/5] vfio: selftests: add end of address space DMA map/unmap tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20251027-fix-unmap-v5-5-4f0fcf8ffb7d@fb.com> References: <20251027-fix-unmap-v5-0-4f0fcf8ffb7d@fb.com> In-Reply-To: <20251027-fix-unmap-v5-0-4f0fcf8ffb7d@fb.com> To: Alex Williamson CC: Jason Gunthorpe , Alejandro Jimenez , David Matlack , , , Alex Mastro X-Mailer: b4 0.13.0 X-FB-Internal: Safe X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMDI3MDE2MyBTYWx0ZWRfX9gr8tmQWZJPA efPHJs7TqzdG/vDGmbZpOaP38tpB4pcrp+lMzuDXaARmz84T+uWDINGf97caubDjH5fFvGPmRpc MuMVyAVbgGWmrOpPjPvEi4DEFAF7kkA9DgcBt/SFNsdaAo9pCsJ41r0EZYpmy8dP8Rh2sLcvG1o +4bqc91GQ0IeG18gsLzCNQNbFex/7ToDmDME3YnjBeG/CqoVTupSxkhMCPaqpwsGwxA5eIl9lF5 Rlm/ApYHXLLHFVWD9jk8IAjffkMpDWQBy48egbYz1C0LhCzmw4H7Q1F0I6aOfGBZuPLzwXyB3AJ 80tHJeQ3V1xmL04hEi5xN3wjAj9AAXliNE0zyx0iyDfiYbZVA6Q9JK4Dfji4kLYbwT53Aj3h8ux EmLUTH8nVV8Utardby38i8B1Ob6mOQ== X-Proofpoint-ORIG-GUID: UWw_IfPADrF_v9Q44csJMw_vBs58e2lB X-Proofpoint-GUID: UWw_IfPADrF_v9Q44csJMw_vBs58e2lB X-Authority-Analysis: v=2.4 cv=OaWVzxTY c=1 sm=1 tr=0 ts=68ffad14 cx=c_pps a=MfjaFnPeirRr97d5FC5oHw==:117 a=MfjaFnPeirRr97d5FC5oHw==:17 a=IkcTkHD0fZMA:10 a=x6icFKpwvdMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=FOH2dFAWAAAA:8 a=roStD_RBd83EyHEBywkA:9 a=QEXdDO2ut3YA:10 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-10-27_07,2025-10-22_01,2025-03-28_01 Add tests which validate dma map/unmap at the end of address space. Add negative test cases for checking that overflowing ioctl args fail with the expected errno. Signed-off-by: Alex Mastro Reviewed-by: David Matlack --- .../testing/selftests/vfio/vfio_dma_mapping_test.c | 89 ++++++++++++++++++= ++++ 1 file changed, 89 insertions(+) diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/t= esting/selftests/vfio/vfio_dma_mapping_test.c index a38966e8e5a6..2c38bc17232e 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -112,6 +112,8 @@ FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous, 0, 0); FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_2mb, SZ_2M, MAP_HUGE= TLB | MAP_HUGE_2MB); FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_1gb, SZ_1G, MAP_HUGE= TLB | MAP_HUGE_1GB); =20 +#undef FIXTURE_VARIANT_ADD_IOMMU_MODE + FIXTURE_SETUP(vfio_dma_mapping_test) { self->device =3D vfio_pci_device_init(device_bdf, variant->iommu_mode); @@ -195,6 +197,93 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) ASSERT_TRUE(!munmap(region.vaddr, size)); } =20 +FIXTURE(vfio_dma_map_limit_test) { + struct vfio_pci_device *device; + struct vfio_dma_region region; + size_t mmap_size; +}; + +FIXTURE_VARIANT(vfio_dma_map_limit_test) { + const char *iommu_mode; +}; + +#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode) \ +FIXTURE_VARIANT_ADD(vfio_dma_map_limit_test, _iommu_mode) { \ + .iommu_mode =3D #_iommu_mode, \ +} + +FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(); + +#undef FIXTURE_VARIANT_ADD_IOMMU_MODE + +FIXTURE_SETUP(vfio_dma_map_limit_test) +{ + u64 region_size =3D getpagesize(); + /* + * Over-allocate mmap by double the size to provide enough backing vaddr + * for overflow tests + */ + self->mmap_size =3D 2 * region_size; + struct vfio_dma_region *region =3D &self->region; + + self->device =3D vfio_pci_device_init(device_bdf, variant->iommu_mode); + region->vaddr =3D mmap(NULL, self->mmap_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + ASSERT_NE(region->vaddr, MAP_FAILED); + + /* One page prior to the end of address space */ + region->iova =3D ~(iova_t)0 & ~(region_size - 1); + region->size =3D region_size; +} + +FIXTURE_TEARDOWN(vfio_dma_map_limit_test) +{ + vfio_pci_device_cleanup(self->device); + ASSERT_EQ(munmap(self->region.vaddr, self->mmap_size), 0); +} + +TEST_F(vfio_dma_map_limit_test, unmap_range) +{ + struct vfio_dma_region *region =3D &self->region; + u64 unmapped; + int rc; + + vfio_pci_dma_map(self->device, region); + ASSERT_EQ(region->iova, to_iova(self->device, region->vaddr)); + + rc =3D __vfio_pci_dma_unmap(self->device, region, &unmapped); + ASSERT_EQ(rc, 0); + ASSERT_EQ(unmapped, region->size); +} + +TEST_F(vfio_dma_map_limit_test, unmap_all) +{ + struct vfio_dma_region *region =3D &self->region; + u64 unmapped; + int rc; + + vfio_pci_dma_map(self->device, region); + ASSERT_EQ(region->iova, to_iova(self->device, region->vaddr)); + + rc =3D __vfio_pci_dma_unmap_all(self->device, &unmapped); + ASSERT_EQ(rc, 0); + ASSERT_EQ(unmapped, region->size); +} + +TEST_F(vfio_dma_map_limit_test, overflow) +{ + struct vfio_dma_region *region =3D &self->region; + int rc; + + region->size =3D self->mmap_size; + + rc =3D __vfio_pci_dma_map(self->device, region); + ASSERT_EQ(rc, -EOVERFLOW); + + rc =3D __vfio_pci_dma_unmap(self->device, region, NULL); + ASSERT_EQ(rc, -EOVERFLOW); +} + int main(int argc, char *argv[]) { device_bdf =3D vfio_selftests_get_bdf(&argc, argv); --=20 2.47.3