github.com/swiftstack/ProxyFS@v0.0.0-20210203235616-4017c267d62f/inode/api.go (about)

     1  // Copyright (c) 2015-2021, NVIDIA CORPORATION.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  // Package inode provides inode-management functionality for ProxyFS.
     5  package inode
     6  
     7  import (
     8  	"time"
     9  	"unsafe"
    10  
    11  	"golang.org/x/sys/unix"
    12  
    13  	"github.com/swiftstack/sortedmap"
    14  
    15  	"github.com/swiftstack/ProxyFS/dlm"
    16  	"github.com/swiftstack/ProxyFS/utils"
    17  )
    18  
    19  type InodeNumber uint64
    20  type InodeType uint16
    21  type InodeMode uint32
    22  type InodeUserID uint32
    23  type InodeGroupID uint32
    24  type InodeDirLocation int64
    25  
    26  const (
    27  	InodeRootUserID = InodeUserID(0)
    28  )
    29  
    30  // NOTE: Using unix.DT_* constants for these types makes it easier
    31  //       to expose this information in a standardized way with our RPC APIs.
    32  const (
    33  	DirType     InodeType = unix.DT_DIR
    34  	FileType    InodeType = unix.DT_REG
    35  	SymlinkType InodeType = unix.DT_LNK
    36  )
    37  
    38  // NOTE: Would have liked to use os.FileMode bitmask definitions here instead of creating our own,
    39  //       but unfortunately the bitmasks used by os.ModeDir and os.ModeSymlink (0x80000000 and 0x8000000)
    40  //       are not the same values as what is expected on the linux side (0x4000 and 0xa000).
    41  const (
    42  	PosixModeType    InodeMode = 0xE000
    43  	PosixModeDir     InodeMode = 0x4000
    44  	PosixModeFile    InodeMode = 0x8000
    45  	PosixModeSymlink InodeMode = 0xa000
    46  	PosixModePerm    InodeMode = 0777
    47  )
    48  
    49  // The following are used in calls to Access()... either F_OK or bitwise or of R_OK, W_OK, and X_OK
    50  const (
    51  	F_OK = InodeMode(unix.F_OK)                               //         check for existence
    52  	R_OK = InodeMode(unix.R_OK)                               // UID:GID check for read    permission
    53  	W_OK = InodeMode(unix.W_OK)                               // UID:GID check for write   permission
    54  	X_OK = InodeMode(unix.X_OK)                               // UID:GID check for execute permission
    55  	P_OK = InodeMode((unix.R_OK | unix.W_OK | unix.X_OK) + 1) //         check for ownership permissions
    56  )
    57  
    58  // AccessOverride.Owner means Access() grants permission to the owner of the
    59  // file even if the permission bits disallow it.
    60  type AccessOverride uint32
    61  
    62  const (
    63  	NoOverride AccessOverride = iota
    64  	OwnerOverride
    65  )
    66  
    67  // The following line of code is a directive to go generate that tells it to create a
    68  // file called inodetype_string.go that implements the .String() method for InodeType.
    69  //go:generate stringer -type=InodeType
    70  
    71  type MetadataStruct struct {
    72  	InodeType
    73  	LinkCount            uint64
    74  	Size                 uint64
    75  	CreationTime         time.Time
    76  	ModificationTime     time.Time
    77  	AccessTime           time.Time
    78  	AttrChangeTime       time.Time // aka ctime; This field is intended to be changed by writing or by setting inode information (i.e., owner, group, link count, mode, etc.).
    79  	NumWrites            uint64    // only maintained for FileType inodes
    80  	InodeStreamNameSlice []string
    81  	Mode                 InodeMode
    82  	UserID               InodeUserID
    83  	GroupID              InodeGroupID
    84  }
    85  
    86  type FragmentationReport struct {
    87  	NumberOfFragments uint64 // used with BytesInFragments to compute average fragment size
    88  	BytesInFragments  uint64 // equivalent to size of file for FileInode that is not sparse
    89  	BytesTrapped      uint64 // unreferenced bytes trapped in referenced log segments
    90  }
    91  
    92  type DirEntry struct {
    93  	InodeNumber
    94  	Basename        string
    95  	Type            InodeType
    96  	NextDirLocation InodeDirLocation
    97  }
    98  
    99  type CoalesceElement struct {
   100  	ContainingDirectoryInodeNumber InodeNumber
   101  	ElementInodeNumber             InodeNumber
   102  	ElementName                    string
   103  }
   104  
   105  type ReadPlanStep struct {
   106  	LogSegmentNumber uint64 // If == 0, Length specifies zero-fill size
   107  	Offset           uint64 // If zero-fill case, == 0
   108  	Length           uint64 // Must != 0
   109  	AccountName      string // If == "", Length specifies a zero-fill size
   110  	ContainerName    string // If == "", Length specifies a zero-fill size
   111  	ObjectName       string // If == "", Length specifies a zero-fill size
   112  	ObjectPath       string // If == "", Length specifies a zero-fill size
   113  }
   114  
   115  type ExtentMapEntryStruct struct {
   116  	FileOffset       uint64
   117  	LogSegmentOffset uint64
   118  	Length           uint64
   119  	ContainerName    string // While "read-as-zero" entries in ExtentMapShunkStruct
   120  	ObjectName       string //   are not present, {Container|Object}Name would be == ""
   121  }
   122  
   123  type ExtentMapChunkStruct struct {
   124  	FileOffsetRangeStart uint64                 // Holes in [FileOffsetRangeStart:FileOffsetRangeEnd)
   125  	FileOffsetRangeEnd   uint64                 //   not covered in ExtentMapEntry slice should "read-as-zero"
   126  	FileSize             uint64                 //   up to the end-of-file as indicated by FileSize
   127  	ExtentMapEntry       []ExtentMapEntryStruct // All will be in [FileOffsetRangeStart:FileOffsetRangeEnd)
   128  }
   129  
   130  const (
   131  	RootDirInodeNumber = InodeNumber(1)
   132  )
   133  
   134  const (
   135  	SnapShotDirName = ".snapshot"
   136  )
   137  
   138  type RWModeType uint8
   139  
   140  const (
   141  	RWModeNormal   RWModeType = iota // All reads, writes, etc... should be allowed
   142  	RWModeNoWrite                    // Same as modeNormal except Write() & ProvisionObject() should fail
   143  	RWModeReadOnly                   // No operations that modify state (data or metadata) should be allowed
   144  )
   145  
   146  func (de *DirEntry) Size() int {
   147  	// sizeof(InodeNumber) + sizeof(InodeType) + sizeof(DirLocation) + string data + null byte delimiter
   148  	return int(unsafe.Sizeof(de.InodeNumber)) + int(unsafe.Sizeof(de.Type)) + int(unsafe.Sizeof(de.NextDirLocation)) + len(de.Basename) + 1
   149  }
   150  
   151  // AccountNameToVolumeName returns the corresponding volumeName for the supplied accountName (if any).
   152  func AccountNameToVolumeName(accountName string) (volumeName string, ok bool) {
   153  	volumeName, ok = accountNameToVolumeName(accountName)
   154  	return
   155  }
   156  
   157  // VolumeNameToAccountName returns the corresponding accountName for the supplied volumeName (if any).
   158  func VolumeNameToAccountName(volumeName string) (accountName string, ok bool) {
   159  	accountName, ok = volumeNameToAccountName(volumeName)
   160  	return
   161  }
   162  
   163  // VolumeNameToActivePeerPrivateIPAddr returns the Peer IP Address serving the specified VolumeName.
   164  func VolumeNameToActivePeerPrivateIPAddr(volumeName string) (activePeerPrivateIPAddr string, ok bool) {
   165  	activePeerPrivateIPAddr, ok = volumeNameToActivePeerPrivateIPAddr(volumeName)
   166  	return
   167  }
   168  
   169  // FetchVolumeHandle returns a the VolumeHandle corresponding to the name VolumeName.
   170  //
   171  // Note: The method should be considered a write operation on the RoodDirInodeNumber.
   172  //       As such, an exclusive lock should be held around a call to FetchVolumeHandle().
   173  func FetchVolumeHandle(volumeName string) (volumeHandle VolumeHandle, err error) {
   174  	volumeHandle, err = fetchVolumeHandle(volumeName)
   175  	return
   176  }
   177  
   178  type VolumeHandle interface {
   179  	// Generic methods, implemented volume.go
   180  
   181  	GetFSID() (fsid uint64)
   182  	SnapShotCreate(name string) (id uint64, err error)
   183  	SnapShotDelete(id uint64) (err error)
   184  
   185  	// Wrapper methods around DLM locks.  Implemented in locker.go
   186  
   187  	MakeLockID(inodeNumber InodeNumber) (lockID string, err error)
   188  	InitInodeLock(inodeNumber InodeNumber, callerID dlm.CallerID) (lock *dlm.RWLockStruct, err error)
   189  	GetReadLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error)
   190  	GetWriteLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error)
   191  	AttemptReadLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error)
   192  	AttemptWriteLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error)
   193  	EnsureReadLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error)
   194  	EnsureWriteLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error)
   195  
   196  	// Common Inode methods, implemented in inode.go
   197  
   198  	Access(inodeNumber InodeNumber, userID InodeUserID, groupID InodeGroupID, otherGroupIDs []InodeGroupID, accessMode InodeMode, override AccessOverride) (accessReturn bool)
   199  	Purge(inodeNumber InodeNumber) (err error)
   200  	Destroy(inodeNumber InodeNumber) (err error)
   201  	GetMetadata(inodeNumber InodeNumber) (metadata *MetadataStruct, err error)
   202  	GetType(inodeNumber InodeNumber) (inodeType InodeType, err error)
   203  	GetLinkCount(inodeNumber InodeNumber) (linkCount uint64, err error)
   204  	SetLinkCount(inodeNumber InodeNumber, linkCount uint64) (err error)
   205  	SetCreationTime(inodeNumber InodeNumber, creationTime time.Time) (err error)
   206  	SetModificationTime(inodeNumber InodeNumber, modificationTime time.Time) (err error)
   207  	SetAccessTime(inodeNumber InodeNumber, accessTime time.Time) (err error)
   208  	SetPermMode(inodeNumber InodeNumber, filePerm InodeMode) (err error)
   209  	SetOwnerUserID(inodeNumber InodeNumber, userID InodeUserID) (err error)
   210  	SetOwnerUserIDGroupID(inodeNumber InodeNumber, userID InodeUserID, groupID InodeGroupID) (err error)
   211  	SetOwnerGroupID(inodeNumber InodeNumber, groupID InodeGroupID) (err error)
   212  	GetStream(inodeNumber InodeNumber, inodeStreamName string) (buf []byte, err error)
   213  	PutStream(inodeNumber InodeNumber, inodeStreamName string, buf []byte) (err error)
   214  	DeleteStream(inodeNumber InodeNumber, inodeStreamName string) (err error)
   215  	FetchOnDiskInode(inodeNumber InodeNumber) (corruptionDetected CorruptionDetected, version Version, onDiskInode []byte, err error)
   216  	PatchInode(inodeNumber InodeNumber, inodeType InodeType, linkCount uint64, mode InodeMode, userID InodeUserID, groupID InodeGroupID, parentInodeNumber InodeNumber, symlinkTarget string) (err error)
   217  	FetchLayoutReport(inodeNumber InodeNumber) (layoutReport sortedmap.LayoutReport, err error)
   218  	FetchFragmentationReport(inodeNumber InodeNumber) (fragmentationReport FragmentationReport, err error)
   219  	Optimize(inodeNumber InodeNumber, maxDuration time.Duration) (err error)
   220  	Validate(inodeNumber InodeNumber, deeply bool) (err error)
   221  
   222  	// Directory Inode specific methods, implemented in dir.go
   223  
   224  	CreateDir(filePerm InodeMode, userID InodeUserID, groupID InodeGroupID) (dirInodeNumber InodeNumber, err error)
   225  	Link(dirInodeNumber InodeNumber, basename string, targetInodeNumber InodeNumber, insertOnly bool) (err error)
   226  	Unlink(dirInodeNumber InodeNumber, basename string, removeOnly bool) (toDestroyInodeNumber InodeNumber, err error)
   227  	Move(srcDirInodeNumber InodeNumber, srcBasename string, dstDirInodeNumber InodeNumber, dstBasename string) (toDestroyInodeNumber InodeNumber, err error)
   228  	Lookup(dirInodeNumber InodeNumber, basename string) (targetInodeNumber InodeNumber, err error)
   229  	NumDirEntries(dirInodeNumber InodeNumber) (numEntries uint64, err error)
   230  	ReadDir(dirInodeNumber InodeNumber, maxEntries uint64, maxBufSize uint64, prevReturned ...interface{}) (dirEntrySlice []DirEntry, moreEntries bool, err error)
   231  	AddDirEntry(dirInodeNumber InodeNumber, dirEntryName string, dirEntryInodeNumber InodeNumber, skipDirLinkCountIncrementOnSubDirEntry bool, skipSettingDotDotOnSubDirEntry bool, skipDirEntryLinkCountIncrementOnNonSubDirEntry bool) (err error)
   232  	ReplaceDirEntries(parentDirInodeNumber InodeNumber, parentDirEntryBasename string, dirInodeNumber InodeNumber, dirEntryInodeNumbers []InodeNumber) (err error)
   233  
   234  	// File Inode specific methods, implemented in file.go
   235  
   236  	CreateFile(filePerm InodeMode, userID InodeUserID, groupID InodeGroupID) (fileInodeNumber InodeNumber, err error)
   237  	Read(inodeNumber InodeNumber, offset uint64, length uint64, profiler *utils.Profiler) (buf []byte, err error)
   238  	GetReadPlan(fileInodeNumber InodeNumber, offset *uint64, length *uint64) (readPlan []ReadPlanStep, err error)
   239  	FetchExtentMapChunk(fileInodeNumber InodeNumber, fileOffset uint64, maxEntriesFromFileOffset int64, maxEntriesBeforeFileOffset int64) (extentMapChunk *ExtentMapChunkStruct, err error)
   240  	Write(fileInodeNumber InodeNumber, offset uint64, buf []byte, profiler *utils.Profiler) (err error)
   241  	ProvisionObject() (objectPath string, err error)
   242  	Wrote(fileInodeNumber InodeNumber, containerName string, objectName string, fileOffset []uint64, objectOffset []uint64, length []uint64, wroteTime time.Time, patchOnly bool) (err error)
   243  	SetSize(fileInodeNumber InodeNumber, Size uint64) (err error)
   244  	Flush(fileInodeNumber InodeNumber, andPurge bool) (err error)
   245  	Coalesce(destInodeNumber InodeNumber, metaDataName string, metaData []byte, elements []*CoalesceElement) (attrChangeTime time.Time, modificationTime time.Time, numWrites uint64, fileSize uint64, err error)
   246  	DefragmentFile(fileInodeNumber InodeNumber, startingFileOffset uint64, chunkSize uint64) (nextFileOffset uint64, eofReached bool, err error)
   247  
   248  	// Symlink Inode specific methods, implemented in symlink.go
   249  
   250  	CreateSymlink(target string, filePerm InodeMode, userID InodeUserID, groupID InodeGroupID) (symlinkInodeNumber InodeNumber, err error)
   251  	GetSymlink(symlinkInodeNumber InodeNumber) (target string, err error)
   252  }
   253  
   254  // SetRWMode sets the package to either allow all read/write operations (RWModeNormal),
   255  // allow all except Write() and ProvisionObject() operations (RWModeNoWrite), or
   256  // disallow any data or metadata operations (RWModeReadOnly).
   257  func SetRWMode(rwMode RWModeType) (err error) {
   258  	err = setRWMode(rwMode)
   259  	return
   260  }