Skip to content
Snippets Groups Projects
Select Git revision
  • v5.4-rt
  • v5.10-rt
  • v6.1-rt
  • v6.6-rt
  • v6.6-rt-next
  • v4.19-rt
  • v4.14-rt
  • v6.6-rt-rebase
  • v5.15-rt
  • v5.15-rt-next
  • v6.1-rt-next
  • v6.1-rt-rebase
  • v4.9-rt
  • v4.19-rt-next
  • v4.4-rt
  • v5.10-rt-next
  • v5.15-rt-rebase
  • stable-rt/v5.10-rt
  • v4.14-rt-next
  • v5.10-rt-rebase
  • v5.4.293-rt98-rebase protected
  • v5.15.183-rt85-rebase protected
  • v5.4.293-rt98 protected
  • v5.4.291-rt97 protected
  • v5.15.183-rt85 protected
  • v5.10.237-rt131-rebase protected
  • v5.10.237-rt131 protected
  • v6.6.87-rt54-arch1 protected
  • v5.10.237-rt131-rc1 protected
  • v5.10.236-rt130 protected
  • v5.10.236-rt130-rc1 protected
  • v6.1.134-rt51-rebase protected
  • v6.1.134-rt51 protected
  • v6.6.87-rt54-rebase protected
  • v6.6.87-rt54 protected
  • v6.6.85-rt53-rebase protected
  • v6.6.85-rt53 protected
  • v6.1.132-rt50-rebase protected
  • v6.1.132-rt50 protected
  • v5.10.235-rt129-rebase protected
40 results

kernel

  • Clone with SSH
  • Clone with HTTPS
  • user avatar
    Oleg Nesterov authored
    Let's suppose we have 2 threads in thread group:
    	A - does coredump
    	B - has pending SIGSTOP
    
    thread A						thread B
    
    do_coredump:						get_signal_to_deliver:
    
      lock(->sighand)
      ->signal->flags = SIGNAL_GROUP_EXIT
      unlock(->sighand)
    
    							lock(->sighand)
    							signr = dequeue_signal()
    								->signal->flags |= SIGNAL_STOP_DEQUEUED
    								return SIGSTOP;
    
    							do_signal_stop:
    							    unlock(->sighand)
    
      coredump_wait:
    
          zap_threads:
              lock(tasklist_lock)
              send SIGKILL to B
                  // signal_wake_up() does nothing
              unlock(tasklist_lock)
    
    							    lock(tasklist_lock)
    							    lock(->sighand)
    							    re-check sig->flags & SIGNAL_STOP_DEQUEUED, yes
    							    set_current_state(TASK_STOPPED);
    							    finish_stop:
    							        schedule();
    							            // ->state == TASK_STOPPED
    
          wait_for_completion(&startup_done)
             // waits for complete() from B,
             // ->state == TASK_UNINTERRUPTIBLE
    
    We can't wake up 'B' in any way:
    
    	SIGCONT will be ignored because handle_stop_signal() sees
    	->signal->flags & SIGNAL_GROUP_EXIT.
    
    	sys_kill(SIGKILL)->__group_complete_signal() will choose
    	uninterruptible 'A', so it can't help.
    
    	sys_tkill(B, SIGKILL) will be ignored by specific_send_sig_info()
    	because B already has pending SIGKILL.
    
    This scenario is not possbile if 'A' does do_group_exit(), because
    it sets sig->flags = SIGNAL_GROUP_EXIT and delivers SIGKILL to
    subthreads atomically, holding both tasklist_lock and sighand->lock.
    That means that do_signal_stop() will notice !SIGNAL_STOP_DEQUEUED
    after re-locking ->sighand. And it is not possible to any other
    thread to re-add SIGNAL_STOP_DEQUEUED later, because dequeue_signal()
    can only return SIGKILL.
    
    I think it is better to change do_coredump() to do sigaddset(SIGKILL)
    and signal_wake_up() under sighand->lock, but this patch is much
    simpler.
    
    Signed-off-by: default avatarOleg Nesterov <oleg@tv-sign.ru>
    Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
    788e05a6
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    Name Last commit Last update
    ..