github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/inode/locker.go (about) 1 package inode 2 3 // Lock-related wrappers for inodes 4 // 5 // These APIs wrap calls to package DLM, which is a generic locking package. 6 // 7 // These wrappers enforce a naming convention for lock IDs. 8 // 9 10 import ( 11 "fmt" 12 13 "github.com/swiftstack/ProxyFS/dlm" 14 ) 15 16 // MakeLockID creates the ID of an inode used in volume 17 func (vS *volumeStruct) MakeLockID(inodeNumber InodeNumber) (lockID string, err error) { 18 myLockID := fmt.Sprintf("vol.%s:ino.%d", vS.volumeName, inodeNumber) 19 20 return myLockID, nil 21 } 22 23 // InitInodeLock creates an inode lock. If callerID is non-nil, it is used. 24 // Otherwise a new callerID is allocated. 25 func (vS *volumeStruct) InitInodeLock(inodeNumber InodeNumber, callerID dlm.CallerID) (lock *dlm.RWLockStruct, err error) { 26 lockID, err := vS.MakeLockID(inodeNumber) 27 if err != nil { 28 return nil, err 29 } 30 31 if callerID == nil { 32 callerID = dlm.GenerateCallerID() 33 } 34 35 return &dlm.RWLockStruct{LockID: lockID, 36 Notify: nil, 37 LockCallerID: callerID, 38 }, nil 39 } 40 41 // GetReadLock is a convenience function to create and acquire an inode lock 42 func (vS *volumeStruct) GetReadLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) { 43 lock, err := vS.InitInodeLock(inodeNumber, callerID) 44 if err != nil { 45 return nil, err 46 } 47 48 err = lock.ReadLock() 49 return lock, err 50 } 51 52 // GetWriteLock is a convenience function to create and acquire an inode lock 53 func (vS *volumeStruct) GetWriteLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) { 54 lock, err := vS.InitInodeLock(inodeNumber, callerID) 55 if err != nil { 56 return nil, err 57 } 58 59 err = lock.WriteLock() 60 return lock, err 61 } 62 63 // AttemptReadLock is a convenience function to create and try to acquire an inode lock 64 func (vS *volumeStruct) AttemptReadLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) { 65 lock, err := vS.InitInodeLock(inodeNumber, callerID) 66 if err != nil { 67 return nil, err 68 } 69 70 err = lock.TryReadLock() 71 return lock, err 72 } 73 74 // AttemptWriteLock is a convenience function to create and try to acquire an inode lock 75 func (vS *volumeStruct) AttemptWriteLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) { 76 lock, err := vS.InitInodeLock(inodeNumber, callerID) 77 if err != nil { 78 return nil, err 79 } 80 81 err = lock.TryWriteLock() 82 return lock, err 83 } 84 85 // EnsureReadLock ensures that a lock of the right type is held by the given callerID. If the lock is not held, it 86 // acquires it. If the lock is held, it returns nil (so you don't unlock twice; even if that's not crashworthy, you'd 87 // still release a lock that other code thinks it still holds). 88 func (vS *volumeStruct) EnsureReadLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) { 89 lock, err := vS.InitInodeLock(inodeNumber, callerID) 90 if err != nil { 91 return nil, err 92 } 93 94 if lock.IsReadHeld() { 95 return nil, nil 96 } 97 98 err = lock.ReadLock() 99 return lock, err 100 } 101 102 // EnsureWriteLock ensures that a lock of the right type is held by the given callerID. If the lock is not held, it 103 // acquires it. If the lock is held, it returns nil (so you don't unlock twice; even if that's not crashworthy, you'd 104 // still release a lock that other code thinks it still holds). 105 func (vS *volumeStruct) EnsureWriteLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) { 106 lock, err := vS.InitInodeLock(inodeNumber, callerID) 107 if err != nil { 108 return nil, err 109 } 110 111 if lock.IsWriteHeld() { 112 return nil, nil 113 } 114 115 err = lock.WriteLock() 116 return lock, err 117 }