diff options
Diffstat (limited to 'libpod/lock/shm/shm_lock.c')
-rw-r--r-- | libpod/lock/shm/shm_lock.c | 452 |
1 files changed, 0 insertions, 452 deletions
diff --git a/libpod/lock/shm/shm_lock.c b/libpod/lock/shm/shm_lock.c deleted file mode 100644 index 4af58d857..000000000 --- a/libpod/lock/shm/shm_lock.c +++ /dev/null @@ -1,452 +0,0 @@ -#include <errno.h> -#include <fcntl.h> -#include <pthread.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdlib.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "shm_lock.h" - -// Compute the size of the SHM struct -static size_t compute_shm_size(uint32_t num_bitmaps) { - return sizeof(shm_struct_t) + (num_bitmaps * sizeof(lock_group_t)); -} - -// Take the given mutex. -// Handles exceptional conditions, including a mutex locked by a process that -// died holding it. -// Returns 0 on success, or positive errno on failure. -static int take_mutex(pthread_mutex_t *mutex) { - int ret_code; - - do { - ret_code = pthread_mutex_lock(mutex); - } while(ret_code == EAGAIN); - - if (ret_code == EOWNERDEAD) { - // The previous owner of the mutex died while holding it - // Take it for ourselves - ret_code = pthread_mutex_consistent(mutex); - if (ret_code != 0) { - // Someone else may have gotten here first and marked the state consistent - // However, the mutex could also be invalid. - // Fail here instead of looping back to trying to lock the mutex. - return ret_code; - } - } else if (ret_code != 0) { - return ret_code; - } - - return 0; -} - -// Release the given mutex. -// Returns 0 on success, or positive errno on failure. -static int release_mutex(pthread_mutex_t *mutex) { - int ret_code; - - do { - ret_code = pthread_mutex_unlock(mutex); - } while(ret_code == EAGAIN); - - if (ret_code != 0) { - return ret_code; - } - - return 0; -} - -// Set up an SHM segment holding locks for libpod. -// num_locks must not be 0. -// Path is the path to the SHM segment. It must begin with a single / and -// container no other / characters, and be at most 255 characters including -// terminating NULL byte. -// Returns a valid pointer on success or NULL on error. -// If an error occurs, negative ERRNO values will be written to error_code. -shm_struct_t *setup_lock_shm(char *path, uint32_t num_locks, int *error_code) { - int shm_fd, i, j, ret_code; - uint32_t num_bitmaps; - size_t shm_size; - shm_struct_t *shm; - pthread_mutexattr_t attr; - - // If error_code doesn't point to anything, we can't reasonably return errors - // So fail immediately - if (error_code == NULL) { - return NULL; - } - - // We need a nonzero number of locks - if (num_locks == 0) { - *error_code = -1 * EINVAL; - return NULL; - } - - if (path == NULL) { - *error_code = -1 * EINVAL; - return NULL; - } - - // Calculate the number of bitmaps required - num_bitmaps = num_locks / BITMAP_SIZE; - if (num_locks % BITMAP_SIZE != 0) { - // The actual number given is not an even multiple of our bitmap size - // So round up - num_bitmaps += 1; - } - - // Calculate size of the shm segment - shm_size = compute_shm_size(num_bitmaps); - - // Create a new SHM segment for us - shm_fd = shm_open(path, O_RDWR | O_CREAT | O_EXCL, 0600); - if (shm_fd < 0) { - *error_code = -1 * errno; - return NULL; - } - - // Increase its size to what we need - ret_code = ftruncate(shm_fd, shm_size); - if (ret_code < 0) { - *error_code = -1 * errno; - goto CLEANUP_UNLINK; - } - - // Map the shared memory in - shm = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - if (shm == MAP_FAILED) { - *error_code = -1 * errno; - goto CLEANUP_UNLINK; - } - - // We have successfully mapped the memory, now initialize the region - shm->magic = MAGIC; - shm->unused = 0; - shm->num_locks = num_bitmaps * BITMAP_SIZE; - shm->num_bitmaps = num_bitmaps; - - // Create an initializer for our pthread mutexes - ret_code = pthread_mutexattr_init(&attr); - if (ret_code != 0) { - *error_code = -1 * ret_code; - goto CLEANUP_UNMAP; - } - - // Set mutexes to pshared - multiprocess-safe - ret_code = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); - if (ret_code != 0) { - *error_code = -1 * ret_code; - goto CLEANUP_FREEATTR; - } - - // Set mutexes to robust - if a process dies while holding a mutex, we'll get - // a special error code on the next attempt to lock it. - // This should prevent panicing processes from leaving the state unusable. - ret_code = pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST); - if (ret_code != 0) { - *error_code = -1 * ret_code; - goto CLEANUP_FREEATTR; - } - - // Initialize the mutex that protects the bitmaps using the mutex attributes - ret_code = pthread_mutex_init(&(shm->segment_lock), &attr); - if (ret_code != 0) { - *error_code = -1 * ret_code; - goto CLEANUP_FREEATTR; - } - - // Initialize all bitmaps to 0 initially - // And initialize all semaphores they use - for (i = 0; i < num_bitmaps; i++) { - shm->locks[i].bitmap = 0; - for (j = 0; j < BITMAP_SIZE; j++) { - // Initialize each mutex - ret_code = pthread_mutex_init(&(shm->locks[i].locks[j]), &attr); - if (ret_code != 0) { - *error_code = -1 * ret_code; - goto CLEANUP_FREEATTR; - } - } - } - - // Close the file descriptor, we're done with it - // Ignore errors, it's ok if we leak a single FD and this should only run once - close(shm_fd); - - // Destroy the pthread initializer attribute. - // Again, ignore errors, this will only run once and we might leak a tiny bit - // of memory at worst. - pthread_mutexattr_destroy(&attr); - - return shm; - - // Cleanup after an error - CLEANUP_FREEATTR: - pthread_mutexattr_destroy(&attr); - CLEANUP_UNMAP: - munmap(shm, shm_size); - CLEANUP_UNLINK: - close(shm_fd); - shm_unlink(path); - return NULL; -} - -// Open an existing SHM segment holding libpod locks. -// num_locks is the number of locks that will be configured in the SHM segment. -// num_locks cannot be 0. -// Path is the path to the SHM segment. It must begin with a single / and -// container no other / characters, and be at most 255 characters including -// terminating NULL byte. -// Returns a valid pointer on success or NULL on error. -// If an error occurs, negative ERRNO values will be written to error_code. -shm_struct_t *open_lock_shm(char *path, uint32_t num_locks, int *error_code) { - int shm_fd; - shm_struct_t *shm; - size_t shm_size; - uint32_t num_bitmaps; - - if (error_code == NULL) { - return NULL; - } - - // We need a nonzero number of locks - if (num_locks == 0) { - *error_code = -1 * EINVAL; - return NULL; - } - - if (path == NULL) { - *error_code = -1 * EINVAL; - return NULL; - } - - // Calculate the number of bitmaps required - num_bitmaps = num_locks / BITMAP_SIZE; - if (num_locks % BITMAP_SIZE != 0) { - num_bitmaps += 1; - } - - // Calculate size of the shm segment - shm_size = compute_shm_size(num_bitmaps); - - shm_fd = shm_open(path, O_RDWR, 0600); - if (shm_fd < 0) { - *error_code = -1 * errno; - return NULL; - } - - // Map the shared memory in - shm = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - if (shm == MAP_FAILED) { - *error_code = -1 * errno; - } - - // Ignore errors, it's ok if we leak a single FD since this only runs once - close(shm_fd); - - // Check if we successfully mmap'd - if (shm == MAP_FAILED) { - return NULL; - } - - // Need to check the SHM to see if it's actually our locks - if (shm->magic != MAGIC) { - *error_code = -1 * errno; - goto CLEANUP; - } - if (shm->num_locks != (num_bitmaps * BITMAP_SIZE)) { - *error_code = -1 * errno; - goto CLEANUP; - } - - return shm; - - CLEANUP: - munmap(shm, shm_size); - return NULL; -} - -// Close an open SHM lock struct, unmapping the backing memory. -// The given shm_struct_t will be rendered unusable as a result. -// On success, 0 is returned. On failure, negative ERRNO values are returned. -int32_t close_lock_shm(shm_struct_t *shm) { - int ret_code; - size_t shm_size; - - // We can't unmap null... - if (shm == NULL) { - return -1 * EINVAL; - } - - shm_size = compute_shm_size(shm->num_bitmaps); - - ret_code = munmap(shm, shm_size); - - if (ret_code != 0) { - return -1 * errno; - } - - return 0; -} - -// Allocate the first available semaphore -// Returns a positive integer guaranteed to be less than UINT32_MAX on success, -// or negative errno values on failure -// On sucess, the returned integer is the number of the semaphore allocated -int64_t allocate_semaphore(shm_struct_t *shm) { - int ret_code, i; - bitmap_t test_map; - int64_t sem_number, num_within_bitmap; - - if (shm == NULL) { - return -1 * EINVAL; - } - - // Lock the semaphore controlling access to our shared memory - ret_code = take_mutex(&(shm->segment_lock)); - if (ret_code != 0) { - return -1 * ret_code; - } - - // Loop through our bitmaps to search for one that is not full - for (i = 0; i < shm->num_bitmaps; i++) { - if (shm->locks[i].bitmap != 0xFFFFFFFF) { - test_map = 0x1; - num_within_bitmap = 0; - while (test_map != 0) { - if ((test_map & shm->locks[i].bitmap) == 0) { - // Compute the number of the semaphore we are allocating - sem_number = (BITMAP_SIZE * i) + num_within_bitmap; - // OR in the bitmap - shm->locks[i].bitmap = shm->locks[i].bitmap | test_map; - - // Clear the mutex - ret_code = release_mutex(&(shm->segment_lock)); - if (ret_code != 0) { - return -1 * ret_code; - } - - // Return the semaphore we've allocated - return sem_number; - } - test_map = test_map << 1; - num_within_bitmap++; - } - // We should never fall through this loop - // TODO maybe an assert() here to panic if we do? - } - } - - // Clear the mutex - ret_code = release_mutex(&(shm->segment_lock)); - if (ret_code != 0) { - return -1 * ret_code; - } - - // All bitmaps are full - // We have no available semaphores, report allocation failure - return -1 * ENOSPC; -} - -// Deallocate a given semaphore -// Returns 0 on success, negative ERRNO values on failure -int32_t deallocate_semaphore(shm_struct_t *shm, uint32_t sem_index) { - bitmap_t test_map; - int bitmap_index, index_in_bitmap, ret_code, i; - - if (shm == NULL) { - return -1 * EINVAL; - } - - // Check if the lock index is valid - if (sem_index >= shm->num_locks) { - return -1 * EINVAL; - } - - bitmap_index = sem_index / BITMAP_SIZE; - index_in_bitmap = sem_index % BITMAP_SIZE; - - // This should never happen if the sem_index test above succeeded, but better - // safe than sorry - if (bitmap_index >= shm->num_bitmaps) { - return -1 * EFAULT; - } - - test_map = 0x1 << index_in_bitmap; - - // Lock the mutex controlling access to our shared memory - ret_code = take_mutex(&(shm->segment_lock)); - if (ret_code != 0) { - return -1 * ret_code; - } - - // Check if the semaphore is allocated - if ((test_map & shm->locks[bitmap_index].bitmap) == 0) { - ret_code = release_mutex(&(shm->segment_lock)); - if (ret_code != 0) { - return -1 * ret_code; - } - - return -1 * ENOENT; - } - - // The semaphore is allocated, clear it - // Invert the bitmask we used to test to clear the bit - test_map = ~test_map; - shm->locks[bitmap_index].bitmap = shm->locks[bitmap_index].bitmap & test_map; - - ret_code = release_mutex(&(shm->segment_lock)); - if (ret_code != 0) { - return -1 * ret_code; - } - - return 0; -} - -// Lock a given semaphore -// Does not check if the semaphore is allocated - this ensures that, even for -// removed containers, we can still successfully lock to check status (and -// subsequently realize they have been removed). -// Returns 0 on success, -1 on failure -int32_t lock_semaphore(shm_struct_t *shm, uint32_t sem_index) { - int bitmap_index, index_in_bitmap, ret_code; - - if (shm == NULL) { - return -1 * EINVAL; - } - - if (sem_index >= shm->num_locks) { - return -1 * EINVAL; - } - - bitmap_index = sem_index / BITMAP_SIZE; - index_in_bitmap = sem_index % BITMAP_SIZE; - - return -1 * take_mutex(&(shm->locks[bitmap_index].locks[index_in_bitmap])); -} - -// Unlock a given semaphore -// Does not check if the semaphore is allocated - this ensures that, even for -// removed containers, we can still successfully lock to check status (and -// subsequently realize they have been removed). -// Returns 0 on success, -1 on failure -int32_t unlock_semaphore(shm_struct_t *shm, uint32_t sem_index) { - int bitmap_index, index_in_bitmap, ret_code; - - if (shm == NULL) { - return -1 * EINVAL; - } - - if (sem_index >= shm->num_locks) { - return -1 * EINVAL; - } - - bitmap_index = sem_index / BITMAP_SIZE; - index_in_bitmap = sem_index % BITMAP_SIZE; - - return -1 * release_mutex(&(shm->locks[bitmap_index].locks[index_in_bitmap])); -} |