Skip to content

Commit 7fbbbf9

Browse files
committed
fix: FC hugepages bug + io_uring + entropy + boot args tuning
- Fix hugepages: field was "hugepages" (bool), FC API needs "huge_pages" (string "None"/"2M"). Never worked before. - Add io_engine "Async" (io_uring) for writable drives. - Add PUT /entropy for virtio-rng device (parity with CH --rng). - Add pci=off, i8042.noaux, 8250.nr_uarts=1 to kernel cmdline to skip unnecessary device probing (~100-200ms boot savings).
1 parent dd3ed5d commit 7fbbbf9

3 files changed

Lines changed: 27 additions & 7 deletions

File tree

hypervisor/firecracker/api.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ const (
3131
// configure via HTTP PUT/PATCH, then issue InstanceStart.
3232

3333
type fcMachineConfig struct {
34-
VCPUCount int `json:"vcpu_count"`
35-
MemSizeMiB int `json:"mem_size_mib"`
36-
HugePages bool `json:"hugepages,omitempty"`
34+
VCPUCount int `json:"vcpu_count"`
35+
MemSizeMiB int `json:"mem_size_mib"`
36+
HugePages string `json:"huge_pages,omitempty"` // "None" or "2M"
3737
}
3838

3939
type fcBootSource struct {
@@ -47,6 +47,7 @@ type fcDrive struct {
4747
PathOnHost string `json:"path_on_host"`
4848
IsRootDevice bool `json:"is_root_device"`
4949
IsReadOnly bool `json:"is_read_only"`
50+
IoEngine string `json:"io_engine,omitempty"` // "Sync" (default) or "Async" (io_uring)
5051
}
5152

5253
type fcNetworkInterface struct {
@@ -126,6 +127,10 @@ func putNetworkInterface(ctx context.Context, hc *http.Client, iface fcNetworkIn
126127
return fcAPI(ctx, hc, http.MethodPut, "/network-interfaces/"+iface.IfaceID, body)
127128
}
128129

130+
func putEntropy(ctx context.Context, hc *http.Client) error {
131+
return fcAPI(ctx, hc, http.MethodPut, "/entropy", []byte("{}"))
132+
}
133+
129134
func instanceStart(ctx context.Context, hc *http.Client) error {
130135
body, err := json.Marshal(fcAction{ActionType: actionInstanceStart})
131136
if err != nil {

hypervisor/firecracker/create.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,11 @@ func buildCmdline(storageConfigs []*types.StorageConfig, networkConfigs []*types
267267
// FC serial console is ttyS0 (not hvc0 like CH's virtio-console).
268268
// reboot=k: FC has no ACPI PM — use i8042 keyboard controller reset so
269269
// guest reboot/shutdown triggers FC process exit instead of hanging.
270+
// pci=off: FC has no PCI bus, skip probing (~50-100ms saved)
271+
// i8042.noaux: no PS/2 mouse, skip auxiliary device probe timeout
272+
// 8250.nr_uarts=1: FC exposes one serial port, skip probing for 3 others
270273
fmt.Fprintf(&cmdline,
271-
"console=ttyS0 reboot=k loglevel=3 boot=cocoon-overlay cocoon.layers=%s cocoon.cow=%s clocksource=kvm-clock rw",
274+
"console=ttyS0 reboot=k loglevel=3 pci=off i8042.noaux 8250.nr_uarts=1 boot=cocoon-overlay cocoon.layers=%s cocoon.cow=%s clocksource=kvm-clock rw",
272275
strings.Join(layerDevs, ","), cowDev,
273276
)
274277

hypervisor/firecracker/start.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,14 @@ func (fc *Firecracker) startOne(ctx context.Context, id string) error {
7575
// then issues InstanceStart to boot the guest.
7676
func (fc *Firecracker) configureVM(ctx context.Context, hc *http.Client, rec *hypervisor.VMRecord) error {
7777
memMiB := int(rec.Config.Memory >> 20) //nolint:mnd
78+
hugePages := "None"
79+
if utils.DetectHugePages() {
80+
hugePages = "2M"
81+
}
7882
if err := putMachineConfig(ctx, hc, fcMachineConfig{
7983
VCPUCount: rec.Config.CPU,
8084
MemSizeMiB: memMiB,
81-
HugePages: utils.DetectHugePages(),
85+
HugePages: hugePages,
8286
}); err != nil {
8387
return fmt.Errorf("machine-config: %w", err)
8488
}
@@ -95,12 +99,16 @@ func (fc *Firecracker) configureVM(ctx context.Context, hc *http.Client, rec *hy
9599

96100
for i, sc := range rec.StorageConfigs {
97101
driveID := fmt.Sprintf(driveIDFmt, i)
98-
if err := putDrive(ctx, hc, fcDrive{
102+
d := fcDrive{
99103
DriveID: driveID,
100104
PathOnHost: sc.Path,
101105
IsRootDevice: false,
102106
IsReadOnly: sc.RO,
103-
}); err != nil {
107+
}
108+
if !sc.RO {
109+
d.IoEngine = "Async"
110+
}
111+
if err := putDrive(ctx, hc, d); err != nil {
104112
return fmt.Errorf("drive %s: %w", driveID, err)
105113
}
106114
}
@@ -131,6 +139,10 @@ func (fc *Firecracker) configureVM(ctx context.Context, hc *http.Client, rec *hy
131139
}
132140
}
133141

142+
if err := putEntropy(ctx, hc); err != nil {
143+
return fmt.Errorf("entropy: %w", err)
144+
}
145+
134146
if err := instanceStart(ctx, hc); err != nil {
135147
return fmt.Errorf("instance-start: %w", err)
136148
}

0 commit comments

Comments
 (0)