diff --git a/qemu/qemu-kernel.go b/qemu/qemu-kernel.go index 26683f0..1b643de 100644 --- a/qemu/qemu-kernel.go +++ b/qemu/qemu-kernel.go @@ -71,6 +71,8 @@ type QemuSystem struct { Timeout time.Duration KilledByTimeout bool + KernelPanic bool + Died bool sshAddrPort string @@ -154,6 +156,19 @@ func kvmExists() bool { return true } +func (q *QemuSystem) panicWatcher() { + for { + time.Sleep(time.Second) + if bytes.Contains(q.Stdout, []byte("Kernel panic")) { + time.Sleep(time.Second) + // There is no reason to stay alive after kernel panic + q.Stop() + q.KernelPanic = true + return + } + } +} + // Start qemu process func (q *QemuSystem) Start() (err error) { rand.Seed(time.Now().UnixNano()) // Are you sure? @@ -214,6 +229,8 @@ func (q *QemuSystem) Start() (err error) { err = errors.New("qemu died immediately: " + string(q.Stderr)) } + go q.panicWatcher() + if q.Timeout != 0 { go func() { time.Sleep(q.Timeout) diff --git a/qemu/qemu-kernel_test.go b/qemu/qemu-kernel_test.go index d062ec0..f061cb3 100644 --- a/qemu/qemu-kernel_test.go +++ b/qemu/qemu-kernel_test.go @@ -240,6 +240,41 @@ func TestQemuSystemCopyAndInsmod(t *testing.T) { } } +func TestQemuSystemKernelPanic(t *testing.T) { + qemu, err := startTestQemu(t, time.Minute) + if err != nil { + t.Fatal(err) + } + defer qemu.Stop() + + // Enable sysrq + _, err = qemu.Command("root", "echo 1 > /proc/sys/kernel/sysrq") + if err != nil { + t.Fatal(err) + } + + // Trigger kernel panic + err = qemu.AsyncCommand("root", "sleep 1s && echo c > /proc/sysrq-trigger") + if err != nil { + t.Fatal(err) + } + + // Wait for panic watcher timeout + time.Sleep(5 * time.Second) + + if qemu.KilledByTimeout { + t.Fatal("qemu is killed by timeout, not because of panic") + } + + if !qemu.Died { + t.Fatal("qemu is not killed after kernel panic") + } + + if !qemu.KernelPanic { + t.Fatal("qemu is died but there's no information about panic") + } +} + func TestQemuSystemRun(t *testing.T) { qemu, err := startTestQemu(t, 0) if err != nil {