podman/libpod/lock/lock.go
Matthew Heon faae3a7065 When refreshing after a reboot, force lock allocation
After a reboot, when we refresh Podman's state, we retrieved the
lock from the fresh SHM instance, but we did not mark it as
allocated to prevent it being handed out to other containers and
pods.

Provide a method for marking locks as in-use, and use it when we
refresh Podman state after a reboot.

Fixes #2900

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
2019-05-06 14:17:54 -04:00

83 lines
3.9 KiB
Go

package lock
// Manager provides an interface for allocating multiprocess locks.
// Locks returned by Manager MUST be multiprocess - allocating a lock in
// process A and retrieving that lock's ID in process B must return handles for
// the same lock, and locking the lock in A should exclude B from the lock until
// it is unlocked in A.
// All locks must be identified by a UUID (retrieved with Locker's ID() method).
// All locks with a given UUID must refer to the same underlying lock, and it
// must be possible to retrieve the lock given its UUID.
// Each UUID should refer to a unique underlying lock.
// Calls to AllocateLock() must return a unique, unallocated UUID.
// AllocateLock() must fail once all available locks have been allocated.
// Locks are returned to use by calls to Free(), and can subsequently be
// reallocated.
type Manager interface {
// AllocateLock returns an unallocated lock.
// It is guaranteed that the same lock will not be returned again by
// AllocateLock until the returned lock has Free() called on it.
// If all available locks are allocated, AllocateLock will return an
// error.
AllocateLock() (Locker, error)
// RetrieveLock retrieves a lock given its UUID.
// The underlying lock MUST be the same as another other lock with the
// same UUID.
RetrieveLock(id uint32) (Locker, error)
// AllocateAndRetrieveLock marks the lock with the given UUID as in use
// and retrieves it.
// RetrieveAndAllocateLock will error if the lock in question has
// already been allocated.
// This is mostly used after a system restart to repopulate the list of
// locks in use.
AllocateAndRetrieveLock(id uint32) (Locker, error)
// PLEASE READ FULL DESCRIPTION BEFORE USING.
// FreeAllLocks frees all allocated locks, in preparation for lock
// reallocation.
// As this deallocates all presently-held locks, this can be very
// dangerous - if there are other processes running that might be
// attempting to allocate new locks and free existing locks, we may
// encounter races leading to an inconsistent state.
// (This is in addition to the fact that FreeAllLocks instantly makes
// the state inconsistent simply by using it, and requires a full
// lock renumbering to restore consistency!).
// In short, this should only be used as part of unit tests, or lock
// renumbering, where reasonable guarantees about other processes can be
// made.
FreeAllLocks() error
}
// Locker is similar to sync.Locker, but provides a method for freeing the lock
// to allow its reuse.
// All Locker implementations must maintain mutex semantics - the lock only
// allows one caller in the critical section at a time.
// All locks with the same ID must refer to the same underlying lock, even
// if they are within multiple processes.
type Locker interface {
// ID retrieves the lock's ID.
// ID is guaranteed to uniquely identify the lock within the
// Manager - that is, calling RetrieveLock with this ID will return
// another instance of the same lock.
ID() uint32
// Lock locks the lock.
// This call MUST block until it successfully acquires the lock or
// encounters a fatal error.
// All errors must be handled internally, as they are not returned. For
// the most part, panicking should be appropriate.
// Some lock implementations may require that Lock() and Unlock() occur
// within the same goroutine (SHM locking, for example). The usual Go
// Lock()/defer Unlock() pattern will still work fine in these cases.
Lock()
// Unlock unlocks the lock.
// All errors must be handled internally, as they are not returned. For
// the most part, panicking should be appropriate.
// This includes unlocking locks which are already unlocked.
Unlock()
// Free deallocates the underlying lock, allowing its reuse by other
// pods and containers.
// The lock MUST still be usable after a Free() - some libpod instances
// may still retain Container structs with the old lock. This simply
// advises the manager that the lock may be reallocated.
Free() error
}