cpus: fix deadlock and segfault in qemu_mutex_lock_iothread
When two threads (other than the low-priority TCG VCPU thread) are competing for the iothread lock, a deadlock can happen. This is because iothread_requesting_mutex is set to false by the first thread that gets the mutex, and then the VCPU thread might never yield from the execution loop. If iothread_requesting_mutex is changed from a bool to a counter, the deadlock is fixed. However, there is another bug in qemu_mutex_lock_iothread that can be triggered by the new call_rcu thread. The bug happens if qemu_mutex_lock_iothread is called before the CPUs are created. In that case, first_cpu is NULL and the caller segfaults in qemu_mutex_lock_iothread. To fix this, just do not do the kick if first_cpu is NULL. Reported-by: Leon Alrae <leon.alrae@imgtec.com> Reported-by: Andreas Gustafsson <gson@gson.org> Tested-by: Leon Alrae <leon.alrae@imgtec.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									f6758f7d6b
								
							
						
					
					
						commit
						6b49809c59
					
				
							
								
								
									
										8
									
								
								cpus.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								cpus.c
									
									
									
									
									
								
							@ -778,7 +778,7 @@ static void qemu_tcg_init_cpu_signals(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static QemuMutex qemu_global_mutex;
 | 
					static QemuMutex qemu_global_mutex;
 | 
				
			||||||
static QemuCond qemu_io_proceeded_cond;
 | 
					static QemuCond qemu_io_proceeded_cond;
 | 
				
			||||||
static bool iothread_requesting_mutex;
 | 
					static unsigned iothread_requesting_mutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static QemuThread io_thread;
 | 
					static QemuThread io_thread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1115,15 +1115,15 @@ bool qemu_in_vcpu_thread(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void qemu_mutex_lock_iothread(void)
 | 
					void qemu_mutex_lock_iothread(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!tcg_enabled()) {
 | 
					    if (!tcg_enabled() || !first_cpu) {
 | 
				
			||||||
        qemu_mutex_lock(&qemu_global_mutex);
 | 
					        qemu_mutex_lock(&qemu_global_mutex);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        iothread_requesting_mutex = true;
 | 
					        atomic_inc(&iothread_requesting_mutex);
 | 
				
			||||||
        if (qemu_mutex_trylock(&qemu_global_mutex)) {
 | 
					        if (qemu_mutex_trylock(&qemu_global_mutex)) {
 | 
				
			||||||
            qemu_cpu_kick_thread(first_cpu);
 | 
					            qemu_cpu_kick_thread(first_cpu);
 | 
				
			||||||
            qemu_mutex_lock(&qemu_global_mutex);
 | 
					            qemu_mutex_lock(&qemu_global_mutex);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        iothread_requesting_mutex = false;
 | 
					        atomic_dec(&iothread_requesting_mutex);
 | 
				
			||||||
        qemu_cond_broadcast(&qemu_io_proceeded_cond);
 | 
					        qemu_cond_broadcast(&qemu_io_proceeded_cond);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user