[lxc-devel] [lxd/master] VM: Switch to unsafe async I/O mode on ZFS backed disk files
tomponline on Github
lxc-bot at linuxcontainers.org
Wed Jan 22 11:03:35 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 669 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200122/6165461d/attachment.bin>
-------------- next part --------------
From 5d30eaf34ad46fbc93dd8723582de37bbb545976 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 22 Jan 2020 11:00:35 +0000
Subject: [PATCH] lxd/instance/drivers/driver/qemu: Switch to unsafe async I/O
mode on ZFS backed disk files
Detects if the storage root disk is running on a ZFS pool backed by a loop file or if the attached disk is a file stored on a ZFS partition.
In both cases we attached the disk to qemu using unsafe async I/O mode that disables flushing to avoid kernel hangs and qemu direct I/O errors with ZFS pre 0.8.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/instance/drivers/driver_qemu.go | 47 ++++++++++++++++++++++++++---
1 file changed, 42 insertions(+), 5 deletions(-)
diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index 0639b907b2..9d7bdc1424 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -52,6 +52,9 @@ import (
"github.com/lxc/lxd/shared/units"
)
+// qemuAsyncIO is used to indicate disk should use async I/O.
+const qemuAsyncIO = "asyncio"
+
var errQemuAgentOffline = fmt.Errorf("LXD VM agent isn't currently running")
var vmConsole = map[int]bool{}
@@ -1512,12 +1515,44 @@ func (vm *qemu) addRootDriveConfig(sb *strings.Builder, bootIndexes map[string]i
DevPath: rootDrivePath,
}
+ // If the storage pool is on ZFS and backed by a loop file then indicate to qemu we need to use asyncio.
+ // We use async I/O to avoid kernel hangs and qemu direct I/O errors with pre ZFS 0.8.
+ if pool.Driver().Info().Name == "zfs" && !shared.IsBlockdevPath(pool.Driver().Config()["source"]) {
+ driveConf.Opts = append(driveConf.Opts, qemuAsyncIO)
+ }
+
return vm.addDriveConfig(sb, bootIndexes, driveConf)
}
// addDriveConfig adds the qemu config required for adding a supplementary drive.
func (vm *qemu) addDriveConfig(sb *strings.Builder, bootIndexes map[string]int, driveConf deviceConfig.MountEntryItem) error {
- devName := fmt.Sprintf(driveConf.DevName)
+ asyncIOMode := false
+ backingFile := driveConf.DevPath
+
+ // If drive config indicates we need to use async I/O then enable it.
+ if shared.StringInSlice(qemuAsyncIO, driveConf.Opts) {
+ asyncIOMode = true
+ } else if !shared.IsBlockdevPath(backingFile) {
+ fsType, err := util.FilesystemDetect(backingFile)
+ if err != nil {
+ return errors.Wrapf(err, "Failed detecting filesystem type of %q", backingFile)
+ }
+
+ if fsType == "zfs" {
+ // Use async I/O to avoid kernel hangs and qemu direct I/O errors with pre ZFS 0.8.
+ asyncIOMode = true
+ }
+ }
+
+ // Use direct I/O by default.
+ cacheMode := "none"
+ aioMode := "native"
+
+ if asyncIOMode {
+ logger.Warnf("Using async I/O with %s", driveConf.DevPath)
+ cacheMode = "unsafe"
+ aioMode = "threads"
+ }
// Devices use "lxd_" prefix indicating that this is a user named device.
t := template.Must(template.New("").Parse(`
@@ -1526,8 +1561,8 @@ func (vm *qemu) addDriveConfig(sb *strings.Builder, bootIndexes map[string]int,
file = "{{.devPath}}"
format = "raw"
if = "none"
-cache = "none"
-aio = "native"
+cache = "{{.cacheMode}}"
+aio = "{{.aioMode}}"
[device "dev-lxd_{{.devName}}"]
driver = "scsi-hd"
@@ -1540,9 +1575,11 @@ bootindex = "{{.bootIndex}}"
`))
m := map[string]interface{}{
- "devName": devName,
+ "devName": driveConf.DevName,
"devPath": driveConf.DevPath,
- "bootIndex": bootIndexes[devName],
+ "bootIndex": bootIndexes[driveConf.DevName],
+ "cacheMode": cacheMode,
+ "aioMode": aioMode,
}
return t.Execute(sb, m)
}
More information about the lxc-devel
mailing list