Page MenuHomeFreeBSD

bhyve: ahci: Do not advertise SNotification
AcceptedPublic

Authored by wanpengqian_gmail.com on Tue, Oct 20, 4:16 PM.

Details

Reviewers
mav
markj
Group Reviewers
bhyve
Summary

The emulated controller sets CAP.SSNTF, but it never generates a
notification: PxSNTF is never set by the device model, reads back as
zero and a write to it is ignored.

Linux checks HOST_CAP_SNTF and, when it is set, calls
sata_async_notification() from every port interrupt that has PxIS.SDBS
set. That function reads PxSNTF and writes the value back, so every
NCQ command costs the guest two extra MMIO accesses, i.e. two more
VM exits per I/O. QEMU and VirtualBox do not advertise SSNTF, so a
Linux guest on bhyve takes more exits per command than on them.

Drop AHCI_CAP_SSNTF from CAP. The PxSNTF register handling and its
snapshot stay as they are, so a guest that still touches the register
keeps working. CAP is part of the snapshot, so a guest restored from
a checkpoint taken before this change keeps the old CAP value and
works as before.

Signed-off-by: Wanpeng Qian <wanpengqian@gmail.com>
Sponsored by: keelos.dev

Test Plan

Built usr.sbin/bhyve on current main (0ce9d6e24) with and without WITH_BHYVE_SNAPSHOT: no warnings.

Guests ran under bhyve inside a QEMU/KVM FreeBSD main VM. The baseline is the same tree without this change.

Debian 13 (Linux 6.12), 2 vCPUs, -s 2,ahci-hd, MSI. Booted with mitigations=off and init=/bin/bash because the nested setup lacks SPEC_CTRL.

  • Before: ahci 0000:00:02.0: flags: 64bit ncq sntf ilck stag pm led clo pio slum part sxs apst. After: the same line without sntf.
  • 20000 direct 4k reads at queue depth 1 (dd if=/dev/sda of=/dev/null bs=4k count=20000 iflag=direct). The counters are from bhyvectl --get-stats, summed over both vCPUs, as the difference around the dd.
  • VM exits handled in userspace (the MMIO accesses to the controller): 10.03 per I/O before, 8.03 per I/O after, so exactly 2 fewer per I/O (the read and the write of PxSNTF).
  • The dd completes, no I/O errors in dmesg, one interrupt per I/O as before.

FreeBSD main guest (bhyveload, 2 vCPUs, ahci-hd):

  • Before: ahci0: Caps: 64bit NCQ SNTF MPS SS ALP AL CLO 6Gbps PMD SSC PSC 32cmd eSATA 32ports. After: the same line without SNTF.
  • camcontrol identify and a 20000 block dd of the disk work with both (about 1.5 MB/s in this nested setup, no timeouts or CAM errors).
  • A checkpoint taken from a guest running the unpatched bhyve was restored with the patched bhyve: the guest continues, reads the disk and writes a file.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 78424
Build 75307: arc lint + arc unit

Event Timeline

SNTF supposed to be used by CDROMs for media change notifications. Without them IIRC CAM will poll it. Though for VMs more efficient interrupt handling may indeed be more important than small idle load for CDROMs.

This revision is now accepted and ready to land.Tue, Oct 20, 5:55 PM

Thanks. I checked how the guests behave: cd(4) only skips its 3-second TUR polling when SID_AEN is set, which ata_xpt sets after PROBE_SETAN, and that step requires the device to report async notification in IDENTIFY word 78 bit 5. The ATAPI emulation here does not set that bit and never sends an SDB FIS with the N bit, so CAM already polls bhyve's CD today; this change does not alter that.

If media-change notification is added to the ATAPI emulation later (we plan to, for swapping the ISO of a running guest), both ahci(4) and Linux's libahci pick the N bit up from the received SDB FIS when CAP.SSNTF is clear, so it can be done without the register, or SSNTF can be advertised again at that point.