diff options
| author | Jeff Garzik <jeff@garzik.org> | 2006-05-20 00:03:38 -0400 |
|---|---|---|
| committer | Jeff Garzik <jeff@garzik.org> | 2006-05-20 00:03:38 -0400 |
| commit | badc48e6605ddeeb2484afae5993c859494decaa (patch) | |
| tree | 7da638f9bb53b1812b71e40ad6deca91d59ad301 /kernel | |
| parent | 753a6c4ff4c371a3e4e3408aaba4d03f3cfde73a (diff) | |
| parent | 2f880b65fdbc2d4915bddc59d75a176329570fdd (diff) | |
Merge branch 'master' into upstream
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/extable.c | 2 | ||||
| -rw-r--r-- | kernel/module.c | 12 | ||||
| -rw-r--r-- | kernel/ptrace.c | 57 | ||||
| -rw-r--r-- | kernel/rcupdate.c | 19 |
4 files changed, 65 insertions, 25 deletions
diff --git a/kernel/extable.c b/kernel/extable.c index 7501b531ceed..7fe262855317 100644 --- a/kernel/extable.c +++ b/kernel/extable.c | |||
| @@ -40,7 +40,7 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr) | |||
| 40 | return e; | 40 | return e; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | static int core_kernel_text(unsigned long addr) | 43 | int core_kernel_text(unsigned long addr) |
| 44 | { | 44 | { |
| 45 | if (addr >= (unsigned long)_stext && | 45 | if (addr >= (unsigned long)_stext && |
| 46 | addr <= (unsigned long)_etext) | 46 | addr <= (unsigned long)_etext) |
diff --git a/kernel/module.c b/kernel/module.c index d24deb0dbbc9..bbe04862e1b0 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -705,14 +705,14 @@ EXPORT_SYMBOL(__symbol_put); | |||
| 705 | 705 | ||
| 706 | void symbol_put_addr(void *addr) | 706 | void symbol_put_addr(void *addr) |
| 707 | { | 707 | { |
| 708 | unsigned long flags; | 708 | struct module *modaddr; |
| 709 | 709 | ||
| 710 | spin_lock_irqsave(&modlist_lock, flags); | 710 | if (core_kernel_text((unsigned long)addr)) |
| 711 | if (!kernel_text_address((unsigned long)addr)) | 711 | return; |
| 712 | BUG(); | ||
| 713 | 712 | ||
| 714 | module_put(module_text_address((unsigned long)addr)); | 713 | if (!(modaddr = module_text_address((unsigned long)addr))) |
| 715 | spin_unlock_irqrestore(&modlist_lock, flags); | 714 | BUG(); |
| 715 | module_put(modaddr); | ||
| 716 | } | 716 | } |
| 717 | EXPORT_SYMBOL_GPL(symbol_put_addr); | 717 | EXPORT_SYMBOL_GPL(symbol_put_addr); |
| 718 | 718 | ||
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 4e0f0ec003f7..921c22ad16e4 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -148,12 +148,34 @@ int ptrace_may_attach(struct task_struct *task) | |||
| 148 | int ptrace_attach(struct task_struct *task) | 148 | int ptrace_attach(struct task_struct *task) |
| 149 | { | 149 | { |
| 150 | int retval; | 150 | int retval; |
| 151 | task_lock(task); | 151 | |
| 152 | retval = -EPERM; | 152 | retval = -EPERM; |
| 153 | if (task->pid <= 1) | 153 | if (task->pid <= 1) |
| 154 | goto bad; | 154 | goto out; |
| 155 | if (task->tgid == current->tgid) | 155 | if (task->tgid == current->tgid) |
| 156 | goto bad; | 156 | goto out; |
| 157 | |||
| 158 | repeat: | ||
| 159 | /* | ||
| 160 | * Nasty, nasty. | ||
| 161 | * | ||
| 162 | * We want to hold both the task-lock and the | ||
| 163 | * tasklist_lock for writing at the same time. | ||
| 164 | * But that's against the rules (tasklist_lock | ||
| 165 | * is taken for reading by interrupts on other | ||
| 166 | * cpu's that may have task_lock). | ||
| 167 | */ | ||
| 168 | task_lock(task); | ||
| 169 | local_irq_disable(); | ||
| 170 | if (!write_trylock(&tasklist_lock)) { | ||
| 171 | local_irq_enable(); | ||
| 172 | task_unlock(task); | ||
| 173 | do { | ||
| 174 | cpu_relax(); | ||
| 175 | } while (!write_can_lock(&tasklist_lock)); | ||
| 176 | goto repeat; | ||
| 177 | } | ||
| 178 | |||
| 157 | /* the same process cannot be attached many times */ | 179 | /* the same process cannot be attached many times */ |
| 158 | if (task->ptrace & PT_PTRACED) | 180 | if (task->ptrace & PT_PTRACED) |
| 159 | goto bad; | 181 | goto bad; |
| @@ -166,17 +188,15 @@ int ptrace_attach(struct task_struct *task) | |||
| 166 | ? PT_ATTACHED : 0); | 188 | ? PT_ATTACHED : 0); |
| 167 | if (capable(CAP_SYS_PTRACE)) | 189 | if (capable(CAP_SYS_PTRACE)) |
| 168 | task->ptrace |= PT_PTRACE_CAP; | 190 | task->ptrace |= PT_PTRACE_CAP; |
| 169 | task_unlock(task); | ||
| 170 | 191 | ||
| 171 | write_lock_irq(&tasklist_lock); | ||
| 172 | __ptrace_link(task, current); | 192 | __ptrace_link(task, current); |
| 173 | write_unlock_irq(&tasklist_lock); | ||
| 174 | 193 | ||
| 175 | force_sig_specific(SIGSTOP, task); | 194 | force_sig_specific(SIGSTOP, task); |
| 176 | return 0; | ||
| 177 | 195 | ||
| 178 | bad: | 196 | bad: |
| 197 | write_unlock_irq(&tasklist_lock); | ||
| 179 | task_unlock(task); | 198 | task_unlock(task); |
| 199 | out: | ||
| 180 | return retval; | 200 | return retval; |
| 181 | } | 201 | } |
| 182 | 202 | ||
| @@ -417,21 +437,22 @@ int ptrace_request(struct task_struct *child, long request, | |||
| 417 | */ | 437 | */ |
| 418 | int ptrace_traceme(void) | 438 | int ptrace_traceme(void) |
| 419 | { | 439 | { |
| 420 | int ret; | 440 | int ret = -EPERM; |
| 421 | 441 | ||
| 422 | /* | 442 | /* |
| 423 | * Are we already being traced? | 443 | * Are we already being traced? |
| 424 | */ | 444 | */ |
| 425 | if (current->ptrace & PT_PTRACED) | 445 | task_lock(current); |
| 426 | return -EPERM; | 446 | if (!(current->ptrace & PT_PTRACED)) { |
| 427 | ret = security_ptrace(current->parent, current); | 447 | ret = security_ptrace(current->parent, current); |
| 428 | if (ret) | 448 | /* |
| 429 | return -EPERM; | 449 | * Set the ptrace bit in the process ptrace flags. |
| 430 | /* | 450 | */ |
| 431 | * Set the ptrace bit in the process ptrace flags. | 451 | if (!ret) |
| 432 | */ | 452 | current->ptrace |= PT_PTRACED; |
| 433 | current->ptrace |= PT_PTRACED; | 453 | } |
| 434 | return 0; | 454 | task_unlock(current); |
| 455 | return ret; | ||
| 435 | } | 456 | } |
| 436 | 457 | ||
| 437 | /** | 458 | /** |
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 6d32ff26f948..2058f88c7bbb 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c | |||
| @@ -479,12 +479,31 @@ static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) | |||
| 479 | return 0; | 479 | return 0; |
| 480 | } | 480 | } |
| 481 | 481 | ||
| 482 | /* | ||
| 483 | * Check to see if there is any immediate RCU-related work to be done | ||
| 484 | * by the current CPU, returning 1 if so. This function is part of the | ||
| 485 | * RCU implementation; it is -not- an exported member of the RCU API. | ||
| 486 | */ | ||
| 482 | int rcu_pending(int cpu) | 487 | int rcu_pending(int cpu) |
| 483 | { | 488 | { |
| 484 | return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) || | 489 | return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) || |
| 485 | __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)); | 490 | __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)); |
| 486 | } | 491 | } |
| 487 | 492 | ||
| 493 | /* | ||
| 494 | * Check to see if any future RCU-related work will need to be done | ||
| 495 | * by the current CPU, even if none need be done immediately, returning | ||
| 496 | * 1 if so. This function is part of the RCU implementation; it is -not- | ||
| 497 | * an exported member of the RCU API. | ||
| 498 | */ | ||
| 499 | int rcu_needs_cpu(int cpu) | ||
| 500 | { | ||
| 501 | struct rcu_data *rdp = &per_cpu(rcu_data, cpu); | ||
| 502 | struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu); | ||
| 503 | |||
| 504 | return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu)); | ||
| 505 | } | ||
| 506 | |||
| 488 | void rcu_check_callbacks(int cpu, int user) | 507 | void rcu_check_callbacks(int cpu, int user) |
| 489 | { | 508 | { |
| 490 | if (user || | 509 | if (user || |
