// ForceUnlock - forcefully unlock a lock based on name. func (n *nsLockMap) ForceUnlock(volume, path string) { n.lockMapMutex.Lock() defer n.lockMapMutex.Unlock() // Clarification on operation: // - In case of FS or XL we call ForceUnlock on the local nsMutex // (since there is only a single server) which will cause the 'stuck' // mutex to be removed from the map. Existing operations for this // will continue to be blocked (and timeout). New operations on this // resource will use a new mutex and proceed normally. // // - In case of Distributed setup (using dsync), there is no need to call // ForceUnlock on the server where the lock was acquired and is presumably // 'stuck'. Instead dsync.ForceUnlock() will release the underlying locks // that participated in granting the lock. Any pending dsync locks that // are blocking can now proceed as normal and any new locks will also // participate normally. if n.isDist { // For distributed mode, broadcast ForceUnlock message. dsync.NewDRWMutex(pathutil.Join(volume, path)).ForceUnlock() } param := nsParam{volume, path} if _, found := n.lockMap[param]; found { // Remove lock from the map. delete(n.lockMap, param) // delete the lock state entry for given // <volume, path> pair. err := n.deleteLockInfoEntryForVolumePath(param) if err != nil { errorIf(err, "Failed to delete lock info entry") } } }
// Lock the namespace resource. func (n *nsLockMap) lock(volume, path string, lockOrigin, opsID string, readLock bool) { var nsLk *nsLock n.lockMapMutex.Lock() param := nsParam{volume, path} nsLk, found := n.lockMap[param] if !found { nsLk = &nsLock{ RWLocker: func() RWLocker { if n.isDist { return dsync.NewDRWMutex(pathutil.Join(volume, path)) } return &sync.RWMutex{} }(), ref: 0, } n.lockMap[param] = nsLk } nsLk.ref++ // Update ref count here to avoid multiple races. if globalDebugLock { // change the state of the lock to be blocked for the given pair of <volume, path> and <OperationID> till the lock unblocks. // The lock for accessing `nsMutex` is held inside the function itself. err := n.statusNoneToBlocked(param, lockOrigin, opsID, readLock) if err != nil { errorIf(err, "Failed to set lock state to blocked.") } } // Unlock map before Locking NS which might block. n.lockMapMutex.Unlock() // Locking here can block. if readLock { nsLk.RLock() } else { nsLk.Lock() } // check if lock debugging enabled. if globalDebugLock { // Changing the status of the operation from blocked to running. // change the state of the lock to be running (from blocked) for the given pair of <volume, path> and <OperationID>. err := n.statusBlockedToRunning(param, lockOrigin, opsID, readLock) if err != nil { errorIf(err, "Failed to set the lock state to running.") } } }