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 }