diff options
Diffstat (limited to 'drivers/staging/android/ion/ion.c')
-rw-r--r-- | drivers/staging/android/ion/ion.c | 121 |
1 files changed, 103 insertions, 18 deletions
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 574066ff73f8..e00e6e8f95e9 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -59,6 +59,8 @@ struct ion_device { unsigned long arg); struct rb_root clients; struct dentry *debug_root; + struct dentry *heaps_debug_root; + struct dentry *clients_debug_root; }; /** @@ -69,6 +71,8 @@ struct ion_device { * @idr: an idr space for allocating handle ids * @lock: lock protecting the tree of handles * @name: used for debugging + * @display_name: used for debugging (unique version of @name) + * @display_serial: used for debugging (to make display_name unique) * @task: used for debugging * * A client represents a list of buffers this client may access. @@ -82,6 +86,8 @@ struct ion_client { struct idr idr; struct mutex lock; const char *name; + char *display_name; + int display_serial; struct task_struct *task; pid_t pid; struct dentry *debug_root; @@ -708,6 +714,21 @@ static const struct file_operations debug_client_fops = { .release = single_release, }; +static int ion_get_client_serial(const struct rb_root *root, + const unsigned char *name) +{ + int serial = -1; + struct rb_node *node; + for (node = rb_first(root); node; node = rb_next(node)) { + struct ion_client *client = rb_entry(node, struct ion_client, + node); + if (strcmp(client->name, name)) + continue; + serial = max(serial, client->display_serial); + } + return serial + 1; +} + struct ion_client *ion_client_create(struct ion_device *dev, const char *name) { @@ -716,9 +737,13 @@ struct ion_client *ion_client_create(struct ion_device *dev, struct rb_node **p; struct rb_node *parent = NULL; struct ion_client *entry; - char debug_name[64]; pid_t pid; + if (!name) { + pr_err("%s: Name cannot be null\n", __func__); + return ERR_PTR(-EINVAL); + } + get_task_struct(current->group_leader); task_lock(current->group_leader); pid = task_pid_nr(current->group_leader); @@ -733,21 +758,27 @@ struct ion_client *ion_client_create(struct ion_device *dev, task_unlock(current->group_leader); client = kzalloc(sizeof(struct ion_client), GFP_KERNEL); - if (!client) { - if (task) - put_task_struct(current->group_leader); - return ERR_PTR(-ENOMEM); - } + if (!client) + goto err_put_task_struct; client->dev = dev; client->handles = RB_ROOT; idr_init(&client->idr); mutex_init(&client->lock); - client->name = name; client->task = task; client->pid = pid; + client->name = kstrdup(name, GFP_KERNEL); + if (!client->name) + goto err_free_client; down_write(&dev->lock); + client->display_serial = ion_get_client_serial(&dev->clients, name); + client->display_name = kasprintf( + GFP_KERNEL, "%s-%d", name, client->display_serial); + if (!client->display_name) { + up_write(&dev->lock); + goto err_free_client_name; + } p = &dev->clients.rb_node; while (*p) { parent = *p; @@ -761,13 +792,28 @@ struct ion_client *ion_client_create(struct ion_device *dev, rb_link_node(&client->node, parent, p); rb_insert_color(&client->node, &dev->clients); - snprintf(debug_name, 64, "%u", client->pid); - client->debug_root = debugfs_create_file(debug_name, 0664, - dev->debug_root, client, - &debug_client_fops); + client->debug_root = debugfs_create_file(client->display_name, 0664, + dev->clients_debug_root, + client, &debug_client_fops); + if (!client->debug_root) { + char buf[256], *path; + path = dentry_path(dev->clients_debug_root, buf, 256); + pr_err("Failed to create client debugfs at %s/%s\n", + path, client->display_name); + } + up_write(&dev->lock); return client; + +err_free_client_name: + kfree(client->name); +err_free_client: + kfree(client); +err_put_task_struct: + if (task) + put_task_struct(current->group_leader); + return ERR_PTR(-ENOMEM); } EXPORT_SYMBOL(ion_client_create); @@ -792,6 +838,8 @@ void ion_client_destroy(struct ion_client *client) debugfs_remove_recursive(client->debug_root); up_write(&dev->lock); + kfree(client->display_name); + kfree(client->name); kfree(client); } EXPORT_SYMBOL(ion_client_destroy); @@ -1293,9 +1341,11 @@ static int ion_open(struct inode *inode, struct file *file) struct miscdevice *miscdev = file->private_data; struct ion_device *dev = container_of(miscdev, struct ion_device, dev); struct ion_client *client; + char debug_name[64]; pr_debug("%s: %d\n", __func__, __LINE__); - client = ion_client_create(dev, "user"); + snprintf(debug_name, 64, "%u", task_pid_nr(current->group_leader)); + client = ion_client_create(dev, debug_name); if (IS_ERR(client)) return PTR_ERR(client); file->private_data = client; @@ -1443,6 +1493,8 @@ DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get, void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) { + struct dentry *debug_file; + if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma || !heap->ops->unmap_dma) pr_err("%s: can not add heap with invalid ops struct.\n", @@ -1451,21 +1503,40 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) ion_heap_init_deferred_free(heap); + if ((heap->flags & ION_HEAP_FLAG_DEFER_FREE) || heap->ops->shrink) + ion_heap_init_shrinker(heap); + heap->dev = dev; down_write(&dev->lock); /* use negative heap->id to reverse the priority -- when traversing the list later attempt higher id numbers first */ plist_node_init(&heap->node, -heap->id); plist_add(&heap->node, &dev->heaps); - debugfs_create_file(heap->name, 0664, dev->debug_root, heap, - &debug_heap_fops); + debug_file = debugfs_create_file(heap->name, 0664, + dev->heaps_debug_root, heap, + &debug_heap_fops); + + if (!debug_file) { + char buf[256], *path; + path = dentry_path(dev->heaps_debug_root, buf, 256); + pr_err("Failed to create heap debugfs at %s/%s\n", + path, heap->name); + } + #ifdef DEBUG_HEAP_SHRINKER if (heap->shrinker.shrink) { char debug_name[64]; snprintf(debug_name, 64, "%s_shrink", heap->name); - debugfs_create_file(debug_name, 0644, dev->debug_root, heap, - &debug_shrink_fops); + debug_file = debugfs_create_file( + debug_name, 0644, dev->heaps_debug_root, heap, + &debug_shrink_fops); + if (!debug_file) { + char buf[256], *path; + path = dentry_path(dev->heaps_debug_root, buf, 256); + pr_err("Failed to create heap shrinker debugfs at %s/%s\n", + path, debug_name); + } } #endif up_write(&dev->lock); @@ -1494,8 +1565,21 @@ struct ion_device *ion_device_create(long (*custom_ioctl) } idev->debug_root = debugfs_create_dir("ion", NULL); - if (!idev->debug_root) - pr_err("ion: failed to create debug files.\n"); + if (!idev->debug_root) { + pr_err("ion: failed to create debugfs root directory.\n"); + goto debugfs_done; + } + idev->heaps_debug_root = debugfs_create_dir("heaps", idev->debug_root); + if (!idev->heaps_debug_root) { + pr_err("ion: failed to create debugfs heaps directory.\n"); + goto debugfs_done; + } + idev->clients_debug_root = debugfs_create_dir("clients", + idev->debug_root); + if (!idev->clients_debug_root) + pr_err("ion: failed to create debugfs clients directory.\n"); + +debugfs_done: idev->custom_ioctl = custom_ioctl; idev->buffers = RB_ROOT; @@ -1509,6 +1593,7 @@ struct ion_device *ion_device_create(long (*custom_ioctl) void ion_device_destroy(struct ion_device *dev) { misc_deregister(&dev->dev); + debugfs_remove_recursive(dev->debug_root); /* XXX need to free the heaps and clients ? */ kfree(dev); } |