Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion machine/cmdline.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,13 @@ func (c Cmdline) String() string {
// Timing shortcuts a KVM guest can take:
// no_timer_check skip the boot-time timer IRQ delivery probe,
// which exists for hardware that misroutes it.
// tsc=reliable trust the TSC and skip the clocksource watchdog.
// The watchdog exists for silicon whose TSC drifts
// or stops; this machine's TSC is the host's, which
// KVM advertises as invariant, and the guest is
// told so through CPUID.
// rcupdate.rcu_expedited=1 expedite RCU grace periods during boot.
parts = append(parts, "no_timer_check", "rcupdate.rcu_expedited=1")
parts = append(parts, "no_timer_check", "tsc=reliable", "rcupdate.rcu_expedited=1")

parts = append(parts, c.Extra...)

Expand Down
30 changes: 27 additions & 3 deletions machine/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,6 @@ func (s Spec) Args() ([]string, error) {
// every VM restored from one have their memory in a file whatever the spec being
// asked was configured with.
func (s Spec) Fingerprint() (string, error) {
shape := s.TemplateShape()

h := sha256.New()

// Length-prefixed, so that no two different machines can produce the same
Expand Down Expand Up @@ -675,6 +673,32 @@ func (s Spec) Fingerprint() (string, error) {
}
write(f.name, sum)
}
ident, err := s.Identity()
if err != nil {
return "", err
}
write("identity", ident)

return hex.EncodeToString(h.Sum(nil)), nil
}

// Identity is everything the fingerprint hashes except the contents of those
// three files: the machine's shape, its device topology, and the host's own CPU
// when the guest is being shown it.
//
// It is separate because reading the three files is the expensive half — 76 MB
// of SHA-256, 29 ms on a machine measured — and a caller that memoises that half
// needs the other half whole to key the memo on. Under-keying it is the failure
// that has no symptom: a stale fingerprint is a template that matches a machine
// it does not describe, and a restore into it is undefined rather than an error.
// So there is no list here for a caller to keep in step; there is this.
func (s Spec) Identity() (string, error) {
shape := s.TemplateShape()

var b strings.Builder
write := func(key, value string) {
_, _ = fmt.Fprintf(&b, "%s=%d:%s\n", key, len(value), value)
}
write("machine", shape.Machine)
write("cpu", shape.CPU)
write("smp", shape.SMP)
Expand Down Expand Up @@ -703,7 +727,7 @@ func (s Spec) Fingerprint() (string, error) {
write("host-cpu", cpu)
}

return hex.EncodeToString(h.Sum(nil)), nil
return b.String(), nil
}

// topology is the machine's device list — which models, at which slots — with
Expand Down