mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-21 21:18:54 +00:00
virtcontainers: Implement function to get the pmem DeviceInfo
Implement function to get the pmem `DeviceInfo` from a volume. `PmemDeviceInfo` return a new `DeviceInfo` object if a volume has a loop device as backend and the backing file for such loop device contains the PFN signature, needed to enable DAX in the guest. Signed-off-by: Julio Montes <julio.montes@intel.com>
This commit is contained in:
parent
9ff44dba87
commit
ee941e5c56
@ -113,6 +113,10 @@ type DeviceInfo struct {
|
||||
Major int64
|
||||
Minor int64
|
||||
|
||||
// Pmem enabled persistent memory. Use HostPath as backing file
|
||||
// for a nvdimm device in the guest.
|
||||
Pmem bool
|
||||
|
||||
// FileMode permission bits for the device.
|
||||
FileMode os.FileMode
|
||||
|
||||
@ -169,6 +173,10 @@ type BlockDrive struct {
|
||||
|
||||
// ReadOnly sets the device file readonly
|
||||
ReadOnly bool
|
||||
|
||||
// Pmem enables persistent memory. Use File as backing file
|
||||
// for a nvdimm device in the guest
|
||||
Pmem bool
|
||||
}
|
||||
|
||||
// VFIODeviceType indicates VFIO device type
|
||||
|
116
virtcontainers/device/config/pmem.go
Normal file
116
virtcontainers/device/config/pmem.go
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/kata-containers/runtime/virtcontainers/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
// This signature is defined in the linux NVDIMM driver.
|
||||
// devices or backing files with this signature can be used
|
||||
// as pmem (persistent memory) devices in the guest.
|
||||
pfnSignature = "NVDIMM_PFN_INFO"
|
||||
|
||||
// offset in the backing file where the signature should be
|
||||
pfnSignatureOffset = int64(4 * 1024)
|
||||
)
|
||||
|
||||
var (
|
||||
pmemLog = logrus.WithField("source", "virtcontainers/device/config")
|
||||
)
|
||||
|
||||
// PmemDeviceInfo returns a DeviceInfo if a loop device
|
||||
// is mounted on source, and the backing file of the loop device
|
||||
// has the PFN signature.
|
||||
func PmemDeviceInfo(source, destination string) (*DeviceInfo, error) {
|
||||
stat := syscall.Stat_t{}
|
||||
err := syscall.Stat(source, &stat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// device object is still incomplete,
|
||||
// but it can be used to fetch the backing file
|
||||
device := &DeviceInfo{
|
||||
ContainerPath: destination,
|
||||
DevType: "b",
|
||||
Major: int64(unix.Major(stat.Dev)),
|
||||
Minor: int64(unix.Minor(stat.Dev)),
|
||||
Pmem: true,
|
||||
DriverOptions: make(map[string]string),
|
||||
}
|
||||
|
||||
pmemLog.WithFields(
|
||||
logrus.Fields{
|
||||
"major": device.Major,
|
||||
"minor": device.Minor,
|
||||
}).Debug("looking for backing file")
|
||||
|
||||
device.HostPath, err = getBackingFile(*device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pmemLog.WithField("backing-file", device.HostPath).
|
||||
Debug("backing file found: looking for PFN signature")
|
||||
|
||||
if !hasPFNSignature(device.HostPath) {
|
||||
return nil, fmt.Errorf("backing file %v has not PFN signature", device.HostPath)
|
||||
}
|
||||
|
||||
_, fstype, err := utils.GetDevicePathAndFsType(source)
|
||||
if err != nil {
|
||||
pmemLog.WithError(err).WithField("mount-point", source).Warn("failed to get fstype: using ext4")
|
||||
fstype = "ext4"
|
||||
}
|
||||
|
||||
pmemLog.WithField("fstype", fstype).Debug("filesystem for mount point")
|
||||
device.DriverOptions["fstype"] = fstype
|
||||
|
||||
return device, nil
|
||||
}
|
||||
|
||||
// returns true if the file/device path has the PFN signature
|
||||
// required to use it as PMEM device and enable DAX.
|
||||
// See [1] to know more about the PFN signature.
|
||||
//
|
||||
// [1] - https://github.com/kata-containers/osbuilder/blob/master/image-builder/nsdax.gpl.c
|
||||
func hasPFNSignature(path string) bool {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
pmemLog.WithError(err).Error("Could not get PFN signature")
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
signatureLen := len(pfnSignature)
|
||||
signature := make([]byte, signatureLen)
|
||||
|
||||
l, err := f.ReadAt(signature, pfnSignatureOffset)
|
||||
if err != nil {
|
||||
pmemLog.WithError(err).Debug("Could not read pfn signature")
|
||||
return false
|
||||
}
|
||||
|
||||
pmemLog.WithFields(logrus.Fields{
|
||||
"path": path,
|
||||
"signature": string(signature),
|
||||
}).Debug("got signature")
|
||||
|
||||
if l != signatureLen {
|
||||
pmemLog.WithField("read-bytes", l).Debug("Incomplete signature")
|
||||
return false
|
||||
}
|
||||
|
||||
return pfnSignature == string(signature)
|
||||
}
|
49
virtcontainers/device/config/pmem_test.go
Normal file
49
virtcontainers/device/config/pmem_test.go
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func createPFNFile(assert *assert.Assertions, dir string) string {
|
||||
pfnPath := filepath.Join(dir, "pfn")
|
||||
file, err := os.Create(pfnPath)
|
||||
assert.NoError(err)
|
||||
defer file.Close()
|
||||
|
||||
l, err := file.WriteAt([]byte(pfnSignature), pfnSignatureOffset)
|
||||
assert.NoError(err)
|
||||
assert.Equal(len(pfnSignature), l)
|
||||
|
||||
return pfnPath
|
||||
}
|
||||
|
||||
func TestHasPFNSignature(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
b := hasPFNSignature("/abc/xyz/123/sw")
|
||||
assert.False(b)
|
||||
|
||||
f, err := ioutil.TempFile("", "pfn")
|
||||
assert.NoError(err)
|
||||
f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
b = hasPFNSignature(f.Name())
|
||||
assert.False(b)
|
||||
|
||||
pfnFile := createPFNFile(assert, os.TempDir())
|
||||
defer os.Remove(pfnFile)
|
||||
|
||||
b = hasPFNSignature(pfnFile)
|
||||
assert.True(b)
|
||||
}
|
Loading…
Reference in New Issue
Block a user