Commit 42720989 authored by Zou Nanhai's avatar Zou Nanhai Committed by Linus Torvalds

[PATCH] fix might-sleep-in-atomic while dumping elf

Here is a patch to fix a problem of might-sleep-in-atomic which David
Mosberger mentioned at
http://www.gelato.unsw.edu.au/linux-ia64/0407/10526.html

On IA64 platform, a might-sleep-in-atomic warning raise while dumping a
multi-thread process.  That is because elf_core_dump holds the tasklist_lock
before the kernel does a access_process_vm in elf_core_copy_task_regs,

This patch detached elf_core_copy_task_regs function from inside
tasklist_lock to remove the warning.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3d67e6da
...@@ -1224,6 +1224,7 @@ struct elf_thread_status ...@@ -1224,6 +1224,7 @@ struct elf_thread_status
struct list_head list; struct list_head list;
struct elf_prstatus prstatus; /* NT_PRSTATUS */ struct elf_prstatus prstatus; /* NT_PRSTATUS */
elf_fpregset_t fpu; /* NT_PRFPREG */ elf_fpregset_t fpu; /* NT_PRFPREG */
struct task_struct *thread;
#ifdef ELF_CORE_COPY_XFPREGS #ifdef ELF_CORE_COPY_XFPREGS
elf_fpxregset_t xfpu; /* NT_PRXFPREG */ elf_fpxregset_t xfpu; /* NT_PRXFPREG */
#endif #endif
...@@ -1236,18 +1237,10 @@ struct elf_thread_status ...@@ -1236,18 +1237,10 @@ struct elf_thread_status
* we need to keep a linked list of every threads pr_status and then * we need to keep a linked list of every threads pr_status and then
* create a single section for them in the final core file. * create a single section for them in the final core file.
*/ */
static int elf_dump_thread_status(long signr, struct task_struct * p, struct list_head * thread_list) static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
{ {
struct elf_thread_status *t;
int sz = 0; int sz = 0;
struct task_struct *p = t->thread;
t = kmalloc(sizeof(*t), GFP_ATOMIC);
if (!t)
return 0;
memset(t, 0, sizeof(*t));
INIT_LIST_HEAD(&t->list);
t->num_notes = 0; t->num_notes = 0;
fill_prstatus(&t->prstatus, p, signr); fill_prstatus(&t->prstatus, p, signr);
...@@ -1270,7 +1263,6 @@ static int elf_dump_thread_status(long signr, struct task_struct * p, struct lis ...@@ -1270,7 +1263,6 @@ static int elf_dump_thread_status(long signr, struct task_struct * p, struct lis
sz += notesize(&t->notes[2]); sz += notesize(&t->notes[2]);
} }
#endif #endif
list_add(&t->list, thread_list);
return sz; return sz;
} }
...@@ -1341,22 +1333,32 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) ...@@ -1341,22 +1333,32 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
goto cleanup; goto cleanup;
#endif #endif
/* capture the status of all other threads */
if (signr) { if (signr) {
struct elf_thread_status *tmp;
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
do_each_thread(g,p) do_each_thread(g,p)
if (current->mm == p->mm && current != p) { if (current->mm == p->mm && current != p) {
int sz = elf_dump_thread_status(signr, p, &thread_list); tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);
if (!sz) { if (!tmp) {
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
goto cleanup; goto cleanup;
} else }
thread_status_size += sz; memset(tmp, 0, sizeof(*tmp));
INIT_LIST_HEAD(&tmp->list);
tmp->thread = p;
list_add(&tmp->list, &thread_list);
} }
while_each_thread(g,p); while_each_thread(g,p);
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
} list_for_each(t, &thread_list) {
struct elf_thread_status *tmp;
int sz;
tmp = list_entry(t, struct elf_thread_status, list);
sz = elf_dump_thread_status(signr, tmp);
thread_status_size += sz;
}
}
/* now collect the dump for the current */ /* now collect the dump for the current */
memset(prstatus, 0, sizeof(*prstatus)); memset(prstatus, 0, sizeof(*prstatus));
fill_prstatus(prstatus, current, signr); fill_prstatus(prstatus, current, signr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment