]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/spdk/ocf/src/utils/utils_async_lock.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / ocf / src / utils / utils_async_lock.c
diff --git a/ceph/src/spdk/ocf/src/utils/utils_async_lock.c b/ceph/src/spdk/ocf/src/utils/utils_async_lock.c
new file mode 100644 (file)
index 0000000..2321c28
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright(c) 2019 Intel Corporation
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ */
+
+#include "utils_async_lock.h"
+
+struct ocf_async_lock_waiter {
+       struct list_head list;
+       ocf_async_lock_t lock;
+       bool write_lock;
+       ocf_async_lock_end_t cmpl;
+};
+
+void _ocf_async_lock_collect_waiters(ocf_async_lock_t lock,
+               struct list_head *waiters)
+{
+       ocf_async_lock_waiter_t iter, temp;
+
+       list_for_each_entry_safe(iter, temp, &lock->waiters, list) {
+               if (!iter->write_lock) {
+                       list_move_tail(&iter->list, waiters);
+                       lock->rd++;
+               } else {
+                       if (!lock->rd) {
+                               list_move_tail(&iter->list, waiters);
+                               lock->wr = 1;
+                       }
+                       break;
+               }
+       }
+}
+
+void _ocf_async_lock_run_waiters(struct ocf_async_lock *lock,
+               struct list_head *waiters, int status)
+{
+       ocf_async_lock_waiter_t iter, temp;
+
+       /* TODO: Should we run waiters asynchronously? */
+
+       list_for_each_entry_safe(iter, temp, waiters, list) {
+               list_del(&iter->list);
+               iter->cmpl(iter, status);
+               env_vfree(iter);
+       }
+}
+
+int ocf_async_lock_init(struct ocf_async_lock *lock, uint32_t waiter_priv_size)
+{
+       int err = 0;
+
+       err = env_spinlock_init(&lock->waiters_lock);
+       if (err)
+               return err;
+
+       INIT_LIST_HEAD(&lock->waiters);
+       lock->rd = 0;
+       lock->wr = 0;
+       lock->waiter_priv_size = waiter_priv_size;
+
+       return 0;
+}
+
+void ocf_async_lock_deinit(struct ocf_async_lock *lock)
+{
+       struct list_head waiters;
+       ocf_async_lock_waiter_t iter, temp;
+
+       INIT_LIST_HEAD(&waiters);
+
+       env_spinlock_lock(&lock->waiters_lock);
+       list_for_each_entry_safe(iter, temp, &lock->waiters, list)
+               list_move_tail(&iter->list, &waiters);
+       env_spinlock_unlock(&lock->waiters_lock);
+
+       env_spinlock_destroy(&lock->waiters_lock);
+
+       _ocf_async_lock_run_waiters(lock, &waiters, -OCF_ERR_NO_LOCK);
+}
+
+ocf_async_lock_waiter_t ocf_async_lock_new_waiter(ocf_async_lock_t lock,
+               ocf_async_lock_end_t cmpl)
+{
+       ocf_async_lock_waiter_t waiter;
+
+       waiter = env_vmalloc(sizeof(*waiter) + lock->waiter_priv_size);
+       if (!waiter)
+               return NULL;
+
+       waiter->lock = lock;
+       waiter->cmpl = cmpl;
+
+       return waiter;
+}
+
+ocf_async_lock_t ocf_async_lock_waiter_get_lock(ocf_async_lock_waiter_t waiter)
+{
+       return waiter->lock;
+}
+
+void *ocf_async_lock_waiter_get_priv(ocf_async_lock_waiter_t waiter)
+{
+       return (void *)waiter + sizeof(*waiter);
+}
+
+static int _ocf_async_trylock(struct ocf_async_lock *lock)
+{
+       if (lock->wr || lock->rd)
+               return -OCF_ERR_NO_LOCK;
+
+       lock->wr = 1;
+       return 0;
+}
+
+void ocf_async_lock(ocf_async_lock_waiter_t waiter)
+{
+       ocf_async_lock_t lock = waiter->lock;
+       int result;
+
+       env_spinlock_lock(&lock->waiters_lock);
+
+       result = _ocf_async_trylock(lock);
+       if (!result) {
+               env_spinlock_unlock(&lock->waiters_lock);
+               waiter->cmpl(waiter, 0);
+               env_vfree(waiter);
+               return;
+       }
+
+       waiter->write_lock = true;
+       list_add_tail(&waiter->list, &lock->waiters);
+
+       env_spinlock_unlock(&lock->waiters_lock);
+}
+
+int ocf_async_trylock(struct ocf_async_lock *lock)
+{
+       int result;
+
+       env_spinlock_lock(&lock->waiters_lock);
+       result = _ocf_async_trylock(lock);
+       env_spinlock_unlock(&lock->waiters_lock);
+
+       return result;
+}
+
+void ocf_async_unlock(struct ocf_async_lock *lock)
+{
+       struct list_head waiters;
+
+       INIT_LIST_HEAD(&waiters);
+
+       env_spinlock_lock(&lock->waiters_lock);
+
+       ENV_BUG_ON(lock->rd);
+       ENV_BUG_ON(!lock->wr);
+
+       lock->wr = 0;
+
+       _ocf_async_lock_collect_waiters(lock, &waiters);
+
+       env_spinlock_unlock(&lock->waiters_lock);
+
+       _ocf_async_lock_run_waiters(lock, &waiters, 0);
+}
+
+static int _ocf_async_read_trylock(struct ocf_async_lock *lock)
+{
+       if (lock->wr || !list_empty(&lock->waiters))
+               return -OCF_ERR_NO_LOCK;
+
+       lock->rd++;
+       return 0;
+}
+
+void ocf_async_read_lock(ocf_async_lock_waiter_t waiter)
+{
+       ocf_async_lock_t lock = waiter->lock;
+       int result;
+
+       env_spinlock_lock(&lock->waiters_lock);
+
+       result = _ocf_async_read_trylock(lock);
+       if (!result) {
+               env_spinlock_unlock(&lock->waiters_lock);
+               waiter->cmpl(waiter, 0);
+               env_vfree(waiter);
+               return;
+       }
+
+       waiter->write_lock = false;
+       list_add_tail(&waiter->list, &lock->waiters);
+
+       env_spinlock_unlock(&lock->waiters_lock);
+}
+
+int ocf_async_read_trylock(struct ocf_async_lock *lock)
+{
+       int result;
+
+       env_spinlock_lock(&lock->waiters_lock);
+       result = _ocf_async_read_trylock(lock);
+       env_spinlock_unlock(&lock->waiters_lock);
+
+       return result;
+}
+
+void ocf_async_read_unlock(struct ocf_async_lock *lock)
+{
+       struct list_head waiters;
+
+       INIT_LIST_HEAD(&waiters);
+
+       env_spinlock_lock(&lock->waiters_lock);
+
+       ENV_BUG_ON(!lock->rd);
+       ENV_BUG_ON(lock->wr);
+
+       if (--lock->rd) {
+               env_spinlock_unlock(&lock->waiters_lock);
+               return;
+       }
+
+       _ocf_async_lock_collect_waiters(lock, &waiters);
+
+       env_spinlock_unlock(&lock->waiters_lock);
+
+       _ocf_async_lock_run_waiters(lock, &waiters, 0);
+}
+
+bool ocf_async_is_locked(struct ocf_async_lock *lock)
+{
+       bool locked;
+
+       env_spinlock_lock(&lock->waiters_lock);
+       locked = lock->rd || lock->wr;
+       env_spinlock_unlock(&lock->waiters_lock);
+
+       return locked;
+}