diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index a96ab2bd359..b0b6c8bfdee 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -64,14 +64,8 @@ struct kgsl_dma_buf_meta { struct sg_table *table; }; -static void kgsl_put_process_private(struct kgsl_device *device, - struct kgsl_process_private *private); - static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry); -static void -kgsl_put_process_private(struct kgsl_device *device, - struct kgsl_process_private *private); /** * kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy * device: KGSL device @@ -352,8 +346,8 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry, { int ret; struct kgsl_process_private *process = dev_priv->process_priv; - - ret = kref_get_unless_zero(&process->refcount); + + ret = kgsl_process_private_get(process); if (!ret) return -EBADF; @@ -392,7 +386,7 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry, return ret; err_put_proc_priv: - kgsl_put_process_private(dev_priv->device, process); + kgsl_process_private_put(process); return ret; } @@ -415,7 +409,7 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) entry->priv->stats[entry->memtype].cur -= entry->memdesc.size; spin_unlock(&entry->priv->mem_lock); - kgsl_put_process_private(entry->dev_priv->device, entry->priv); + kgsl_process_private_put(entry->priv); entry->priv = NULL; } @@ -473,7 +467,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, * the context is destroyed. This will also prevent the pagetable * from being destroyed */ - if (!kref_get_unless_zero(&dev_priv->process_priv->refcount)) + if (!kgsl_process_private_get(dev_priv->process_priv)) goto fail_free_id; context->device = dev_priv->device; context->dev_priv = dev_priv; @@ -568,8 +562,7 @@ kgsl_context_destroy(struct kref *kref) } write_unlock(&device->context_lock); kgsl_sync_timeline_destroy(context); - kgsl_put_process_private(device, - context->proc_priv); + kgsl_process_private_put(context->proc_priv); device->ftbl->drawctxt_destroy(context); } @@ -811,9 +804,8 @@ static void kgsl_destroy_process_private(struct kref *kref) return; } -static void -kgsl_put_process_private(struct kgsl_device *device, - struct kgsl_process_private *private) +void +kgsl_process_private_put(struct kgsl_process_private *private) { mutex_lock(&kgsl_driver.process_mutex); @@ -842,7 +834,8 @@ kgsl_find_process_private(struct kgsl_device_private *cur_dev_priv) mutex_lock(&kgsl_driver.process_mutex); list_for_each_entry(private, &kgsl_driver.process_list, list) { if (private->pid == task_tgid_nr(current)) { - kref_get(&private->refcount); + if (!kgsl_process_private_get(private)) + private = NULL; goto done; } } @@ -915,7 +908,7 @@ done: error: mutex_unlock(&private->process_private_mutex); - kgsl_put_process_private(cur_dev_priv->device, private); + kgsl_process_private_put(private); return NULL; } @@ -1009,7 +1002,7 @@ static int kgsl_release(struct inode *inodep, struct file *filep) kfree(dev_priv); - kgsl_put_process_private(device, private); + kgsl_process_private_put(private); pm_runtime_put(device->parentdev); return result; diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index c1b313913c4..01aa4930dd9 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -303,14 +303,36 @@ static int process_mem_print(struct seq_file *s, void *unused) static int process_mem_open(struct inode *inode, struct file *file) { - return single_open(file, process_mem_print, inode->i_private); + struct kgsl_process_private *private = inode->i_private; + + /* + * Hold a reference count on the process while open + * in case the process tries to die in the meantime. + * If the process is already dying we cannot get a + * refcount, print nothing. + */ + + if (!private || !kgsl_process_private_get(private)) + return -ENODEV; + + return single_open(file, process_mem_print, private); +} + +static int process_mem_release(struct inode *inode, struct file *file) +{ + struct kgsl_process_private *private = inode->i_private; + + if (private) + kgsl_process_private_put(private); + + return single_release(inode, file); } static const struct file_operations process_mem_fops = { .open = process_mem_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = process_mem_release, }; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 47801a46186..bda6ddfa49c 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -696,6 +696,24 @@ void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch); void kgsl_cmdbatch_destroy_object(struct kref *kref); +/** +* kgsl_process_private_get() - increment the refcount on a kgsl_process_private +* struct +* @process: Pointer to the KGSL process_private +* +* Returns 0 if the structure is invalid and a reference count could not be +* obtained, nonzero otherwise. +*/ +static inline int kgsl_process_private_get(struct kgsl_process_private *process) +{ + int ret = 0; + if (process != NULL) + ret = kref_get_unless_zero(&process->refcount); + return ret; +} + +void kgsl_process_private_put(struct kgsl_process_private *private); + /** * kgsl_cmdbatch_put() - Decrement the refcount for a command batch object * @cmdbatch: Pointer to the command batch object