Skip to content

Commit 9cef739

Browse files
jgunthorpeawilliam
authored andcommitted
vfio: Use cdev_device_add() instead of device_create()
Modernize how vfio is creating the group char dev and sysfs presence. These days drivers with state should use cdev_device_add() and cdev_device_del() to manage the cdev and sysfs lifetime. This API requires the driver to put the struct device and struct cdev inside its state struct (vfio_group), and then use the usual device_initialize()/cdev_device_add()/cdev_device_del() sequence. Split the code to make this possible: - vfio_group_alloc()/vfio_group_release() are pair'd functions to alloc/free the vfio_group. release is done under the struct device kref. - vfio_create_group()/vfio_group_put() are pairs that manage the sysfs/cdev lifetime. Once the uses count is zero the vfio group's userspace presence is destroyed. - The IDR is replaced with an IDA. container_of(inode->i_cdev) is used to get back to the vfio_group during fops open. The IDA assigns unique minor numbers. Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alex Williamson <[email protected]>
1 parent 2b678aa commit 9cef739

File tree

1 file changed

+92
-101
lines changed

1 file changed

+92
-101
lines changed

drivers/vfio/vfio.c

Lines changed: 92 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,8 @@ static struct vfio {
4343
struct list_head iommu_drivers_list;
4444
struct mutex iommu_drivers_lock;
4545
struct list_head group_list;
46-
struct idr group_idr;
47-
struct mutex group_lock;
48-
struct cdev group_cdev;
46+
struct mutex group_lock; /* locks group_list */
47+
struct ida group_ida;
4948
dev_t group_devt;
5049
} vfio;
5150

@@ -69,14 +68,14 @@ struct vfio_unbound_dev {
6968
};
7069

7170
struct vfio_group {
71+
struct device dev;
72+
struct cdev cdev;
7273
refcount_t users;
73-
int minor;
7474
atomic_t container_users;
7575
struct iommu_group *iommu_group;
7676
struct vfio_container *container;
7777
struct list_head device_list;
7878
struct mutex device_lock;
79-
struct device *dev;
8079
struct notifier_block nb;
8180
struct list_head vfio_next;
8281
struct list_head container_next;
@@ -98,6 +97,7 @@ MODULE_PARM_DESC(enable_unsafe_noiommu_mode, "Enable UNSAFE, no-IOMMU mode. Thi
9897
#endif
9998

10099
static DEFINE_XARRAY(vfio_device_set_xa);
100+
static const struct file_operations vfio_group_fops;
101101

102102
int vfio_assign_device_set(struct vfio_device *device, void *set_id)
103103
{
@@ -281,19 +281,6 @@ void vfio_unregister_iommu_driver(const struct vfio_iommu_driver_ops *ops)
281281
}
282282
EXPORT_SYMBOL_GPL(vfio_unregister_iommu_driver);
283283

284-
/**
285-
* Group minor allocation/free - both called with vfio.group_lock held
286-
*/
287-
static int vfio_alloc_group_minor(struct vfio_group *group)
288-
{
289-
return idr_alloc(&vfio.group_idr, group, 0, MINORMASK + 1, GFP_KERNEL);
290-
}
291-
292-
static void vfio_free_group_minor(int minor)
293-
{
294-
idr_remove(&vfio.group_idr, minor);
295-
}
296-
297284
static int vfio_iommu_group_notifier(struct notifier_block *nb,
298285
unsigned long action, void *data);
299286
static void vfio_group_get(struct vfio_group *group);
@@ -322,22 +309,6 @@ static void vfio_container_put(struct vfio_container *container)
322309
kref_put(&container->kref, vfio_container_release);
323310
}
324311

325-
static void vfio_group_unlock_and_free(struct vfio_group *group)
326-
{
327-
struct vfio_unbound_dev *unbound, *tmp;
328-
329-
mutex_unlock(&vfio.group_lock);
330-
iommu_group_unregister_notifier(group->iommu_group, &group->nb);
331-
332-
list_for_each_entry_safe(unbound, tmp,
333-
&group->unbound_list, unbound_next) {
334-
list_del(&unbound->unbound_next);
335-
kfree(unbound);
336-
}
337-
iommu_group_put(group->iommu_group);
338-
kfree(group);
339-
}
340-
341312
/**
342313
* Group objects - create, release, get, put, search
343314
*/
@@ -366,71 +337,112 @@ vfio_group_get_from_iommu(struct iommu_group *iommu_group)
366337
return group;
367338
}
368339

369-
static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group,
370-
enum vfio_group_type type)
340+
static void vfio_group_release(struct device *dev)
371341
{
372-
struct vfio_group *group, *existing_group;
373-
struct device *dev;
374-
int ret, minor;
342+
struct vfio_group *group = container_of(dev, struct vfio_group, dev);
343+
struct vfio_unbound_dev *unbound, *tmp;
344+
345+
list_for_each_entry_safe(unbound, tmp,
346+
&group->unbound_list, unbound_next) {
347+
list_del(&unbound->unbound_next);
348+
kfree(unbound);
349+
}
350+
351+
mutex_destroy(&group->device_lock);
352+
mutex_destroy(&group->unbound_lock);
353+
iommu_group_put(group->iommu_group);
354+
ida_free(&vfio.group_ida, MINOR(group->dev.devt));
355+
kfree(group);
356+
}
357+
358+
static struct vfio_group *vfio_group_alloc(struct iommu_group *iommu_group,
359+
enum vfio_group_type type)
360+
{
361+
struct vfio_group *group;
362+
int minor;
375363

376364
group = kzalloc(sizeof(*group), GFP_KERNEL);
377365
if (!group)
378366
return ERR_PTR(-ENOMEM);
379367

368+
minor = ida_alloc_max(&vfio.group_ida, MINORMASK, GFP_KERNEL);
369+
if (minor < 0) {
370+
kfree(group);
371+
return ERR_PTR(minor);
372+
}
373+
374+
device_initialize(&group->dev);
375+
group->dev.devt = MKDEV(MAJOR(vfio.group_devt), minor);
376+
group->dev.class = vfio.class;
377+
group->dev.release = vfio_group_release;
378+
cdev_init(&group->cdev, &vfio_group_fops);
379+
group->cdev.owner = THIS_MODULE;
380+
380381
refcount_set(&group->users, 1);
381382
INIT_LIST_HEAD(&group->device_list);
382383
mutex_init(&group->device_lock);
383384
INIT_LIST_HEAD(&group->unbound_list);
384385
mutex_init(&group->unbound_lock);
385-
atomic_set(&group->container_users, 0);
386-
atomic_set(&group->opened, 0);
387386
init_waitqueue_head(&group->container_q);
388387
group->iommu_group = iommu_group;
389-
/* put in vfio_group_unlock_and_free() */
388+
/* put in vfio_group_release() */
390389
iommu_group_ref_get(iommu_group);
391390
group->type = type;
392391
BLOCKING_INIT_NOTIFIER_HEAD(&group->notifier);
393392

393+
return group;
394+
}
395+
396+
static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group,
397+
enum vfio_group_type type)
398+
{
399+
struct vfio_group *group;
400+
struct vfio_group *ret;
401+
int err;
402+
403+
group = vfio_group_alloc(iommu_group, type);
404+
if (IS_ERR(group))
405+
return group;
406+
407+
err = dev_set_name(&group->dev, "%s%d",
408+
group->type == VFIO_NO_IOMMU ? "noiommu-" : "",
409+
iommu_group_id(iommu_group));
410+
if (err) {
411+
ret = ERR_PTR(err);
412+
goto err_put;
413+
}
414+
394415
group->nb.notifier_call = vfio_iommu_group_notifier;
395-
ret = iommu_group_register_notifier(iommu_group, &group->nb);
396-
if (ret) {
397-
iommu_group_put(iommu_group);
398-
kfree(group);
399-
return ERR_PTR(ret);
416+
err = iommu_group_register_notifier(iommu_group, &group->nb);
417+
if (err) {
418+
ret = ERR_PTR(err);
419+
goto err_put;
400420
}
401421

402422
mutex_lock(&vfio.group_lock);
403423

404424
/* Did we race creating this group? */
405-
existing_group = __vfio_group_get_from_iommu(iommu_group);
406-
if (existing_group) {
407-
vfio_group_unlock_and_free(group);
408-
return existing_group;
409-
}
410-
411-
minor = vfio_alloc_group_minor(group);
412-
if (minor < 0) {
413-
vfio_group_unlock_and_free(group);
414-
return ERR_PTR(minor);
415-
}
425+
ret = __vfio_group_get_from_iommu(iommu_group);
426+
if (ret)
427+
goto err_unlock;
416428

417-
dev = device_create(vfio.class, NULL,
418-
MKDEV(MAJOR(vfio.group_devt), minor), group, "%s%d",
419-
group->type == VFIO_NO_IOMMU ? "noiommu-" : "",
420-
iommu_group_id(iommu_group));
421-
if (IS_ERR(dev)) {
422-
vfio_free_group_minor(minor);
423-
vfio_group_unlock_and_free(group);
424-
return ERR_CAST(dev);
429+
err = cdev_device_add(&group->cdev, &group->dev);
430+
if (err) {
431+
ret = ERR_PTR(err);
432+
goto err_unlock;
425433
}
426434

427-
group->minor = minor;
428-
group->dev = dev;
429-
430435
list_add(&group->vfio_next, &vfio.group_list);
431436

432437
mutex_unlock(&vfio.group_lock);
433438
return group;
439+
440+
err_unlock:
441+
mutex_unlock(&vfio.group_lock);
442+
iommu_group_unregister_notifier(group->iommu_group, &group->nb);
443+
err_put:
444+
put_device(&group->dev);
445+
return ret;
434446
}
435447

436448
static void vfio_group_put(struct vfio_group *group)
@@ -448,33 +460,19 @@ static void vfio_group_put(struct vfio_group *group)
448460
WARN_ON(atomic_read(&group->container_users));
449461
WARN_ON(group->notifier.head);
450462

451-
device_destroy(vfio.class, MKDEV(MAJOR(vfio.group_devt), group->minor));
452463
list_del(&group->vfio_next);
453-
vfio_free_group_minor(group->minor);
454-
vfio_group_unlock_and_free(group);
464+
cdev_device_del(&group->cdev, &group->dev);
465+
mutex_unlock(&vfio.group_lock);
466+
467+
iommu_group_unregister_notifier(group->iommu_group, &group->nb);
468+
put_device(&group->dev);
455469
}
456470

457471
static void vfio_group_get(struct vfio_group *group)
458472
{
459473
refcount_inc(&group->users);
460474
}
461475

462-
static struct vfio_group *vfio_group_get_from_minor(int minor)
463-
{
464-
struct vfio_group *group;
465-
466-
mutex_lock(&vfio.group_lock);
467-
group = idr_find(&vfio.group_idr, minor);
468-
if (!group) {
469-
mutex_unlock(&vfio.group_lock);
470-
return NULL;
471-
}
472-
vfio_group_get(group);
473-
mutex_unlock(&vfio.group_lock);
474-
475-
return group;
476-
}
477-
478476
static struct vfio_group *vfio_group_get_from_dev(struct device *dev)
479477
{
480478
struct iommu_group *iommu_group;
@@ -1479,11 +1477,12 @@ static long vfio_group_fops_unl_ioctl(struct file *filep,
14791477

14801478
static int vfio_group_fops_open(struct inode *inode, struct file *filep)
14811479
{
1482-
struct vfio_group *group;
1480+
struct vfio_group *group =
1481+
container_of(inode->i_cdev, struct vfio_group, cdev);
14831482
int opened;
14841483

1485-
group = vfio_group_get_from_minor(iminor(inode));
1486-
if (!group)
1484+
/* users can be zero if this races with vfio_group_put() */
1485+
if (!refcount_inc_not_zero(&group->users))
14871486
return -ENODEV;
14881487

14891488
if (group->type == VFIO_NO_IOMMU && !capable(CAP_SYS_RAWIO)) {
@@ -2293,7 +2292,7 @@ static int __init vfio_init(void)
22932292
{
22942293
int ret;
22952294

2296-
idr_init(&vfio.group_idr);
2295+
ida_init(&vfio.group_ida);
22972296
mutex_init(&vfio.group_lock);
22982297
mutex_init(&vfio.iommu_drivers_lock);
22992298
INIT_LIST_HEAD(&vfio.group_list);
@@ -2318,20 +2317,13 @@ static int __init vfio_init(void)
23182317
if (ret)
23192318
goto err_alloc_chrdev;
23202319

2321-
cdev_init(&vfio.group_cdev, &vfio_group_fops);
2322-
ret = cdev_add(&vfio.group_cdev, vfio.group_devt, MINORMASK + 1);
2323-
if (ret)
2324-
goto err_cdev_add;
2325-
23262320
pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
23272321

23282322
#ifdef CONFIG_VFIO_NOIOMMU
23292323
vfio_register_iommu_driver(&vfio_noiommu_ops);
23302324
#endif
23312325
return 0;
23322326

2333-
err_cdev_add:
2334-
unregister_chrdev_region(vfio.group_devt, MINORMASK + 1);
23352327
err_alloc_chrdev:
23362328
class_destroy(vfio.class);
23372329
vfio.class = NULL;
@@ -2347,8 +2339,7 @@ static void __exit vfio_cleanup(void)
23472339
#ifdef CONFIG_VFIO_NOIOMMU
23482340
vfio_unregister_iommu_driver(&vfio_noiommu_ops);
23492341
#endif
2350-
idr_destroy(&vfio.group_idr);
2351-
cdev_del(&vfio.group_cdev);
2342+
ida_destroy(&vfio.group_ida);
23522343
unregister_chrdev_region(vfio.group_devt, MINORMASK + 1);
23532344
class_destroy(vfio.class);
23542345
vfio.class = NULL;

0 commit comments

Comments
 (0)