forked from rubenslte/android_kernel_samsung_msm8226
msm: kgsl: hold a process_private refcount in process_mem_print
There is a possible race condition where the process can be going away while its debugfs 'mem' file is being read, which could cause memory corruption. Conflicts: drivers/gpu/msm/kgsl.c CRs-Fixed: 627780 Change-Id: I697486faeb3f186fd1220d0acc1e449a4f7b77b0 Signed-off-by: Jeremy Gebben <jgebben@codeaurora.org> Signed-off-by: Hareesh Gundu <hareeshg@codeaurora.org>
This commit is contained in:
committed by
Hareesh Gundu
parent
789a7e2fde
commit
441f3c2d77
+12
-19
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user