* Re: [PATCH V7 9/9] iommufd: map file selftest
[not found] ` <1729861919-234514-10-git-send-email-steven.sistare@oracle.com>
@ 2024-10-25 13:14 ` Steven Sistare
2024-10-25 17:00 ` Nicolin Chen
0 siblings, 1 reply; 2+ messages in thread
From: Steven Sistare @ 2024-10-25 13:14 UTC (permalink / raw)
To: linux-kselftest; +Cc: Jason Gunthorpe, Kevin Tian, Nicolin Chen, iommu
cc linux-selftest
- Steve
On 10/25/2024 9:11 AM, Steve Sistare wrote:
> Add test cases to exercise IOMMU_IOAS_MAP_FILE.
>
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
> Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
> ---
> tools/testing/selftests/iommu/iommufd.c | 124 ++++++++++++++++++++---
> tools/testing/selftests/iommu/iommufd_fail_nth.c | 39 +++++++
> tools/testing/selftests/iommu/iommufd_utils.h | 57 +++++++++++
> 3 files changed, 205 insertions(+), 15 deletions(-)
>
> diff --git a/tools/testing/selftests/iommu/iommufd.c b/tools/testing/selftests/iommu/iommufd.c
> index 4927b9a..88b92bb 100644
> --- a/tools/testing/selftests/iommu/iommufd.c
> +++ b/tools/testing/selftests/iommu/iommufd.c
> @@ -1,5 +1,6 @@
> // SPDX-License-Identifier: GPL-2.0-only
> /* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES */
> +#include <asm/unistd.h>
> #include <stdlib.h>
> #include <sys/mman.h>
> #include <sys/eventfd.h>
> @@ -49,6 +50,9 @@ static __attribute__((constructor)) void setup_sizes(void)
> vrc = mmap(buffer, BUFFER_SIZE, PROT_READ | PROT_WRITE,
> MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
> assert(vrc == buffer);
> +
> + mfd_buffer = memfd_mmap(BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
> + &mfd);
> }
>
> FIXTURE(iommufd)
> @@ -128,6 +132,7 @@ static __attribute__((constructor)) void setup_sizes(void)
> TEST_LENGTH(iommu_ioas_unmap, IOMMU_IOAS_UNMAP, length);
> TEST_LENGTH(iommu_option, IOMMU_OPTION, val64);
> TEST_LENGTH(iommu_vfio_ioas, IOMMU_VFIO_IOAS, __reserved);
> + TEST_LENGTH(iommu_ioas_map_file, IOMMU_IOAS_MAP_FILE, iova);
> #undef TEST_LENGTH
> }
>
> @@ -1372,6 +1377,7 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> {
> unsigned int mock_domains;
> bool hugepages;
> + bool file;
> };
>
> FIXTURE_SETUP(iommufd_mock_domain)
> @@ -1410,26 +1416,45 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> {
> .mock_domains = 1,
> .hugepages = false,
> + .file = false,
> };
>
> FIXTURE_VARIANT_ADD(iommufd_mock_domain, two_domains)
> {
> .mock_domains = 2,
> .hugepages = false,
> + .file = false,
> };
>
> FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain_hugepage)
> {
> .mock_domains = 1,
> .hugepages = true,
> + .file = false,
> };
>
> FIXTURE_VARIANT_ADD(iommufd_mock_domain, two_domains_hugepage)
> {
> .mock_domains = 2,
> .hugepages = true,
> + .file = false,
> };
>
> +FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain_file)
> +{
> + .mock_domains = 1,
> + .hugepages = false,
> + .file = true,
> +};
> +
> +FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain_file_hugepage)
> +{
> + .mock_domains = 1,
> + .hugepages = true,
> + .file = true,
> +};
> +
> +
> /* Have the kernel check that the user pages made it to the iommu_domain */
> #define check_mock_iova(_ptr, _iova, _length) \
> ({ \
> @@ -1455,7 +1480,10 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> } \
> })
>
> -TEST_F(iommufd_mock_domain, basic)
> +static void
> +test_basic_mmap(struct __test_metadata *_metadata,
> + struct _test_data_iommufd_mock_domain *self,
> + const struct _fixture_variant_iommufd_mock_domain *variant)
> {
> size_t buf_size = self->mmap_buf_size;
> uint8_t *buf;
> @@ -1478,6 +1506,40 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> test_err_ioctl_ioas_map(EFAULT, buf, buf_size, &iova);
> }
>
> +static void
> +test_basic_file(struct __test_metadata *_metadata,
> + struct _test_data_iommufd_mock_domain *self,
> + const struct _fixture_variant_iommufd_mock_domain *variant)
> +{
> + size_t buf_size = self->mmap_buf_size;
> + uint8_t *buf;
> + __u64 iova;
> + int mfd_tmp;
> + int prot = PROT_READ | PROT_WRITE;
> +
> + /* Simple one page map */
> + test_ioctl_ioas_map_file(mfd, 0, PAGE_SIZE, &iova);
> + check_mock_iova(mfd_buffer, iova, PAGE_SIZE);
> +
> + buf = memfd_mmap(buf_size, prot, MAP_SHARED, &mfd_tmp);
> + ASSERT_NE(MAP_FAILED, buf);
> +
> + test_err_ioctl_ioas_map_file(EINVAL, mfd_tmp, 0, buf_size + 1, &iova);
> +
> + ASSERT_EQ(0, ftruncate(mfd_tmp, 0));
> + test_err_ioctl_ioas_map_file(EINVAL, mfd_tmp, 0, buf_size, &iova);
> +
> + close(mfd_tmp);
> +}
> +
> +TEST_F(iommufd_mock_domain, basic)
> +{
> + if (variant->file)
> + test_basic_file(_metadata, self, variant);
> + else
> + test_basic_mmap(_metadata, self, variant);
> +}
> +
> TEST_F(iommufd_mock_domain, ro_unshare)
> {
> uint8_t *buf;
> @@ -1513,9 +1575,13 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> unsigned int start;
> unsigned int end;
> uint8_t *buf;
> + int prot = PROT_READ | PROT_WRITE;
> + int mfd;
>
> - buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, self->mmap_flags, -1,
> - 0);
> + if (variant->file)
> + buf = memfd_mmap(buf_size, prot, MAP_SHARED, &mfd);
> + else
> + buf = mmap(0, buf_size, prot, self->mmap_flags, -1, 0);
> ASSERT_NE(MAP_FAILED, buf);
> check_refs(buf, buf_size, 0);
>
> @@ -1532,7 +1598,12 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> size_t length = end - start;
> __u64 iova;
>
> - test_ioctl_ioas_map(buf + start, length, &iova);
> + if (variant->file) {
> + test_ioctl_ioas_map_file(mfd, start, length,
> + &iova);
> + } else {
> + test_ioctl_ioas_map(buf + start, length, &iova);
> + }
> check_mock_iova(buf + start, iova, length);
> check_refs(buf + start / PAGE_SIZE * PAGE_SIZE,
> end / PAGE_SIZE * PAGE_SIZE -
> @@ -1544,6 +1615,8 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> }
> check_refs(buf, buf_size, 0);
> ASSERT_EQ(0, munmap(buf, buf_size));
> + if (variant->file)
> + close(mfd);
> }
>
> TEST_F(iommufd_mock_domain, all_aligns_copy)
> @@ -1554,9 +1627,13 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> unsigned int start;
> unsigned int end;
> uint8_t *buf;
> + int prot = PROT_READ | PROT_WRITE;
> + int mfd;
>
> - buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, self->mmap_flags, -1,
> - 0);
> + if (variant->file)
> + buf = memfd_mmap(buf_size, prot, MAP_SHARED, &mfd);
> + else
> + buf = mmap(0, buf_size, prot, self->mmap_flags, -1, 0);
> ASSERT_NE(MAP_FAILED, buf);
> check_refs(buf, buf_size, 0);
>
> @@ -1575,7 +1652,12 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> uint32_t mock_stdev_id;
> __u64 iova;
>
> - test_ioctl_ioas_map(buf + start, length, &iova);
> + if (variant->file) {
> + test_ioctl_ioas_map_file(mfd, start, length,
> + &iova);
> + } else {
> + test_ioctl_ioas_map(buf + start, length, &iova);
> + }
>
> /* Add and destroy a domain while the area exists */
> old_id = self->hwpt_ids[1];
> @@ -1596,15 +1678,18 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> }
> check_refs(buf, buf_size, 0);
> ASSERT_EQ(0, munmap(buf, buf_size));
> + if (variant->file)
> + close(mfd);
> }
>
> TEST_F(iommufd_mock_domain, user_copy)
> {
> + void *buf = variant->file ? mfd_buffer : buffer;
> struct iommu_test_cmd access_cmd = {
> .size = sizeof(access_cmd),
> .op = IOMMU_TEST_OP_ACCESS_PAGES,
> .access_pages = { .length = BUFFER_SIZE,
> - .uptr = (uintptr_t)buffer },
> + .uptr = (uintptr_t)buf },
> };
> struct iommu_ioas_copy copy_cmd = {
> .size = sizeof(copy_cmd),
> @@ -1623,9 +1708,13 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
>
> /* Pin the pages in an IOAS with no domains then copy to an IOAS with domains */
> test_ioctl_ioas_alloc(&ioas_id);
> - test_ioctl_ioas_map_id(ioas_id, buffer, BUFFER_SIZE,
> - ©_cmd.src_iova);
> -
> + if (variant->file) {
> + test_ioctl_ioas_map_id_file(ioas_id, mfd, 0, BUFFER_SIZE,
> + ©_cmd.src_iova);
> + } else {
> + test_ioctl_ioas_map_id(ioas_id, buf, BUFFER_SIZE,
> + ©_cmd.src_iova);
> + }
> test_cmd_create_access(ioas_id, &access_cmd.id,
> MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES);
>
> @@ -1635,12 +1724,17 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> &access_cmd));
> copy_cmd.src_ioas_id = ioas_id;
> ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, ©_cmd));
> - check_mock_iova(buffer, MOCK_APERTURE_START, BUFFER_SIZE);
> + check_mock_iova(buf, MOCK_APERTURE_START, BUFFER_SIZE);
>
> /* Now replace the ioas with a new one */
> test_ioctl_ioas_alloc(&new_ioas_id);
> - test_ioctl_ioas_map_id(new_ioas_id, buffer, BUFFER_SIZE,
> - ©_cmd.src_iova);
> + if (variant->file) {
> + test_ioctl_ioas_map_id_file(new_ioas_id, mfd, 0, BUFFER_SIZE,
> + ©_cmd.src_iova);
> + } else {
> + test_ioctl_ioas_map_id(new_ioas_id, buf, BUFFER_SIZE,
> + ©_cmd.src_iova);
> + }
> test_cmd_access_replace_ioas(access_cmd.id, new_ioas_id);
>
> /* Destroy the old ioas and cleanup copied mapping */
> @@ -1654,7 +1748,7 @@ static void check_access_rw(struct __test_metadata *_metadata, int fd,
> &access_cmd));
> copy_cmd.src_ioas_id = new_ioas_id;
> ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, ©_cmd));
> - check_mock_iova(buffer, MOCK_APERTURE_START, BUFFER_SIZE);
> + check_mock_iova(buf, MOCK_APERTURE_START, BUFFER_SIZE);
>
> test_cmd_destroy_access_pages(
> access_cmd.id, access_cmd.access_pages.out_access_pages_id);
> diff --git a/tools/testing/selftests/iommu/iommufd_fail_nth.c b/tools/testing/selftests/iommu/iommufd_fail_nth.c
> index c5d5e69..2d7d016 100644
> --- a/tools/testing/selftests/iommu/iommufd_fail_nth.c
> +++ b/tools/testing/selftests/iommu/iommufd_fail_nth.c
> @@ -47,6 +47,9 @@ static __attribute__((constructor)) void setup_buffer(void)
>
> buffer = mmap(0, BUFFER_SIZE, PROT_READ | PROT_WRITE,
> MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +
> + mfd_buffer = memfd_mmap(BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
> + &mfd);
> }
>
> /*
> @@ -331,6 +334,42 @@ void __fail_nth_enable(struct __test_metadata *_metadata,
> return 0;
> }
>
> +/* iopt_area_fill_domains() and iopt_area_fill_domain() */
> +TEST_FAIL_NTH(basic_fail_nth, map_file_domain)
> +{
> + uint32_t ioas_id;
> + __u32 stdev_id;
> + __u32 hwpt_id;
> + __u64 iova;
> +
> + self->fd = open("/dev/iommu", O_RDWR);
> + if (self->fd == -1)
> + return -1;
> +
> + if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
> + return -1;
> +
> + if (_test_ioctl_set_temp_memory_limit(self->fd, 32))
> + return -1;
> +
> + fail_nth_enable();
> +
> + if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
> + return -1;
> +
> + if (_test_ioctl_ioas_map_file(self->fd, ioas_id, mfd, 0, 262144, &iova,
> + IOMMU_IOAS_MAP_WRITEABLE |
> + IOMMU_IOAS_MAP_READABLE))
> + return -1;
> +
> + if (_test_ioctl_destroy(self->fd, stdev_id))
> + return -1;
> +
> + if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
> + return -1;
> + return 0;
> +}
> +
> TEST_FAIL_NTH(basic_fail_nth, map_two_domains)
> {
> uint32_t ioas_id;
> diff --git a/tools/testing/selftests/iommu/iommufd_utils.h b/tools/testing/selftests/iommu/iommufd_utils.h
> index 40f6f14..6a11c26 100644
> --- a/tools/testing/selftests/iommu/iommufd_utils.h
> +++ b/tools/testing/selftests/iommu/iommufd_utils.h
> @@ -40,12 +40,28 @@ static inline bool test_bit(unsigned int nr, unsigned long *addr)
> static void *buffer;
> static unsigned long BUFFER_SIZE;
>
> +static void *mfd_buffer;
> +static int mfd;
> +
> static unsigned long PAGE_SIZE;
>
> #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
> #define offsetofend(TYPE, MEMBER) \
> (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER))
>
> +static inline void *memfd_mmap(size_t length, int prot, int flags, int *mfd_p)
> +{
> + int mfd_flags = (flags & MAP_HUGETLB) ? MFD_HUGETLB : 0;
> + int mfd = memfd_create("buffer", mfd_flags);
> +
> + if (mfd <= 0)
> + return MAP_FAILED;
> + if (ftruncate(mfd, length))
> + return MAP_FAILED;
> + *mfd_p = mfd;
> + return mmap(0, length, prot, flags, mfd, 0);
> +}
> +
> /*
> * Have the kernel check the refcount on pages. I don't know why a freshly
> * mmap'd anon non-compound page starts out with a ref of 3
> @@ -589,6 +605,47 @@ static int _test_ioctl_ioas_unmap(int fd, unsigned int ioas_id, uint64_t iova,
> EXPECT_ERRNO(_errno, _test_ioctl_ioas_unmap(self->fd, self->ioas_id, \
> iova, length, NULL))
>
> +static int _test_ioctl_ioas_map_file(int fd, unsigned int ioas_id, int mfd,
> + size_t start, size_t length, __u64 *iova,
> + unsigned int flags)
> +{
> + struct iommu_ioas_map_file cmd = {
> + .size = sizeof(cmd),
> + .flags = flags,
> + .ioas_id = ioas_id,
> + .fd = mfd,
> + .start = start,
> + .length = length,
> + };
> + int ret;
> +
> + if (flags & IOMMU_IOAS_MAP_FIXED_IOVA)
> + cmd.iova = *iova;
> +
> + ret = ioctl(fd, IOMMU_IOAS_MAP_FILE, &cmd);
> + *iova = cmd.iova;
> + return ret;
> +}
> +
> +#define test_ioctl_ioas_map_file(mfd, start, length, iova_p) \
> + ASSERT_EQ(0, \
> + _test_ioctl_ioas_map_file( \
> + self->fd, self->ioas_id, mfd, start, length, iova_p, \
> + IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_READABLE))
> +
> +#define test_err_ioctl_ioas_map_file(_errno, mfd, start, length, iova_p) \
> + EXPECT_ERRNO( \
> + _errno, \
> + _test_ioctl_ioas_map_file( \
> + self->fd, self->ioas_id, mfd, start, length, iova_p, \
> + IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_READABLE))
> +
> +#define test_ioctl_ioas_map_id_file(ioas_id, mfd, start, length, iova_p) \
> + ASSERT_EQ(0, \
> + _test_ioctl_ioas_map_file( \
> + self->fd, ioas_id, mfd, start, length, iova_p, \
> + IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_READABLE))
> +
> static int _test_ioctl_set_temp_memory_limit(int fd, unsigned int limit)
> {
> struct iommu_test_cmd memlimit_cmd = {
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH V7 9/9] iommufd: map file selftest
2024-10-25 13:14 ` [PATCH V7 9/9] iommufd: map file selftest Steven Sistare
@ 2024-10-25 17:00 ` Nicolin Chen
0 siblings, 0 replies; 2+ messages in thread
From: Nicolin Chen @ 2024-10-25 17:00 UTC (permalink / raw)
To: Steven Sistare; +Cc: linux-kselftest, Jason Gunthorpe, Kevin Tian, iommu
On Fri, Oct 25, 2024 at 09:14:44AM -0400, Steven Sistare wrote:
> cc linux-selftest
You could just send the entire series to that maillist. I think
that Folks also need the uAPI information to review the change.
Thanks
Nicolin
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2024-10-25 17:00 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1729861919-234514-1-git-send-email-steven.sistare@oracle.com>
[not found] ` <1729861919-234514-10-git-send-email-steven.sistare@oracle.com>
2024-10-25 13:14 ` [PATCH V7 9/9] iommufd: map file selftest Steven Sistare
2024-10-25 17:00 ` Nicolin Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox