mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 15:39:42 -04:00
Merge tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd
Pull iommufd fixes from Jason Gunthorpe: - Fix dirty tracking bitmap collection when using reporting bitmaps that are not neatly aligned to u64's or match the IO page table radix tree layout. - Add self tests to cover the cases that were found to be broken. - Add missing enforcement of invalidation type in the uapi. - Fix selftest config generation * tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd: selftests/iommu: fix the config fragment iommufd: Reject non-zero data_type if no data_len is provided iommufd/iova_bitmap: Consider page offset for the pages to be pinned iommufd/selftest: Add mock IO hugepages tests iommufd/selftest: Hugepage mock domain support iommufd/selftest: Refactor mock_domain_read_and_clear_dirty() iommufd/selftest: Refactor dirty bitmap tests iommufd/iova_bitmap: Handle recording beyond the mapped pages iommufd/selftest: Test u64 unaligned bitmaps iommufd/iova_bitmap: Switch iova_bitmap::bitmap to an u8 array iommufd/iova_bitmap: Bounds check mapped::pages access
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
CONFIG_IOMMUFD
|
||||
CONFIG_IOMMUFD_TEST
|
||||
CONFIG_IOMMUFD=y
|
||||
CONFIG_FAULT_INJECTION=y
|
||||
CONFIG_IOMMUFD_TEST=y
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
static unsigned long HUGEPAGE_SIZE;
|
||||
|
||||
#define MOCK_PAGE_SIZE (PAGE_SIZE / 2)
|
||||
#define MOCK_HUGE_PAGE_SIZE (512 * MOCK_PAGE_SIZE)
|
||||
|
||||
static unsigned long get_huge_page_size(void)
|
||||
{
|
||||
@@ -1716,10 +1717,12 @@ FIXTURE(iommufd_dirty_tracking)
|
||||
FIXTURE_VARIANT(iommufd_dirty_tracking)
|
||||
{
|
||||
unsigned long buffer_size;
|
||||
bool hugepages;
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(iommufd_dirty_tracking)
|
||||
{
|
||||
int mmap_flags;
|
||||
void *vrc;
|
||||
int rc;
|
||||
|
||||
@@ -1732,25 +1735,41 @@ FIXTURE_SETUP(iommufd_dirty_tracking)
|
||||
variant->buffer_size, rc);
|
||||
}
|
||||
|
||||
mmap_flags = MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED;
|
||||
if (variant->hugepages) {
|
||||
/*
|
||||
* MAP_POPULATE will cause the kernel to fail mmap if THPs are
|
||||
* not available.
|
||||
*/
|
||||
mmap_flags |= MAP_HUGETLB | MAP_POPULATE;
|
||||
}
|
||||
assert((uintptr_t)self->buffer % HUGEPAGE_SIZE == 0);
|
||||
vrc = mmap(self->buffer, variant->buffer_size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
mmap_flags, -1, 0);
|
||||
assert(vrc == self->buffer);
|
||||
|
||||
self->page_size = MOCK_PAGE_SIZE;
|
||||
self->bitmap_size =
|
||||
variant->buffer_size / self->page_size / BITS_PER_BYTE;
|
||||
|
||||
/* Provision with an extra (MOCK_PAGE_SIZE) for the unaligned case */
|
||||
/* Provision with an extra (PAGE_SIZE) for the unaligned case */
|
||||
rc = posix_memalign(&self->bitmap, PAGE_SIZE,
|
||||
self->bitmap_size + MOCK_PAGE_SIZE);
|
||||
self->bitmap_size + PAGE_SIZE);
|
||||
assert(!rc);
|
||||
assert(self->bitmap);
|
||||
assert((uintptr_t)self->bitmap % PAGE_SIZE == 0);
|
||||
|
||||
test_ioctl_ioas_alloc(&self->ioas_id);
|
||||
test_cmd_mock_domain(self->ioas_id, &self->stdev_id, &self->hwpt_id,
|
||||
&self->idev_id);
|
||||
/* Enable 1M mock IOMMU hugepages */
|
||||
if (variant->hugepages) {
|
||||
test_cmd_mock_domain_flags(self->ioas_id,
|
||||
MOCK_FLAGS_DEVICE_HUGE_IOVA,
|
||||
&self->stdev_id, &self->hwpt_id,
|
||||
&self->idev_id);
|
||||
} else {
|
||||
test_cmd_mock_domain(self->ioas_id, &self->stdev_id,
|
||||
&self->hwpt_id, &self->idev_id);
|
||||
}
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(iommufd_dirty_tracking)
|
||||
@@ -1784,12 +1803,26 @@ FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty128M)
|
||||
.buffer_size = 128UL * 1024UL * 1024UL,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty128M_huge)
|
||||
{
|
||||
/* 4K bitmap (128M IOVA range) */
|
||||
.buffer_size = 128UL * 1024UL * 1024UL,
|
||||
.hugepages = true,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty256M)
|
||||
{
|
||||
/* 8K bitmap (256M IOVA range) */
|
||||
.buffer_size = 256UL * 1024UL * 1024UL,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty256M_huge)
|
||||
{
|
||||
/* 8K bitmap (256M IOVA range) */
|
||||
.buffer_size = 256UL * 1024UL * 1024UL,
|
||||
.hugepages = true,
|
||||
};
|
||||
|
||||
TEST_F(iommufd_dirty_tracking, enforce_dirty)
|
||||
{
|
||||
uint32_t ioas_id, stddev_id, idev_id;
|
||||
@@ -1849,65 +1882,80 @@ TEST_F(iommufd_dirty_tracking, device_dirty_capability)
|
||||
|
||||
TEST_F(iommufd_dirty_tracking, get_dirty_bitmap)
|
||||
{
|
||||
uint32_t stddev_id;
|
||||
uint32_t page_size = MOCK_PAGE_SIZE;
|
||||
uint32_t hwpt_id;
|
||||
uint32_t ioas_id;
|
||||
|
||||
if (variant->hugepages)
|
||||
page_size = MOCK_HUGE_PAGE_SIZE;
|
||||
|
||||
test_ioctl_ioas_alloc(&ioas_id);
|
||||
test_ioctl_ioas_map_fixed_id(ioas_id, self->buffer,
|
||||
variant->buffer_size, MOCK_APERTURE_START);
|
||||
|
||||
test_cmd_hwpt_alloc(self->idev_id, ioas_id,
|
||||
IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);
|
||||
test_cmd_mock_domain(hwpt_id, &stddev_id, NULL, NULL);
|
||||
|
||||
test_cmd_set_dirty_tracking(hwpt_id, true);
|
||||
|
||||
test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
|
||||
MOCK_APERTURE_START, self->page_size,
|
||||
MOCK_APERTURE_START, self->page_size, page_size,
|
||||
self->bitmap, self->bitmap_size, 0, _metadata);
|
||||
|
||||
/* PAGE_SIZE unaligned bitmap */
|
||||
test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
|
||||
MOCK_APERTURE_START, self->page_size,
|
||||
MOCK_APERTURE_START, self->page_size, page_size,
|
||||
self->bitmap + MOCK_PAGE_SIZE,
|
||||
self->bitmap_size, 0, _metadata);
|
||||
|
||||
test_ioctl_destroy(stddev_id);
|
||||
/* u64 unaligned bitmap */
|
||||
test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
|
||||
MOCK_APERTURE_START, self->page_size, page_size,
|
||||
self->bitmap + 0xff1, self->bitmap_size, 0,
|
||||
_metadata);
|
||||
|
||||
test_ioctl_destroy(hwpt_id);
|
||||
}
|
||||
|
||||
TEST_F(iommufd_dirty_tracking, get_dirty_bitmap_no_clear)
|
||||
{
|
||||
uint32_t stddev_id;
|
||||
uint32_t page_size = MOCK_PAGE_SIZE;
|
||||
uint32_t hwpt_id;
|
||||
uint32_t ioas_id;
|
||||
|
||||
if (variant->hugepages)
|
||||
page_size = MOCK_HUGE_PAGE_SIZE;
|
||||
|
||||
test_ioctl_ioas_alloc(&ioas_id);
|
||||
test_ioctl_ioas_map_fixed_id(ioas_id, self->buffer,
|
||||
variant->buffer_size, MOCK_APERTURE_START);
|
||||
|
||||
test_cmd_hwpt_alloc(self->idev_id, ioas_id,
|
||||
IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);
|
||||
test_cmd_mock_domain(hwpt_id, &stddev_id, NULL, NULL);
|
||||
|
||||
test_cmd_set_dirty_tracking(hwpt_id, true);
|
||||
|
||||
test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
|
||||
MOCK_APERTURE_START, self->page_size,
|
||||
MOCK_APERTURE_START, self->page_size, page_size,
|
||||
self->bitmap, self->bitmap_size,
|
||||
IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR,
|
||||
_metadata);
|
||||
|
||||
/* Unaligned bitmap */
|
||||
test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
|
||||
MOCK_APERTURE_START, self->page_size,
|
||||
MOCK_APERTURE_START, self->page_size, page_size,
|
||||
self->bitmap + MOCK_PAGE_SIZE,
|
||||
self->bitmap_size,
|
||||
IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR,
|
||||
_metadata);
|
||||
|
||||
test_ioctl_destroy(stddev_id);
|
||||
/* u64 unaligned bitmap */
|
||||
test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
|
||||
MOCK_APERTURE_START, self->page_size, page_size,
|
||||
self->bitmap + 0xff1, self->bitmap_size,
|
||||
IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR,
|
||||
_metadata);
|
||||
|
||||
test_ioctl_destroy(hwpt_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -344,16 +344,19 @@ static int _test_cmd_mock_domain_set_dirty(int fd, __u32 hwpt_id, size_t length,
|
||||
page_size, bitmap, nr))
|
||||
|
||||
static int _test_mock_dirty_bitmaps(int fd, __u32 hwpt_id, size_t length,
|
||||
__u64 iova, size_t page_size, __u64 *bitmap,
|
||||
__u64 iova, size_t page_size,
|
||||
size_t pte_page_size, __u64 *bitmap,
|
||||
__u64 bitmap_size, __u32 flags,
|
||||
struct __test_metadata *_metadata)
|
||||
{
|
||||
unsigned long i, nbits = bitmap_size * BITS_PER_BYTE;
|
||||
unsigned long nr = nbits / 2;
|
||||
unsigned long npte = pte_page_size / page_size, pteset = 2 * npte;
|
||||
unsigned long nbits = bitmap_size * BITS_PER_BYTE;
|
||||
unsigned long j, i, nr = nbits / pteset ?: 1;
|
||||
__u64 out_dirty = 0;
|
||||
|
||||
/* Mark all even bits as dirty in the mock domain */
|
||||
for (i = 0; i < nbits; i += 2)
|
||||
memset(bitmap, 0, bitmap_size);
|
||||
for (i = 0; i < nbits; i += pteset)
|
||||
set_bit(i, (unsigned long *)bitmap);
|
||||
|
||||
test_cmd_mock_domain_set_dirty(fd, hwpt_id, length, iova, page_size,
|
||||
@@ -365,8 +368,12 @@ static int _test_mock_dirty_bitmaps(int fd, __u32 hwpt_id, size_t length,
|
||||
test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, page_size, bitmap,
|
||||
flags);
|
||||
/* Beware ASSERT_EQ() is two statements -- braces are not redundant! */
|
||||
for (i = 0; i < nbits; i++) {
|
||||
ASSERT_EQ(!(i % 2), test_bit(i, (unsigned long *)bitmap));
|
||||
for (i = 0; i < nbits; i += pteset) {
|
||||
for (j = 0; j < pteset; j++) {
|
||||
ASSERT_EQ(j < npte,
|
||||
test_bit(i + j, (unsigned long *)bitmap));
|
||||
}
|
||||
ASSERT_EQ(!(i % pteset), test_bit(i, (unsigned long *)bitmap));
|
||||
}
|
||||
|
||||
memset(bitmap, 0, bitmap_size);
|
||||
@@ -374,19 +381,23 @@ static int _test_mock_dirty_bitmaps(int fd, __u32 hwpt_id, size_t length,
|
||||
flags);
|
||||
|
||||
/* It as read already -- expect all zeroes */
|
||||
for (i = 0; i < nbits; i++) {
|
||||
ASSERT_EQ(!(i % 2) && (flags &
|
||||
IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR),
|
||||
test_bit(i, (unsigned long *)bitmap));
|
||||
for (i = 0; i < nbits; i += pteset) {
|
||||
for (j = 0; j < pteset; j++) {
|
||||
ASSERT_EQ(
|
||||
(j < npte) &&
|
||||
(flags &
|
||||
IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR),
|
||||
test_bit(i + j, (unsigned long *)bitmap));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define test_mock_dirty_bitmaps(hwpt_id, length, iova, page_size, bitmap, \
|
||||
bitmap_size, flags, _metadata) \
|
||||
#define test_mock_dirty_bitmaps(hwpt_id, length, iova, page_size, pte_size,\
|
||||
bitmap, bitmap_size, flags, _metadata) \
|
||||
ASSERT_EQ(0, _test_mock_dirty_bitmaps(self->fd, hwpt_id, length, iova, \
|
||||
page_size, bitmap, bitmap_size, \
|
||||
flags, _metadata))
|
||||
page_size, pte_size, bitmap, \
|
||||
bitmap_size, flags, _metadata))
|
||||
|
||||
static int _test_cmd_create_access(int fd, unsigned int ioas_id,
|
||||
__u32 *access_id, unsigned int flags)
|
||||
|
||||
Reference in New Issue
Block a user