summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRebecca Schultz Zavin <rebecca@android.com>2011-07-01 20:41:25 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:38:46 -0800
commitf67ccbde17e5b0fc1b6bba749b07e60d0605d98d (patch)
tree3dcc92e849f184c6fa2ef6bc2da93d0827c18947
parenteb7d0614401283b5708490951b585b231df42512 (diff)
gpu: ion: Fix bug in ion_client_create
If a process already had a client, ion_client_create would loop forever. Change-Id: I723207b5872dfc11be04ca27d38a3cf39c4a1426 Signed-off-by: Rebecca Schultz Zavin <rebecca@android.com>
-rw-r--r--drivers/gpu/ion/ion.c80
1 files changed, 48 insertions, 32 deletions
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 680588841ca1..1a63ebff5eee 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -594,6 +594,29 @@ static const struct file_operations debug_client_fops = {
.release = single_release,
};
+static struct ion_client *ion_client_lookup(struct ion_device *dev,
+ struct task_struct *task)
+{
+ struct rb_node *n = dev->user_clients.rb_node;
+ struct ion_client *client;
+
+ mutex_lock(&dev->lock);
+ while (n) {
+ client = rb_entry(n, struct ion_client, node);
+ if (task == client->task) {
+ ion_client_get(client);
+ mutex_unlock(&dev->lock);
+ return client;
+ } else if (task < client->task) {
+ n = n->rb_left;
+ } else if (task > client->task) {
+ n = n->rb_right;
+ }
+ }
+ mutex_unlock(&dev->lock);
+ return NULL;
+}
+
struct ion_client *ion_client_create(struct ion_device *dev,
unsigned int heap_mask,
const char *name)
@@ -604,18 +627,11 @@ struct ion_client *ion_client_create(struct ion_device *dev,
struct rb_node *parent = NULL;
struct ion_client *entry;
char debug_name[64];
+ pid_t pid;
- client = kzalloc(sizeof(struct ion_client), GFP_KERNEL);
- if (!client)
- return ERR_PTR(-ENOMEM);
- client->dev = dev;
- client->handles = RB_ROOT;
- mutex_init(&client->lock);
- client->name = name;
- client->heap_mask = heap_mask;
get_task_struct(current->group_leader);
task_lock(current->group_leader);
- client->pid = task_pid_nr(current->group_leader);
+ pid = task_pid_nr(current->group_leader);
/* don't bother to store task struct for kernel threads,
they can't be killed anyway */
if (current->group_leader->flags & PF_KTHREAD) {
@@ -625,7 +641,30 @@ struct ion_client *ion_client_create(struct ion_device *dev,
task = current->group_leader;
}
task_unlock(current->group_leader);
+
+ /* if this isn't a kernel thread, see if a client already
+ exists */
+ if (task) {
+ client = ion_client_lookup(dev, task);
+ if (!IS_ERR_OR_NULL(client)) {
+ put_task_struct(current->group_leader);
+ return client;
+ }
+ }
+
+ client = kzalloc(sizeof(struct ion_client), GFP_KERNEL);
+ if (!client) {
+ put_task_struct(current->group_leader);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ client->dev = dev;
+ client->handles = RB_ROOT;
+ mutex_init(&client->lock);
+ client->name = name;
+ client->heap_mask = heap_mask;
client->task = task;
+ client->pid = pid;
kref_init(&client->ref);
mutex_lock(&dev->lock);
@@ -690,29 +729,6 @@ void ion_client_destroy(struct ion_client *client)
kfree(client);
}
-static struct ion_client *ion_client_lookup(struct ion_device *dev,
- struct task_struct *task)
-{
- struct rb_node *n = dev->user_clients.rb_node;
- struct ion_client *client;
-
- mutex_lock(&dev->lock);
- while (n) {
- client = rb_entry(n, struct ion_client, node);
- if (task == client->task) {
- ion_client_get(client);
- mutex_unlock(&dev->lock);
- return client;
- } else if (task < client->task) {
- n = n->rb_left;
- } else if (task > client->task) {
- n = n->rb_right;
- }
- }
- mutex_unlock(&dev->lock);
- return NULL;
-}
-
static void _ion_client_destroy(struct kref *kref)
{
struct ion_client *client = container_of(kref, struct ion_client, ref);