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