From f0abe729244069c89906418be1824e103ca8dca6 Mon Sep 17 00:00:00 2001 From: Mitchel Humpherys Date: Tue, 14 Jul 2015 14:30:33 -0700 Subject: [PATCH] iommu/iommu-debug: Don't add debugfs entries until we init The attachment tracking code adds a node to debugfs every time a client attaches a domain to an IOMMU device. The problem is that clients can start making those attachments during early boot, before iommu-debug initializes (including setting up the root debugfs directory for the attachment tracking), which means they get stuck in the root debugfs directory. Trying to initialize iommu-debug earlier than all possible IOMMU clients is tricky, so fix this by only installing debugfs entries onces we've initialized, installing debugfs entries for any early attachments at initialization time. Change-Id: I8364015346105187e0c8f787fc2b4155d72b3584 Signed-off-by: Mitchel Humpherys --- drivers/iommu/iommu-debug.c | 80 +++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 26 deletions(-) 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; }