Skip to content

Commit 48952c6

Browse files
rmurphy-armgregkh
authored andcommitted
iommu: Handle default domain attach failure
commit 797a8b4d768c58caac58ee3e8cb36a164d1b7751 upstream. We wouldn't normally expect ops->attach_dev() to fail, but on IOMMUs with limited hardware resources, or generally misconfigured systems, it is certainly possible. We report failure correctly from the external iommu_attach_device() interface, but do not do so in iommu_group_add() when attaching to the default domain. The result of failure there is that the device, group and domain all get left in a broken, part-configured state which leads to weird errors and misbehaviour down the line when IOMMU API calls sort-of-but-don't-quite work. Check the return value of __iommu_attach_device() on the default domain, and refactor the error handling paths to cope with its failure and clean up correctly in such cases. Fixes: e39cb8a ("iommu: Make sure a device is always attached to a domain") Reported-by: Punit Agrawal <punit.agrawal@arm.com> Signed-off-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 3de9630 commit 48952c6

1 file changed

Lines changed: 24 additions & 13 deletions

File tree

drivers/iommu/iommu.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -391,36 +391,30 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
391391
device->dev = dev;
392392

393393
ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group");
394-
if (ret) {
395-
kfree(device);
396-
return ret;
397-
}
394+
if (ret)
395+
goto err_free_device;
398396

399397
device->name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj));
400398
rename:
401399
if (!device->name) {
402-
sysfs_remove_link(&dev->kobj, "iommu_group");
403-
kfree(device);
404-
return -ENOMEM;
400+
ret = -ENOMEM;
401+
goto err_remove_link;
405402
}
406403

407404
ret = sysfs_create_link_nowarn(group->devices_kobj,
408405
&dev->kobj, device->name);
409406
if (ret) {
410-
kfree(device->name);
411407
if (ret == -EEXIST && i >= 0) {
412408
/*
413409
* Account for the slim chance of collision
414410
* and append an instance to the name.
415411
*/
412+
kfree(device->name);
416413
device->name = kasprintf(GFP_KERNEL, "%s.%d",
417414
kobject_name(&dev->kobj), i++);
418415
goto rename;
419416
}
420-
421-
sysfs_remove_link(&dev->kobj, "iommu_group");
422-
kfree(device);
423-
return ret;
417+
goto err_free_name;
424418
}
425419

426420
kobject_get(group->devices_kobj);
@@ -432,8 +426,10 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
432426
mutex_lock(&group->mutex);
433427
list_add_tail(&device->list, &group->devices);
434428
if (group->domain)
435-
__iommu_attach_device(group->domain, dev);
429+
ret = __iommu_attach_device(group->domain, dev);
436430
mutex_unlock(&group->mutex);
431+
if (ret)
432+
goto err_put_group;
437433

438434
/* Notify any listeners about change to group. */
439435
blocking_notifier_call_chain(&group->notifier,
@@ -444,6 +440,21 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
444440
pr_info("Adding device %s to group %d\n", dev_name(dev), group->id);
445441

446442
return 0;
443+
444+
err_put_group:
445+
mutex_lock(&group->mutex);
446+
list_del(&device->list);
447+
mutex_unlock(&group->mutex);
448+
dev->iommu_group = NULL;
449+
kobject_put(group->devices_kobj);
450+
err_free_name:
451+
kfree(device->name);
452+
err_remove_link:
453+
sysfs_remove_link(&dev->kobj, "iommu_group");
454+
err_free_device:
455+
kfree(device);
456+
pr_err("Failed to add device %s to group %d: %d\n", dev_name(dev), group->id, ret);
457+
return ret;
447458
}
448459
EXPORT_SYMBOL_GPL(iommu_group_add_device);
449460

0 commit comments

Comments
 (0)