github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/inode/api.go (about)

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