Skip to content

Commit 23a1b46

Browse files
committed
iommufd/selftest: Make the mock iommu driver into a real driver
I've avoided doing this because there is no way to make this happen without an intrusion into the core code. Up till now this has avoided needing the core code's probe path with some hackery - but now that default domains are becoming mandatory it is unavoidable. This became a serious problem when the core code stopped allowing partially registered iommu drivers in commit 14891af ("iommu: Move the iommu driver sysfs setup into iommu_init/deinit_device()") which breaks the selftest. That series was developed along with a second series that contained this patch so it was not noticed. Make it so that iommufd selftest can create a real iommu driver and bind it only to is own private bus. Add iommu_device_register_bus() as a core code helper to make this possible. It simply sets the right pointers and registers the notifier block. The mock driver then works like any normal driver should, with probe triggered by the bus ops When the bus->iommu_ops stuff is fully unwound we can probably do better here and remove this special case. Link: https://lore.kernel.org/r/15-v6-e8114faedade+425-iommu_all_defdom_jgg@nvidia.com Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
1 parent c157fd8 commit 23a1b46

File tree

5 files changed

+144
-59
lines changed

5 files changed

+144
-59
lines changed

drivers/iommu/iommu-priv.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES.
3+
*/
24
#ifndef __LINUX_IOMMU_PRIV_H
35
#define __LINUX_IOMMU_PRIV_H
46

@@ -7,4 +9,11 @@
79
int iommu_group_replace_domain(struct iommu_group *group,
810
struct iommu_domain *new_domain);
911

12+
int iommu_device_register_bus(struct iommu_device *iommu,
13+
const struct iommu_ops *ops, struct bus_type *bus,
14+
struct notifier_block *nb);
15+
void iommu_device_unregister_bus(struct iommu_device *iommu,
16+
struct bus_type *bus,
17+
struct notifier_block *nb);
18+
1019
#endif /* __LINUX_IOMMU_PRIV_H */

drivers/iommu/iommu.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "iommu-priv.h"
3838

3939
#include "iommu-sva.h"
40+
#include "iommu-priv.h"
4041

4142
static struct kset *iommu_group_kset;
4243
static DEFINE_IDA(iommu_group_ida);
@@ -288,6 +289,48 @@ void iommu_device_unregister(struct iommu_device *iommu)
288289
}
289290
EXPORT_SYMBOL_GPL(iommu_device_unregister);
290291

292+
#if IS_ENABLED(CONFIG_IOMMUFD_TEST)
293+
void iommu_device_unregister_bus(struct iommu_device *iommu,
294+
struct bus_type *bus,
295+
struct notifier_block *nb)
296+
{
297+
bus_unregister_notifier(bus, nb);
298+
iommu_device_unregister(iommu);
299+
}
300+
EXPORT_SYMBOL_GPL(iommu_device_unregister_bus);
301+
302+
/*
303+
* Register an iommu driver against a single bus. This is only used by iommufd
304+
* selftest to create a mock iommu driver. The caller must provide
305+
* some memory to hold a notifier_block.
306+
*/
307+
int iommu_device_register_bus(struct iommu_device *iommu,
308+
const struct iommu_ops *ops, struct bus_type *bus,
309+
struct notifier_block *nb)
310+
{
311+
int err;
312+
313+
iommu->ops = ops;
314+
nb->notifier_call = iommu_bus_notifier;
315+
err = bus_register_notifier(bus, nb);
316+
if (err)
317+
return err;
318+
319+
spin_lock(&iommu_device_lock);
320+
list_add_tail(&iommu->list, &iommu_device_list);
321+
spin_unlock(&iommu_device_lock);
322+
323+
bus->iommu_ops = ops;
324+
err = bus_iommu_probe(bus);
325+
if (err) {
326+
iommu_device_unregister_bus(iommu, bus, nb);
327+
return err;
328+
}
329+
return 0;
330+
}
331+
EXPORT_SYMBOL_GPL(iommu_device_register_bus);
332+
#endif
333+
291334
static struct dev_iommu *dev_iommu_get(struct device *dev)
292335
{
293336
struct dev_iommu *param = dev->iommu;

drivers/iommu/iommufd/iommufd_private.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ extern size_t iommufd_test_memory_limit;
334334
void iommufd_test_syz_conv_iova_id(struct iommufd_ucmd *ucmd,
335335
unsigned int ioas_id, u64 *iova, u32 *flags);
336336
bool iommufd_should_fail(void);
337-
void __init iommufd_test_init(void);
337+
int __init iommufd_test_init(void);
338338
void iommufd_test_exit(void);
339339
bool iommufd_selftest_is_mock_dev(struct device *dev);
340340
#else
@@ -347,8 +347,9 @@ static inline bool iommufd_should_fail(void)
347347
{
348348
return false;
349349
}
350-
static inline void __init iommufd_test_init(void)
350+
static inline int __init iommufd_test_init(void)
351351
{
352+
return 0;
352353
}
353354
static inline void iommufd_test_exit(void)
354355
{

drivers/iommu/iommufd/main.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,8 +480,14 @@ static int __init iommufd_init(void)
480480
if (ret)
481481
goto err_misc;
482482
}
483-
iommufd_test_init();
483+
ret = iommufd_test_init();
484+
if (ret)
485+
goto err_vfio_misc;
484486
return 0;
487+
488+
err_vfio_misc:
489+
if (IS_ENABLED(CONFIG_IOMMUFD_VFIO_CONTAINER))
490+
misc_deregister(&vfio_misc_dev);
485491
err_misc:
486492
misc_deregister(&iommu_misc_dev);
487493
return ret;

drivers/iommu/iommufd/selftest.c

Lines changed: 82 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@
99
#include <linux/file.h>
1010
#include <linux/anon_inodes.h>
1111
#include <linux/fault-inject.h>
12+
#include <linux/platform_device.h>
1213
#include <uapi/linux/iommufd.h>
1314

15+
#include "../iommu-priv.h"
1416
#include "io_pagetable.h"
1517
#include "iommufd_private.h"
1618
#include "iommufd_test.h"
1719

1820
static DECLARE_FAULT_ATTR(fail_iommufd);
1921
static struct dentry *dbgfs_root;
22+
static struct platform_device *selftest_iommu_dev;
2023

2124
size_t iommufd_test_memory_limit = 65536;
2225

@@ -135,7 +138,7 @@ static struct iommu_domain *mock_domain_alloc(unsigned int iommu_domain_type)
135138
if (iommu_domain_type == IOMMU_DOMAIN_BLOCKED)
136139
return &mock_blocking_domain;
137140

138-
if (WARN_ON(iommu_domain_type != IOMMU_DOMAIN_UNMANAGED))
141+
if (iommu_domain_type != IOMMU_DOMAIN_UNMANAGED)
139142
return NULL;
140143

141144
mock = kzalloc(sizeof(*mock), GFP_KERNEL);
@@ -276,12 +279,22 @@ static void mock_domain_set_plaform_dma_ops(struct device *dev)
276279
*/
277280
}
278281

282+
static struct iommu_device mock_iommu_device = {
283+
};
284+
285+
static struct iommu_device *mock_probe_device(struct device *dev)
286+
{
287+
return &mock_iommu_device;
288+
}
289+
279290
static const struct iommu_ops mock_ops = {
280291
.owner = THIS_MODULE,
281292
.pgsize_bitmap = MOCK_IO_PAGE_SIZE,
282293
.domain_alloc = mock_domain_alloc,
283294
.capable = mock_domain_capable,
284295
.set_platform_dma_ops = mock_domain_set_plaform_dma_ops,
296+
.device_group = generic_device_group,
297+
.probe_device = mock_probe_device,
285298
.default_domain_ops =
286299
&(struct iommu_domain_ops){
287300
.free = mock_domain_free,
@@ -292,10 +305,6 @@ static const struct iommu_ops mock_ops = {
292305
},
293306
};
294307

295-
static struct iommu_device mock_iommu_device = {
296-
.ops = &mock_ops,
297-
};
298-
299308
static inline struct iommufd_hw_pagetable *
300309
get_md_pagetable(struct iommufd_ucmd *ucmd, u32 mockpt_id,
301310
struct mock_iommu_domain **mock)
@@ -316,22 +325,29 @@ get_md_pagetable(struct iommufd_ucmd *ucmd, u32 mockpt_id,
316325
return hwpt;
317326
}
318327

319-
static struct bus_type iommufd_mock_bus_type = {
320-
.name = "iommufd_mock",
321-
.iommu_ops = &mock_ops,
328+
struct mock_bus_type {
329+
struct bus_type bus;
330+
struct notifier_block nb;
331+
};
332+
333+
static struct mock_bus_type iommufd_mock_bus_type = {
334+
.bus = {
335+
.name = "iommufd_mock",
336+
},
322337
};
323338

339+
static atomic_t mock_dev_num;
340+
324341
static void mock_dev_release(struct device *dev)
325342
{
326343
struct mock_dev *mdev = container_of(dev, struct mock_dev, dev);
327344

345+
atomic_dec(&mock_dev_num);
328346
kfree(mdev);
329347
}
330348

331349
static struct mock_dev *mock_dev_create(void)
332350
{
333-
struct iommu_group *iommu_group;
334-
struct dev_iommu *dev_iommu;
335351
struct mock_dev *mdev;
336352
int rc;
337353

@@ -341,63 +357,26 @@ static struct mock_dev *mock_dev_create(void)
341357

342358
device_initialize(&mdev->dev);
343359
mdev->dev.release = mock_dev_release;
344-
mdev->dev.bus = &iommufd_mock_bus_type;
345-
346-
iommu_group = iommu_group_alloc();
347-
if (IS_ERR(iommu_group)) {
348-
rc = PTR_ERR(iommu_group);
349-
goto err_put;
350-
}
360+
mdev->dev.bus = &iommufd_mock_bus_type.bus;
351361

352362
rc = dev_set_name(&mdev->dev, "iommufd_mock%u",
353-
iommu_group_id(iommu_group));
363+
atomic_inc_return(&mock_dev_num));
354364
if (rc)
355-
goto err_group;
356-
357-
/*
358-
* The iommu core has no way to associate a single device with an iommu
359-
* driver (heck currently it can't even support two iommu_drivers
360-
* registering). Hack it together with an open coded dev_iommu_get().
361-
* Notice that the normal notifier triggered iommu release process also
362-
* does not work here because this bus is not in iommu_buses.
363-
*/
364-
mdev->dev.iommu = kzalloc(sizeof(*dev_iommu), GFP_KERNEL);
365-
if (!mdev->dev.iommu) {
366-
rc = -ENOMEM;
367-
goto err_group;
368-
}
369-
mutex_init(&mdev->dev.iommu->lock);
370-
mdev->dev.iommu->iommu_dev = &mock_iommu_device;
365+
goto err_put;
371366

372367
rc = device_add(&mdev->dev);
373368
if (rc)
374-
goto err_dev_iommu;
375-
376-
rc = iommu_group_add_device(iommu_group, &mdev->dev);
377-
if (rc)
378-
goto err_del;
379-
iommu_group_put(iommu_group);
369+
goto err_put;
380370
return mdev;
381371

382-
err_del:
383-
device_del(&mdev->dev);
384-
err_dev_iommu:
385-
kfree(mdev->dev.iommu);
386-
mdev->dev.iommu = NULL;
387-
err_group:
388-
iommu_group_put(iommu_group);
389372
err_put:
390373
put_device(&mdev->dev);
391374
return ERR_PTR(rc);
392375
}
393376

394377
static void mock_dev_destroy(struct mock_dev *mdev)
395378
{
396-
iommu_group_remove_device(&mdev->dev);
397-
device_del(&mdev->dev);
398-
kfree(mdev->dev.iommu);
399-
mdev->dev.iommu = NULL;
400-
put_device(&mdev->dev);
379+
device_unregister(&mdev->dev);
401380
}
402381

403382
bool iommufd_selftest_is_mock_dev(struct device *dev)
@@ -444,9 +423,14 @@ static int iommufd_test_mock_domain(struct iommufd_ucmd *ucmd,
444423
cmd->mock_domain.out_hwpt_id = pt_id;
445424
cmd->mock_domain.out_stdev_id = sobj->obj.id;
446425
cmd->mock_domain.out_idev_id = idev_id;
426+
rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
427+
if (rc)
428+
goto out_detach;
447429
iommufd_object_finalize(ucmd->ictx, &sobj->obj);
448-
return iommufd_ucmd_respond(ucmd, sizeof(*cmd));
430+
return 0;
449431

432+
out_detach:
433+
iommufd_device_detach(idev);
450434
out_unbind:
451435
iommufd_device_unbind(idev);
452436
out_mdev:
@@ -1051,15 +1035,57 @@ bool iommufd_should_fail(void)
10511035
return should_fail(&fail_iommufd, 1);
10521036
}
10531037

1054-
void __init iommufd_test_init(void)
1038+
int __init iommufd_test_init(void)
10551039
{
1040+
struct platform_device_info pdevinfo = {
1041+
.name = "iommufd_selftest_iommu",
1042+
};
1043+
int rc;
1044+
10561045
dbgfs_root =
10571046
fault_create_debugfs_attr("fail_iommufd", NULL, &fail_iommufd);
1058-
WARN_ON(bus_register(&iommufd_mock_bus_type));
1047+
1048+
selftest_iommu_dev = platform_device_register_full(&pdevinfo);
1049+
if (IS_ERR(selftest_iommu_dev)) {
1050+
rc = PTR_ERR(selftest_iommu_dev);
1051+
goto err_dbgfs;
1052+
}
1053+
1054+
rc = bus_register(&iommufd_mock_bus_type.bus);
1055+
if (rc)
1056+
goto err_platform;
1057+
1058+
rc = iommu_device_sysfs_add(&mock_iommu_device,
1059+
&selftest_iommu_dev->dev, NULL, "%s",
1060+
dev_name(&selftest_iommu_dev->dev));
1061+
if (rc)
1062+
goto err_bus;
1063+
1064+
rc = iommu_device_register_bus(&mock_iommu_device, &mock_ops,
1065+
&iommufd_mock_bus_type.bus,
1066+
&iommufd_mock_bus_type.nb);
1067+
if (rc)
1068+
goto err_sysfs;
1069+
return 0;
1070+
1071+
err_sysfs:
1072+
iommu_device_sysfs_remove(&mock_iommu_device);
1073+
err_bus:
1074+
bus_unregister(&iommufd_mock_bus_type.bus);
1075+
err_platform:
1076+
platform_device_del(selftest_iommu_dev);
1077+
err_dbgfs:
1078+
debugfs_remove_recursive(dbgfs_root);
1079+
return rc;
10591080
}
10601081

10611082
void iommufd_test_exit(void)
10621083
{
1084+
iommu_device_sysfs_remove(&mock_iommu_device);
1085+
iommu_device_unregister_bus(&mock_iommu_device,
1086+
&iommufd_mock_bus_type.bus,
1087+
&iommufd_mock_bus_type.nb);
1088+
bus_unregister(&iommufd_mock_bus_type.bus);
1089+
platform_device_del(selftest_iommu_dev);
10631090
debugfs_remove_recursive(dbgfs_root);
1064-
bus_unregister(&iommufd_mock_bus_type);
10651091
}

0 commit comments

Comments
 (0)