gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/device/config/pmem.go (about) 1 // Copyright (c) 2020 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package config 7 8 import ( 9 "fmt" 10 "os" 11 "syscall" 12 13 "github.com/kata-containers/runtime/virtcontainers/utils" 14 "github.com/sirupsen/logrus" 15 "golang.org/x/sys/unix" 16 ) 17 18 const ( 19 // This signature is defined in the linux NVDIMM driver. 20 // devices or backing files with this signature can be used 21 // as pmem (persistent memory) devices in the guest. 22 pfnSignature = "NVDIMM_PFN_INFO" 23 24 // offset in the backing file where the signature should be 25 pfnSignatureOffset = int64(4 * 1024) 26 ) 27 28 var ( 29 pmemLog = logrus.WithField("source", "virtcontainers/device/config") 30 ) 31 32 // SetLogger sets up a logger for this pkg 33 func SetLogger(logger *logrus.Entry) { 34 fields := pmemLog.Data 35 36 pmemLog = logger.WithFields(fields) 37 } 38 39 // PmemDeviceInfo returns a DeviceInfo if a loop device 40 // is mounted on source, and the backing file of the loop device 41 // has the PFN signature. 42 func PmemDeviceInfo(source, destination string) (*DeviceInfo, error) { 43 stat := syscall.Stat_t{} 44 err := syscall.Stat(source, &stat) 45 if err != nil { 46 return nil, err 47 } 48 49 // device object is still incomplete, 50 // but it can be used to fetch the backing file 51 device := &DeviceInfo{ 52 ContainerPath: destination, 53 DevType: "b", 54 Major: int64(unix.Major(stat.Dev)), 55 Minor: int64(unix.Minor(stat.Dev)), 56 Pmem: true, 57 DriverOptions: make(map[string]string), 58 } 59 60 pmemLog.WithFields( 61 logrus.Fields{ 62 "major": device.Major, 63 "minor": device.Minor, 64 }).Debug("looking for backing file") 65 66 device.HostPath, err = getBackingFile(*device) 67 if err != nil { 68 return nil, err 69 } 70 71 pmemLog.WithField("backing-file", device.HostPath). 72 Debug("backing file found: looking for PFN signature") 73 74 if !hasPFNSignature(device.HostPath) { 75 return nil, fmt.Errorf("backing file %v has not PFN signature", device.HostPath) 76 } 77 78 _, fstype, err := utils.GetDevicePathAndFsType(source) 79 if err != nil { 80 pmemLog.WithError(err).WithField("mount-point", source).Warn("failed to get fstype: using ext4") 81 fstype = "ext4" 82 } 83 84 pmemLog.WithField("fstype", fstype).Debug("filesystem for mount point") 85 device.DriverOptions["fstype"] = fstype 86 87 return device, nil 88 } 89 90 // returns true if the file/device path has the PFN signature 91 // required to use it as PMEM device and enable DAX. 92 // See [1] to know more about the PFN signature. 93 // 94 // [1] - https://github.com/kata-containers/osbuilder/blob/master/image-builder/nsdax.gpl.c 95 func hasPFNSignature(path string) bool { 96 f, err := os.Open(path) 97 if err != nil { 98 pmemLog.WithError(err).Error("Could not get PFN signature") 99 return false 100 } 101 defer f.Close() 102 103 signatureLen := len(pfnSignature) 104 signature := make([]byte, signatureLen) 105 106 l, err := f.ReadAt(signature, pfnSignatureOffset) 107 if err != nil { 108 pmemLog.WithError(err).Debug("Could not read pfn signature") 109 return false 110 } 111 112 pmemLog.WithFields(logrus.Fields{ 113 "path": path, 114 "signature": string(signature), 115 }).Debug("got signature") 116 117 if l != signatureLen { 118 pmemLog.WithField("read-bytes", l).Debug("Incomplete signature") 119 return false 120 } 121 122 return pfnSignature == string(signature) 123 }