OSDN Git Service

iommu/iommu-debug: Don't add debugfs entries until we init
authorMitchel Humpherys <mitchelh@codeaurora.org>
Tue, 14 Jul 2015 21:30:33 +0000 (14:30 -0700)
committerDavid Keitel <dkeitel@codeaurora.org>
Tue, 22 Mar 2016 18:13:34 +0000 (11:13 -0700)
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 <mitchelh@codeaurora.org>
drivers/iommu/iommu-debug.c

index 3347af4..72d4a89 100644 (file)
@@ -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; }