aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-07-22 11:55:49 +0200
committerDmitry Vyukov <dvyukov@google.com>2024-07-25 13:12:57 +0000
commitbe9e3862febd938fc90a69277b9cc218a5e46e28 (patch)
tree6ab258439997f1abf9da4e6e4af96f909408d3c1
parente02ef79b9ce5bc23eac00a1919746a36a308a4ae (diff)
vm: add snapshot interface
-rw-r--r--pkg/mgrconfig/config.go5
-rw-r--r--vm/vm.go51
-rw-r--r--vm/vmimpl/vmimpl.go1
3 files changed, 52 insertions, 5 deletions
diff --git a/pkg/mgrconfig/config.go b/pkg/mgrconfig/config.go
index 0909cd605..b4368f6d5 100644
--- a/pkg/mgrconfig/config.go
+++ b/pkg/mgrconfig/config.go
@@ -137,6 +137,11 @@ type Config struct {
// on this value.
SandboxArg int64 `json:"sandbox_arg"`
+ // Enables snapshotting mode. In this mode VM is snapshotted and restarted from the snapshot
+ // before executing each test program. This provides better reproducibility and avoids global
+ // accumulated state. Currently only qemu VMs and Linux support this mode.
+ Snapshot bool `json:"snapshot"`
+
// Use KCOV coverage (default: true).
Cover bool `json:"cover"`
// Use coverage filter. Supported types of filter:
diff --git a/vm/vm.go b/vm/vm.go
index 19833dc99..ee40865d7 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -11,6 +11,7 @@ package vm
import (
"bytes"
"context"
+ "errors"
"fmt"
"io"
"os"
@@ -48,16 +49,18 @@ type Pool struct {
template string
timeouts targets.Timeouts
activeCount int32
+ snapshot bool
hostFuzzer bool
statOutputReceived *stat.Val
}
type Instance struct {
- pool *Pool
- impl vmimpl.Instance
- workdir string
- index int
- onClose func()
+ pool *Pool
+ impl vmimpl.Instance
+ workdir string
+ index int
+ snapshotSetup bool
+ onClose func()
}
var (
@@ -119,6 +122,7 @@ func Create(cfg *mgrconfig.Config, debug bool) (*Pool, error) {
SSHKey: cfg.SSHKey,
SSHUser: cfg.SSHUser,
Timeouts: cfg.Timeouts,
+ Snapshot: cfg.Snapshot,
Debug: debug,
Config: cfg.VM,
KernelSrc: cfg.KernelSrc,
@@ -133,6 +137,7 @@ func Create(cfg *mgrconfig.Config, debug bool) (*Pool, error) {
workdir: env.Workdir,
template: cfg.WorkdirTemplate,
timeouts: cfg.Timeouts,
+ snapshot: cfg.Snapshot,
hostFuzzer: cfg.SysTarget.HostFuzzer,
statOutputReceived: stat.New("vm output", "Bytes of VM console output received",
stat.Graph("traffic"), stat.Rate{}, stat.FormatMB),
@@ -184,6 +189,42 @@ func (pool *Pool) Close() error {
return nil
}
+// SetupSnapshot must be called once before calling RunSnapshot.
+// Input is copied into the VM in an implementation defined way and is interpreted by executor.
+func (inst *Instance) SetupSnapshot(input []byte) error {
+ impl, ok := inst.impl.(snapshotter)
+ if !ok {
+ return errors.New("this VM type does not support snapshot mode")
+ }
+ if inst.snapshotSetup {
+ return fmt.Errorf("SetupSnapshot called twice")
+ }
+ inst.snapshotSetup = true
+ return impl.SetupSnapshot(input)
+}
+
+// RunSnapshot runs one input in snapshotting mode.
+// Input is copied into the VM in an implementation defined way and is interpreted by executor.
+// Result is the result provided by the executor.
+// Output is the kernel console output during execution of the input.
+func (inst *Instance) RunSnapshot(input []byte) (result, output []byte, err error) {
+ impl, ok := inst.impl.(snapshotter)
+ if !ok {
+ return nil, nil, errors.New("this VM type does not support snapshot mode")
+ }
+ if !inst.snapshotSetup {
+ return nil, nil, fmt.Errorf("RunSnapshot without SetupSnapshot")
+ }
+ // Executor has own timeout logic, so use a slightly larger timeout here.
+ timeout := inst.pool.timeouts.Program / 5 * 7
+ return impl.RunSnapshot(timeout, input)
+}
+
+type snapshotter interface {
+ SetupSnapshot([]byte) error
+ RunSnapshot(time.Duration, []byte) ([]byte, []byte, error)
+}
+
func (inst *Instance) Copy(hostSrc string) (string, error) {
return inst.impl.Copy(hostSrc)
}
diff --git a/vm/vmimpl/vmimpl.go b/vm/vmimpl/vmimpl.go
index 564c3e66e..b95bd2a18 100644
--- a/vm/vmimpl/vmimpl.go
+++ b/vm/vmimpl/vmimpl.go
@@ -79,6 +79,7 @@ type Env struct {
SSHKey string
SSHUser string
Timeouts targets.Timeouts
+ Snapshot bool
Debug bool
Config []byte // json-serialized VM-type-specific config
KernelSrc string