diff options
-rw-r--r-- | include/linux/rcupdate.h | 4 | ||||
-rw-r--r-- | kernel/signal.c | 24 | ||||
-rw-r--r-- | tools/objtool/check.c | 22 |
3 files changed, 30 insertions, 20 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index e679b175b411..65163aa0bb04 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -652,9 +652,7 @@ static inline void rcu_read_lock(void) * Unfortunately, this function acquires the scheduler's runqueue and * priority-inheritance spinlocks. This means that deadlock could result * if the caller of rcu_read_unlock() already holds one of these locks or - * any lock that is ever acquired while holding them; or any lock which - * can be taken from interrupt context because rcu_boost()->rt_mutex_lock() - * does not disable irqs while taking ->wait_lock. + * any lock that is ever acquired while holding them. * * That said, RCU readers are never priority boosted unless they were * preempted. Therefore, one way to avoid deadlock is to make sure diff --git a/kernel/signal.c b/kernel/signal.c index 0f865d67415d..8d8a940422a8 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1244,19 +1244,12 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, { struct sighand_struct *sighand; + rcu_read_lock(); for (;;) { - /* - * Disable interrupts early to avoid deadlocks. - * See rcu_read_unlock() comment header for details. - */ - local_irq_save(*flags); - rcu_read_lock(); sighand = rcu_dereference(tsk->sighand); - if (unlikely(sighand == NULL)) { - rcu_read_unlock(); - local_irq_restore(*flags); + if (unlikely(sighand == NULL)) break; - } + /* * This sighand can be already freed and even reused, but * we rely on SLAB_TYPESAFE_BY_RCU and sighand_ctor() which @@ -1268,15 +1261,12 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, * __exit_signal(). In the latter case the next iteration * must see ->sighand == NULL. */ - spin_lock(&sighand->siglock); - if (likely(sighand == tsk->sighand)) { - rcu_read_unlock(); + spin_lock_irqsave(&sighand->siglock, *flags); + if (likely(sighand == tsk->sighand)) break; - } - spin_unlock(&sighand->siglock); - rcu_read_unlock(); - local_irq_restore(*flags); + spin_unlock_irqrestore(&sighand->siglock, *flags); } + rcu_read_unlock(); return sighand; } diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 3a31b238f885..38047c6aa575 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -543,6 +543,28 @@ static int add_jump_destinations(struct objtool_file *file) dest_off); return -1; } + + /* + * For GCC 8+, create parent/child links for any cold + * subfunctions. This is _mostly_ redundant with a similar + * initialization in read_symbols(). + * + * If a function has aliases, we want the *first* such function + * in the symbol table to be the subfunction's parent. In that + * case we overwrite the initialization done in read_symbols(). + * + * However this code can't completely replace the + * read_symbols() code because this doesn't detect the case + * where the parent function's only reference to a subfunction + * is through a switch table. + */ + if (insn->func && insn->jump_dest->func && + insn->func != insn->jump_dest->func && + !strstr(insn->func->name, ".cold.") && + strstr(insn->jump_dest->func->name, ".cold.")) { + insn->func->cfunc = insn->jump_dest->func; + insn->jump_dest->func->pfunc = insn->func; + } } return 0; |