Skip to content
Snippets Groups Projects
  • Longpeng (Mike)'s avatar
    f962cac4
    cpus: avoid pause_all_vcpus getting stuck due to race · f962cac4
    Longpeng (Mike) authored
    
    We found an issue when repeat reboot in guest during migration, it cause the
    migration thread never be waken up again.
    
    <main loop>                        |<migration_thread>
                                       |
    LOCK BQL                           |
    ...                                |
    main_loop_should_exit              |
     pause_all_vcpus                   |
      1. set all cpus ->stop=true      |
         and then kick                 |
      2. return if all cpus is paused  |
         (by '->stopped == true'), else|
      3. qemu_cond_wait [BQL UNLOCK]   |
                                       |LOCK BQL
                                       |...
                                       |do_vm_stop
                                       | pause_all_vcpus
                                       |  (A)set all cpus ->stop=true
                                       |     and then kick
                                       |  (B)return if all cpus is paused
                                       |     (by '->stopped == true'), else
                                       |  (C)qemu_cond_wait [BQL UNLOCK]
      4. be waken up and LOCK BQL      |  (D)be waken up BUT wait for  BQL
      5. goto 2.                       |
     (BQL is still LOCKed)             |
     resume_all_vcpus                  |
      1. set all cpus ->stop=false     |
         and ->stopped=false           |
    ...                                |
    BQL UNLOCK                         |  (E)LOCK BQL
                                       |  (F)goto B. [but stopped is false now!]
                                       |Finally, sleep at step 3 forever.
    
    resume_all_vcpus should notice this race, so we need to move the change
    of runstate before pause_all_vcpus in do_vm_stop() and ignore the resume
    request if runstate is not running.
    
    Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
    Cc: Richard Henderson <rth@twiddle.net>
    Signed-off-by: default avatarLongpeng <longpeng2@huawei.com>
    Suggested-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    Message-Id: <20200316083732.2010-1-longpeng2@huawei.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    f962cac4
    History
    cpus: avoid pause_all_vcpus getting stuck due to race
    Longpeng (Mike) authored
    
    We found an issue when repeat reboot in guest during migration, it cause the
    migration thread never be waken up again.
    
    <main loop>                        |<migration_thread>
                                       |
    LOCK BQL                           |
    ...                                |
    main_loop_should_exit              |
     pause_all_vcpus                   |
      1. set all cpus ->stop=true      |
         and then kick                 |
      2. return if all cpus is paused  |
         (by '->stopped == true'), else|
      3. qemu_cond_wait [BQL UNLOCK]   |
                                       |LOCK BQL
                                       |...
                                       |do_vm_stop
                                       | pause_all_vcpus
                                       |  (A)set all cpus ->stop=true
                                       |     and then kick
                                       |  (B)return if all cpus is paused
                                       |     (by '->stopped == true'), else
                                       |  (C)qemu_cond_wait [BQL UNLOCK]
      4. be waken up and LOCK BQL      |  (D)be waken up BUT wait for  BQL
      5. goto 2.                       |
     (BQL is still LOCKed)             |
     resume_all_vcpus                  |
      1. set all cpus ->stop=false     |
         and ->stopped=false           |
    ...                                |
    BQL UNLOCK                         |  (E)LOCK BQL
                                       |  (F)goto B. [but stopped is false now!]
                                       |Finally, sleep at step 3 forever.
    
    resume_all_vcpus should notice this race, so we need to move the change
    of runstate before pause_all_vcpus in do_vm_stop() and ignore the resume
    request if runstate is not running.
    
    Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
    Cc: Richard Henderson <rth@twiddle.net>
    Signed-off-by: default avatarLongpeng <longpeng2@huawei.com>
    Suggested-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    Message-Id: <20200316083732.2010-1-longpeng2@huawei.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>