]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/staging/android/ion/ion.c
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
[mirror_ubuntu-artful-kernel.git] / drivers / staging / android / ion / ion.c
index df560216d7026c87de39c8b86f885ea2443a3d17..bceb81309787c5638a40b4f15e043bcf29437647 100644 (file)
@@ -387,13 +387,22 @@ static void ion_handle_get(struct ion_handle *handle)
        kref_get(&handle->ref);
 }
 
-static int ion_handle_put(struct ion_handle *handle)
+static int ion_handle_put_nolock(struct ion_handle *handle)
+{
+       int ret;
+
+       ret = kref_put(&handle->ref, ion_handle_destroy);
+
+       return ret;
+}
+
+int ion_handle_put(struct ion_handle *handle)
 {
        struct ion_client *client = handle->client;
        int ret;
 
        mutex_lock(&client->lock);
-       ret = kref_put(&handle->ref, ion_handle_destroy);
+       ret = ion_handle_put_nolock(handle);
        mutex_unlock(&client->lock);
 
        return ret;
@@ -417,20 +426,30 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client,
        return ERR_PTR(-EINVAL);
 }
 
-static struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client,
                                                int id)
 {
        struct ion_handle *handle;
 
-       mutex_lock(&client->lock);
        handle = idr_find(&client->idr, id);
        if (handle)
                ion_handle_get(handle);
-       mutex_unlock(&client->lock);
 
        return handle ? handle : ERR_PTR(-EINVAL);
 }
 
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+                                               int id)
+{
+       struct ion_handle *handle;
+
+       mutex_lock(&client->lock);
+       handle = ion_handle_get_by_id_nolock(client, id);
+       mutex_unlock(&client->lock);
+
+       return handle;
+}
+
 static bool ion_handle_validate(struct ion_client *client,
                                struct ion_handle *handle)
 {
@@ -532,22 +551,28 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
 }
 EXPORT_SYMBOL(ion_alloc);
 
-void ion_free(struct ion_client *client, struct ion_handle *handle)
+static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle)
 {
        bool valid_handle;
 
        BUG_ON(client != handle->client);
 
-       mutex_lock(&client->lock);
        valid_handle = ion_handle_validate(client, handle);
 
        if (!valid_handle) {
                WARN(1, "%s: invalid handle passed to free.\n", __func__);
-               mutex_unlock(&client->lock);
                return;
        }
+       ion_handle_put_nolock(handle);
+}
+
+void ion_free(struct ion_client *client, struct ion_handle *handle)
+{
+       BUG_ON(client != handle->client);
+
+       mutex_lock(&client->lock);
+       ion_free_nolock(client, handle);
        mutex_unlock(&client->lock);
-       ion_handle_put(handle);
 }
 EXPORT_SYMBOL(ion_free);
 
@@ -677,6 +702,34 @@ void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle)
 }
 EXPORT_SYMBOL(ion_unmap_kernel);
 
+static struct mutex debugfs_mutex;
+static struct rb_root *ion_root_client;
+static int is_client_alive(struct ion_client *client)
+{
+       struct rb_node *node;
+       struct ion_client *tmp;
+       struct ion_device *dev;
+
+       node = ion_root_client->rb_node;
+       dev = container_of(ion_root_client, struct ion_device, clients);
+
+       down_read(&dev->lock);
+       while (node) {
+               tmp = rb_entry(node, struct ion_client, node);
+               if (client < tmp) {
+                       node = node->rb_left;
+               } else if (client > tmp) {
+                       node = node->rb_right;
+               } else {
+                       up_read(&dev->lock);
+                       return 1;
+               }
+       }
+
+       up_read(&dev->lock);
+       return 0;
+}
+
 static int ion_debug_client_show(struct seq_file *s, void *unused)
 {
        struct ion_client *client = s->private;
@@ -685,6 +738,14 @@ static int ion_debug_client_show(struct seq_file *s, void *unused)
        const char *names[ION_NUM_HEAP_IDS] = {NULL};
        int i;
 
+       mutex_lock(&debugfs_mutex);
+       if (!is_client_alive(client)) {
+               seq_printf(s, "ion_client 0x%p dead, can't dump its buffers\n",
+                          client);
+               mutex_unlock(&debugfs_mutex);
+               return 0;
+       }
+
        mutex_lock(&client->lock);
        for (n = rb_first(&client->handles); n; n = rb_next(n)) {
                struct ion_handle *handle = rb_entry(n, struct ion_handle,
@@ -696,6 +757,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused)
                sizes[id] += handle->buffer->size;
        }
        mutex_unlock(&client->lock);
+       mutex_unlock(&debugfs_mutex);
 
        seq_printf(s, "%16.16s: %16.16s\n", "heap_name", "size_in_bytes");
        for (i = 0; i < ION_NUM_HEAP_IDS; i++) {
@@ -832,6 +894,7 @@ void ion_client_destroy(struct ion_client *client)
        struct rb_node *n;
 
        pr_debug("%s: %d\n", __func__, __LINE__);
+       mutex_lock(&debugfs_mutex);
        while ((n = rb_first(&client->handles))) {
                struct ion_handle *handle = rb_entry(n, struct ion_handle,
                                                     node);
@@ -850,6 +913,7 @@ void ion_client_destroy(struct ion_client *client)
        kfree(client->display_name);
        kfree(client->name);
        kfree(client);
+       mutex_unlock(&debugfs_mutex);
 }
 EXPORT_SYMBOL(ion_client_destroy);
 
@@ -1059,8 +1123,7 @@ static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset,
 {
 }
 
-static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start,
-                                       size_t len,
+static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
                                        enum dma_data_direction direction)
 {
        struct ion_buffer *buffer = dmabuf->priv;
@@ -1078,8 +1141,7 @@ static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start,
        return PTR_ERR_OR_ZERO(vaddr);
 }
 
-static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start,
-                                      size_t len,
+static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
                                       enum dma_data_direction direction)
 {
        struct ion_buffer *buffer = dmabuf->priv;
@@ -1153,22 +1215,18 @@ int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle)
 }
 EXPORT_SYMBOL(ion_share_dma_buf_fd);
 
-struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
+struct ion_handle *ion_import_dma_buf(struct ion_client *client,
+                                     struct dma_buf *dmabuf)
 {
-       struct dma_buf *dmabuf;
        struct ion_buffer *buffer;
        struct ion_handle *handle;
        int ret;
 
-       dmabuf = dma_buf_get(fd);
-       if (IS_ERR(dmabuf))
-               return ERR_CAST(dmabuf);
        /* if this memory came from ion */
 
        if (dmabuf->ops != &dma_buf_ops) {
                pr_err("%s: can not import dmabuf from another exporter\n",
                       __func__);
-               dma_buf_put(dmabuf);
                return ERR_PTR(-EINVAL);
        }
        buffer = dmabuf->priv;
@@ -1196,11 +1254,25 @@ struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
        }
 
 end:
-       dma_buf_put(dmabuf);
        return handle;
 }
 EXPORT_SYMBOL(ion_import_dma_buf);
 
+struct ion_handle *ion_import_dma_buf_fd(struct ion_client *client, int fd)
+{
+       struct dma_buf *dmabuf;
+       struct ion_handle *handle;
+
+       dmabuf = dma_buf_get(fd);
+       if (IS_ERR(dmabuf))
+               return ERR_CAST(dmabuf);
+
+       handle = ion_import_dma_buf(client, dmabuf);
+       dma_buf_put(dmabuf);
+       return handle;
+}
+EXPORT_SYMBOL(ion_import_dma_buf_fd);
+
 static int ion_sync_for_device(struct ion_client *client, int fd)
 {
        struct dma_buf *dmabuf;
@@ -1283,11 +1355,15 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        {
                struct ion_handle *handle;
 
-               handle = ion_handle_get_by_id(client, data.handle.handle);
-               if (IS_ERR(handle))
+               mutex_lock(&client->lock);
+               handle = ion_handle_get_by_id_nolock(client, data.handle.handle);
+               if (IS_ERR(handle)) {
+                       mutex_unlock(&client->lock);
                        return PTR_ERR(handle);
-               ion_free(client, handle);
-               ion_handle_put(handle);
+               }
+               ion_free_nolock(client, handle);
+               ion_handle_put_nolock(handle);
+               mutex_unlock(&client->lock);
                break;
        }
        case ION_IOC_SHARE:
@@ -1308,7 +1384,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        {
                struct ion_handle *handle;
 
-               handle = ion_import_dma_buf(client, data.fd.fd);
+               handle = ion_import_dma_buf_fd(client, data.fd.fd);
                if (IS_ERR(handle))
                        ret = PTR_ERR(handle);
                else
@@ -1405,6 +1481,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
        seq_printf(s, "%16s %16s %16s\n", "client", "pid", "size");
        seq_puts(s, "----------------------------------------------------\n");
 
+       mutex_lock(&debugfs_mutex);
        for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
                struct ion_client *client = rb_entry(n, struct ion_client,
                                                     node);
@@ -1423,6 +1500,8 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
                                   client->pid, size);
                }
        }
+       mutex_unlock(&debugfs_mutex);
+
        seq_puts(s, "----------------------------------------------------\n");
        seq_puts(s, "orphaned allocations (info is from last known client):\n");
        mutex_lock(&dev->buffer_lock);
@@ -1474,7 +1553,7 @@ static int debug_shrink_set(void *data, u64 val)
        struct shrink_control sc;
        int objs;
 
-       sc.gfp_mask = -1;
+       sc.gfp_mask = GFP_HIGHUSER;
        sc.nr_to_scan = val;
 
        if (!val) {
@@ -1492,7 +1571,7 @@ static int debug_shrink_get(void *data, u64 *val)
        struct shrink_control sc;
        int objs;
 
-       sc.gfp_mask = -1;
+       sc.gfp_mask = GFP_HIGHUSER;
        sc.nr_to_scan = 0;
 
        objs = heap->shrinker.count_objects(&heap->shrinker, &sc);
@@ -1607,6 +1686,8 @@ debugfs_done:
        init_rwsem(&idev->lock);
        plist_head_init(&idev->heaps);
        idev->clients = RB_ROOT;
+       ion_root_client = &idev->clients;
+       mutex_init(&debugfs_mutex);
        return idev;
 }
 EXPORT_SYMBOL(ion_device_create);