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  }