diff options
author | Cliff Wickman <cpw@sgi.com> | 2005-10-27 11:29:08 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2005-10-27 19:15:03 -0400 |
commit | 4ac0068f44f192f2de95a7bb36df3e19767a45fb (patch) | |
tree | 7971afe201d63657fceeb5770eb8247711ce69aa | |
parent | 72ab373a5688a78cbdaf3bf96012e597d5399bb7 (diff) |
[IA64] ptrace - find memory sharers on children list
In arch/ia64/kernel/ptrace.c there is a test for a peek or poke of a
register image (in register backing storage).
The test can be unnecessarily long (and occurs while holding the tasklist_lock).
Especially long on a large system with thousands of active tasks.
The ptrace caller (presumably a debugger) specifies the pid of
its target and an address to peek or poke. But the debugger could be
attached to several tasks.
The idea of find_thread_for_addr() is to find whether the target address
is in the RBS for any of those tasks.
Currently it searches the thread-list of the target pid. If that search
does not find a match, and the shared mm-struct's user count indicates
that there are other tasks sharing this address space (a rare occurrence),
a search is made of all the tasks in the system.
Another approach can drastically shorten this procedure.
It depends upon the fact that in order to peek or poke from/to any task,
the debugger must first attach to that task. And when it does, the
attached task is made a child of the debugger (is chained to its children list).
Therefore we can search just the debugger's children list.
Signed-off-by: Cliff Wickman <cpw@sgi.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r-- | arch/ia64/kernel/ptrace.c | 26 |
1 files changed, 10 insertions, 16 deletions
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index bbb8bc7c0552..9a9c1bd01dbc 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c | |||
@@ -589,6 +589,7 @@ find_thread_for_addr (struct task_struct *child, unsigned long addr) | |||
589 | { | 589 | { |
590 | struct task_struct *g, *p; | 590 | struct task_struct *g, *p; |
591 | struct mm_struct *mm; | 591 | struct mm_struct *mm; |
592 | struct list_head *this, *next; | ||
592 | int mm_users; | 593 | int mm_users; |
593 | 594 | ||
594 | if (!(mm = get_task_mm(child))) | 595 | if (!(mm = get_task_mm(child))) |
@@ -600,28 +601,21 @@ find_thread_for_addr (struct task_struct *child, unsigned long addr) | |||
600 | goto out; /* not multi-threaded */ | 601 | goto out; /* not multi-threaded */ |
601 | 602 | ||
602 | /* | 603 | /* |
603 | * First, traverse the child's thread-list. Good for scalability with | 604 | * Traverse the current process' children list. Every task that |
604 | * NPTL-threads. | 605 | * one attaches to becomes a child. And it is only attached children |
606 | * of the debugger that are of interest (ptrace_check_attach checks | ||
607 | * for this). | ||
605 | */ | 608 | */ |
606 | p = child; | 609 | list_for_each_safe(this, next, ¤t->children) { |
607 | do { | 610 | p = list_entry(this, struct task_struct, sibling); |
608 | if (thread_matches(p, addr)) { | 611 | if (p->mm != mm) |
609 | child = p; | ||
610 | goto out; | ||
611 | } | ||
612 | if (mm_users-- <= 1) | ||
613 | goto out; | ||
614 | } while ((p = next_thread(p)) != child); | ||
615 | |||
616 | do_each_thread(g, p) { | ||
617 | if (child->mm != mm) | ||
618 | continue; | 612 | continue; |
619 | |||
620 | if (thread_matches(p, addr)) { | 613 | if (thread_matches(p, addr)) { |
621 | child = p; | 614 | child = p; |
622 | goto out; | 615 | goto out; |
623 | } | 616 | } |
624 | } while_each_thread(g, p); | 617 | } |
618 | |||
625 | out: | 619 | out: |
626 | mmput(mm); | 620 | mmput(mm); |
627 | return child; | 621 | return child; |