|
@@ -532,15 +532,18 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
|
|
|
*/
|
|
|
unsigned long get_wchan(struct task_struct *p)
|
|
|
{
|
|
|
- unsigned long start, bottom, top, sp, fp, ip;
|
|
|
+ unsigned long start, bottom, top, sp, fp, ip, ret = 0;
|
|
|
int count = 0;
|
|
|
|
|
|
if (!p || p == current || p->state == TASK_RUNNING)
|
|
|
return 0;
|
|
|
|
|
|
+ if (!try_get_task_stack(p))
|
|
|
+ return 0;
|
|
|
+
|
|
|
start = (unsigned long)task_stack_page(p);
|
|
|
if (!start)
|
|
|
- return 0;
|
|
|
+ goto out;
|
|
|
|
|
|
/*
|
|
|
* Layout of the stack page:
|
|
@@ -564,16 +567,21 @@ unsigned long get_wchan(struct task_struct *p)
|
|
|
|
|
|
sp = READ_ONCE(p->thread.sp);
|
|
|
if (sp < bottom || sp > top)
|
|
|
- return 0;
|
|
|
+ goto out;
|
|
|
|
|
|
fp = READ_ONCE_NOCHECK(((struct inactive_task_frame *)sp)->bp);
|
|
|
do {
|
|
|
if (fp < bottom || fp > top)
|
|
|
- return 0;
|
|
|
+ goto out;
|
|
|
ip = READ_ONCE_NOCHECK(*(unsigned long *)(fp + sizeof(unsigned long)));
|
|
|
- if (!in_sched_functions(ip))
|
|
|
- return ip;
|
|
|
+ if (!in_sched_functions(ip)) {
|
|
|
+ ret = ip;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
fp = READ_ONCE_NOCHECK(*(unsigned long *)fp);
|
|
|
} while (count++ < 16 && p->state != TASK_RUNNING);
|
|
|
- return 0;
|
|
|
+
|
|
|
+out:
|
|
|
+ put_task_stack(p);
|
|
|
+ return ret;
|
|
|
}
|