diff options
Diffstat (limited to 'drivers/md/dm-vdo/sparse-cache.c')
| -rw-r--r-- | drivers/md/dm-vdo/sparse-cache.c | 69 |
1 files changed, 68 insertions, 1 deletions
diff --git a/drivers/md/dm-vdo/sparse-cache.c b/drivers/md/dm-vdo/sparse-cache.c index 5b41c94f53fa..dcd5ef25b360 100644 --- a/drivers/md/dm-vdo/sparse-cache.c +++ b/drivers/md/dm-vdo/sparse-cache.c @@ -6,6 +6,7 @@ #include "sparse-cache.h" #include <linux/cache.h> +#include <linux/delay.h> #include <linux/dm-bufio.h> #include "chapter-index.h" @@ -14,7 +15,6 @@ #include "logger.h" #include "memory-alloc.h" #include "permassert.h" -#include "uds-threads.h" /* * Since the cache is small, it is implemented as a simple array of cache entries. Searching for a @@ -141,6 +141,17 @@ struct search_list { struct cached_chapter_index *entries[]; }; +struct barrier { + /* Lock for this barrier object */ + struct semaphore lock; + /* Semaphore for threads waiting at this barrier */ + struct semaphore wait; + /* Number of threads which have arrived */ + int arrived; + /* Total number of threads using this barrier */ + int thread_count; +}; + struct sparse_cache { const struct index_geometry *geometry; unsigned int capacity; @@ -156,6 +167,62 @@ struct sparse_cache { struct cached_chapter_index chapters[]; }; +static int uds_initialize_barrier(struct barrier *barrier, unsigned int thread_count) +{ + sema_init(&barrier->lock, 1); + barrier->arrived = 0; + barrier->thread_count = thread_count; + sema_init(&barrier->wait, 0); + + return UDS_SUCCESS; +} + +static int uds_destroy_barrier(struct barrier *barrier) +{ + return UDS_SUCCESS; +} + +static inline void __down(struct semaphore *semaphore) +{ + /* + * Do not use down(semaphore). Instead use down_interruptible so that + * we do not get 120 second stall messages in kern.log. + */ + while (down_interruptible(semaphore) != 0) { + /* + * If we're called from a user-mode process (e.g., "dmsetup + * remove") while waiting for an operation that may take a + * while (e.g., UDS index save), and a signal is sent (SIGINT, + * SIGUSR2), then down_interruptible will not block. If that + * happens, sleep briefly to avoid keeping the CPU locked up in + * this loop. We could just call cond_resched, but then we'd + * still keep consuming CPU time slices and swamp other threads + * trying to do computational work. [VDO-4980] + */ + fsleep(1000); + } +} + +static int uds_enter_barrier(struct barrier *barrier) +{ + __down(&barrier->lock); + if (++barrier->arrived == barrier->thread_count) { + /* last thread */ + int i; + + for (i = 1; i < barrier->thread_count; i++) + up(&barrier->wait); + + barrier->arrived = 0; + up(&barrier->lock); + } else { + up(&barrier->lock); + __down(&barrier->wait); + } + + return UDS_SUCCESS; +} + static int __must_check initialize_cached_chapter_index(struct cached_chapter_index *chapter, const struct index_geometry *geometry) { |
