Skip to content

Commit 331e33d

Browse files
Kirti Wankhedeawilliam
authored andcommitted
vfio iommu: Update UNMAP_DMA ioctl to get dirty bitmap before unmap
DMA mapped pages, including those pinned by mdev vendor drivers, might get unpinned and unmapped while migration is active and device is still running. For example, in pre-copy phase while guest driver could access those pages, host device or vendor driver can dirty these mapped pages. Such pages should be marked dirty so as to maintain memory consistency for a user making use of dirty page tracking. To get bitmap during unmap, user should allocate memory for bitmap, set it all zeros, set size of allocated memory, set page size to be considered for bitmap and set flag VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP. Signed-off-by: Kirti Wankhede <[email protected]> Reviewed-by: Neo Jia <[email protected]> Reviewed-by: Cornelia Huck <[email protected]> Reviewed-by: Yan Zhao <[email protected]> Signed-off-by: Alex Williamson <[email protected]>
1 parent d6a4c18 commit 331e33d

File tree

2 files changed

+61
-11
lines changed

2 files changed

+61
-11
lines changed

drivers/vfio/vfio_iommu_type1.c

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,23 +1049,25 @@ static int verify_bitmap_size(uint64_t npages, uint64_t bitmap_size)
10491049
}
10501050

10511051
static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
1052-
struct vfio_iommu_type1_dma_unmap *unmap)
1052+
struct vfio_iommu_type1_dma_unmap *unmap,
1053+
struct vfio_bitmap *bitmap)
10531054
{
1054-
uint64_t mask;
10551055
struct vfio_dma *dma, *dma_last = NULL;
1056-
size_t unmapped = 0;
1056+
size_t unmapped = 0, pgsize;
10571057
int ret = 0, retries = 0;
1058+
unsigned long pgshift;
10581059

10591060
mutex_lock(&iommu->lock);
10601061

1061-
mask = ((uint64_t)1 << __ffs(iommu->pgsize_bitmap)) - 1;
1062+
pgshift = __ffs(iommu->pgsize_bitmap);
1063+
pgsize = (size_t)1 << pgshift;
10621064

1063-
if (unmap->iova & mask) {
1065+
if (unmap->iova & (pgsize - 1)) {
10641066
ret = -EINVAL;
10651067
goto unlock;
10661068
}
10671069

1068-
if (!unmap->size || unmap->size & mask) {
1070+
if (!unmap->size || unmap->size & (pgsize - 1)) {
10691071
ret = -EINVAL;
10701072
goto unlock;
10711073
}
@@ -1076,9 +1078,15 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
10761078
goto unlock;
10771079
}
10781080

1079-
WARN_ON(mask & PAGE_MASK);
1080-
again:
1081+
/* When dirty tracking is enabled, allow only min supported pgsize */
1082+
if ((unmap->flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) &&
1083+
(!iommu->dirty_page_tracking || (bitmap->pgsize != pgsize))) {
1084+
ret = -EINVAL;
1085+
goto unlock;
1086+
}
10811087

1088+
WARN_ON((pgsize - 1) & PAGE_MASK);
1089+
again:
10821090
/*
10831091
* vfio-iommu-type1 (v1) - User mappings were coalesced together to
10841092
* avoid tracking individual mappings. This means that the granularity
@@ -1159,6 +1167,14 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
11591167
mutex_lock(&iommu->lock);
11601168
goto again;
11611169
}
1170+
1171+
if (unmap->flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) {
1172+
ret = update_user_bitmap(bitmap->data, dma,
1173+
unmap->iova, pgsize);
1174+
if (ret)
1175+
break;
1176+
}
1177+
11621178
unmapped += dma->size;
11631179
vfio_remove_dma(iommu, dma);
11641180
}
@@ -2497,17 +2513,40 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
24972513

24982514
} else if (cmd == VFIO_IOMMU_UNMAP_DMA) {
24992515
struct vfio_iommu_type1_dma_unmap unmap;
2500-
long ret;
2516+
struct vfio_bitmap bitmap = { 0 };
2517+
int ret;
25012518

25022519
minsz = offsetofend(struct vfio_iommu_type1_dma_unmap, size);
25032520

25042521
if (copy_from_user(&unmap, (void __user *)arg, minsz))
25052522
return -EFAULT;
25062523

2507-
if (unmap.argsz < minsz || unmap.flags)
2524+
if (unmap.argsz < minsz ||
2525+
unmap.flags & ~VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP)
25082526
return -EINVAL;
25092527

2510-
ret = vfio_dma_do_unmap(iommu, &unmap);
2528+
if (unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) {
2529+
unsigned long pgshift;
2530+
2531+
if (unmap.argsz < (minsz + sizeof(bitmap)))
2532+
return -EINVAL;
2533+
2534+
if (copy_from_user(&bitmap,
2535+
(void __user *)(arg + minsz),
2536+
sizeof(bitmap)))
2537+
return -EFAULT;
2538+
2539+
if (!access_ok((void __user *)bitmap.data, bitmap.size))
2540+
return -EINVAL;
2541+
2542+
pgshift = __ffs(bitmap.pgsize);
2543+
ret = verify_bitmap_size(unmap.size >> pgshift,
2544+
bitmap.size);
2545+
if (ret)
2546+
return ret;
2547+
}
2548+
2549+
ret = vfio_dma_do_unmap(iommu, &unmap, &bitmap);
25112550
if (ret)
25122551
return ret;
25132552

include/uapi/linux/vfio.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,12 +1048,23 @@ struct vfio_bitmap {
10481048
* field. No guarantee is made to the user that arbitrary unmaps of iova
10491049
* or size different from those used in the original mapping call will
10501050
* succeed.
1051+
* VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP should be set to get the dirty bitmap
1052+
* before unmapping IO virtual addresses. When this flag is set, the user must
1053+
* provide a struct vfio_bitmap in data[]. User must provide zero-allocated
1054+
* memory via vfio_bitmap.data and its size in the vfio_bitmap.size field.
1055+
* A bit in the bitmap represents one page, of user provided page size in
1056+
* vfio_bitmap.pgsize field, consecutively starting from iova offset. Bit set
1057+
* indicates that the page at that offset from iova is dirty. A Bitmap of the
1058+
* pages in the range of unmapped size is returned in the user-provided
1059+
* vfio_bitmap.data.
10511060
*/
10521061
struct vfio_iommu_type1_dma_unmap {
10531062
__u32 argsz;
10541063
__u32 flags;
1064+
#define VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP (1 << 0)
10551065
__u64 iova; /* IO virtual address */
10561066
__u64 size; /* Size of mapping (bytes) */
1067+
__u8 data[];
10571068
};
10581069

10591070
#define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)

0 commit comments

Comments
 (0)