diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 3347af4e42e5..72d4a89cae62 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -96,35 +96,29 @@ iommu_debug_attachment_trigger_fault_fops = { .write = iommu_debug_attachment_trigger_fault_write, }; -void iommu_debug_attach_device(struct iommu_domain *domain, - struct device *dev) +/* should be called with iommu_debug_attachments_lock locked */ +static int iommu_debug_attach_add_debugfs( + struct iommu_debug_attachment *attach) { - struct iommu_debug_attachment *attach; - char *attach_name; uuid_le uuid; - - mutex_lock(&iommu_debug_attachments_lock); + char *attach_name; + struct device *dev = attach->dev; + struct iommu_domain *domain = attach->domain; uuid_le_gen(&uuid); attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev), uuid.b); if (!attach_name) - goto err_unlock; - - attach = kmalloc(sizeof(*attach), GFP_KERNEL); - if (!attach) - goto err_free_attach_name; - - attach->domain = domain; - attach->dev = dev; + return -ENOMEM; attach->dentry = debugfs_create_dir(attach_name, debugfs_attachments_dir); if (!attach->dentry) { pr_err("Couldn't create iommu/attachments/%s debugfs directory for domain 0x%p\n", attach_name, domain); - kfree(attach); - goto err_free_attach_name; + kfree(attach_name); + return -EIO; } + kfree(attach_name); if (!debugfs_create_file( "info", S_IRUSR, attach->dentry, attach, @@ -142,16 +136,39 @@ void iommu_debug_attach_device(struct iommu_domain *domain, goto err_rmdir; } - list_add(&attach->list, &iommu_debug_attachments); - kfree(attach_name); - mutex_unlock(&iommu_debug_attachments_lock); - return; + return 0; + err_rmdir: debugfs_remove_recursive(attach->dentry); - kfree(attach); -err_free_attach_name: - kfree(attach_name); -err_unlock: + return -EIO; +} + +void iommu_debug_attach_device(struct iommu_domain *domain, + struct device *dev) +{ + struct iommu_debug_attachment *attach; + + mutex_lock(&iommu_debug_attachments_lock); + + attach = kmalloc(sizeof(*attach), GFP_KERNEL); + if (!attach) + goto out_unlock; + + attach->domain = domain; + attach->dev = dev; + + /* + * we might not init until after other drivers start calling + * iommu_attach_device. Only set up the debugfs nodes if we've + * already init'd to avoid polluting the top-level debugfs + * directory (by calling debugfs_create_dir with a NULL + * parent). These will be flushed out later once we init. + */ + if (debugfs_attachments_dir) + iommu_debug_attach_add_debugfs(attach); + + list_add(&attach->list, &iommu_debug_attachments); +out_unlock: mutex_unlock(&iommu_debug_attachments_lock); } @@ -178,14 +195,25 @@ void iommu_debug_detach_device(struct iommu_domain *domain, static int iommu_debug_init_tracking(void) { + int ret = 0; + struct iommu_debug_attachment *attach; + + mutex_lock(&iommu_debug_attachments_lock); debugfs_attachments_dir = debugfs_create_dir("attachments", debugfs_top_dir); if (!debugfs_attachments_dir) { pr_err("Couldn't create iommu/attachments debugfs directory\n"); - return -ENODEV; + ret = -ENODEV; + goto out_unlock; } - return 0; + /* set up debugfs entries for attachments made during early boot */ + list_for_each_entry(attach, &iommu_debug_attachments, list) + iommu_debug_attach_add_debugfs(attach); + +out_unlock: + mutex_unlock(&iommu_debug_attachments_lock); + return ret; } #else static inline int iommu_debug_init_tracking(void) { return 0; }