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  }