diff options
Diffstat (limited to 'drivers/iommu/iommu.c')
-rw-r--r-- | drivers/iommu/iommu.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 515bb8b80952..a070fa39521a 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c | |||
@@ -391,36 +391,30 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev) | |||
391 | device->dev = dev; | 391 | device->dev = dev; |
392 | 392 | ||
393 | ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group"); | 393 | ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group"); |
394 | if (ret) { | 394 | if (ret) |
395 | kfree(device); | 395 | goto err_free_device; |
396 | return ret; | ||
397 | } | ||
398 | 396 | ||
399 | device->name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj)); | 397 | device->name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj)); |
400 | rename: | 398 | rename: |
401 | if (!device->name) { | 399 | if (!device->name) { |
402 | sysfs_remove_link(&dev->kobj, "iommu_group"); | 400 | ret = -ENOMEM; |
403 | kfree(device); | 401 | goto err_remove_link; |
404 | return -ENOMEM; | ||
405 | } | 402 | } |
406 | 403 | ||
407 | ret = sysfs_create_link_nowarn(group->devices_kobj, | 404 | ret = sysfs_create_link_nowarn(group->devices_kobj, |
408 | &dev->kobj, device->name); | 405 | &dev->kobj, device->name); |
409 | if (ret) { | 406 | if (ret) { |
410 | kfree(device->name); | ||
411 | if (ret == -EEXIST && i >= 0) { | 407 | if (ret == -EEXIST && i >= 0) { |
412 | /* | 408 | /* |
413 | * Account for the slim chance of collision | 409 | * Account for the slim chance of collision |
414 | * and append an instance to the name. | 410 | * and append an instance to the name. |
415 | */ | 411 | */ |
412 | kfree(device->name); | ||
416 | device->name = kasprintf(GFP_KERNEL, "%s.%d", | 413 | device->name = kasprintf(GFP_KERNEL, "%s.%d", |
417 | kobject_name(&dev->kobj), i++); | 414 | kobject_name(&dev->kobj), i++); |
418 | goto rename; | 415 | goto rename; |
419 | } | 416 | } |
420 | 417 | goto err_free_name; | |
421 | sysfs_remove_link(&dev->kobj, "iommu_group"); | ||
422 | kfree(device); | ||
423 | return ret; | ||
424 | } | 418 | } |
425 | 419 | ||
426 | kobject_get(group->devices_kobj); | 420 | kobject_get(group->devices_kobj); |
@@ -432,8 +426,10 @@ rename: | |||
432 | mutex_lock(&group->mutex); | 426 | mutex_lock(&group->mutex); |
433 | list_add_tail(&device->list, &group->devices); | 427 | list_add_tail(&device->list, &group->devices); |
434 | if (group->domain) | 428 | if (group->domain) |
435 | __iommu_attach_device(group->domain, dev); | 429 | ret = __iommu_attach_device(group->domain, dev); |
436 | mutex_unlock(&group->mutex); | 430 | mutex_unlock(&group->mutex); |
431 | if (ret) | ||
432 | goto err_put_group; | ||
437 | 433 | ||
438 | /* Notify any listeners about change to group. */ | 434 | /* Notify any listeners about change to group. */ |
439 | blocking_notifier_call_chain(&group->notifier, | 435 | blocking_notifier_call_chain(&group->notifier, |
@@ -444,6 +440,21 @@ rename: | |||
444 | pr_info("Adding device %s to group %d\n", dev_name(dev), group->id); | 440 | pr_info("Adding device %s to group %d\n", dev_name(dev), group->id); |
445 | 441 | ||
446 | return 0; | 442 | 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; | ||
447 | } | 458 | } |
448 | EXPORT_SYMBOL_GPL(iommu_group_add_device); | 459 | EXPORT_SYMBOL_GPL(iommu_group_add_device); |
449 | 460 | ||