Path: blob/main/sys/compat/linuxkpi/common/src/linux_lock.c
39586 views
/*-1* Copyright (c) 2017 Mellanox Technologies, Ltd.2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice unmodified, this list of conditions, and the following9* disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR15* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES16* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.17* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,18* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT19* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,20* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY21* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT22* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF23* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.24*/2526#include <sys/queue.h>2728#include <linux/sched.h>29#include <linux/ww_mutex.h>3031struct ww_mutex_thread {32TAILQ_ENTRY(ww_mutex_thread) entry;33struct thread *thread;34struct ww_mutex *lock;35};3637static TAILQ_HEAD(, ww_mutex_thread) ww_mutex_head;38static struct mtx ww_mutex_global;3940static void41linux_ww_init(void *arg)42{43TAILQ_INIT(&ww_mutex_head);44mtx_init(&ww_mutex_global, "lkpi-ww-mtx", NULL, MTX_DEF);45}4647SYSINIT(ww_init, SI_SUB_LOCK, SI_ORDER_SECOND, linux_ww_init, NULL);4849static void50linux_ww_uninit(void *arg)51{52mtx_destroy(&ww_mutex_global);53}5455SYSUNINIT(ww_uninit, SI_SUB_LOCK, SI_ORDER_SECOND, linux_ww_uninit, NULL);5657static inline void58linux_ww_lock(void)59{60mtx_lock(&ww_mutex_global);61}6263static inline void64linux_ww_unlock(void)65{66mtx_unlock(&ww_mutex_global);67}6869/* lock a mutex with deadlock avoidance */70int71linux_ww_mutex_lock_sub(struct ww_mutex *lock,72struct ww_acquire_ctx *ctx, int catch_signal)73{74struct task_struct *task;75struct ww_mutex_thread entry;76struct ww_mutex_thread *other;77int retval = 0;7879task = current;8081linux_ww_lock();82if (unlikely(sx_try_xlock(&lock->base.sx) == 0)) {83entry.thread = curthread;84entry.lock = lock;85TAILQ_INSERT_TAIL(&ww_mutex_head, &entry, entry);8687do {88struct thread *owner = (struct thread *)89SX_OWNER(lock->base.sx.sx_lock);9091/* scan for deadlock */92TAILQ_FOREACH(other, &ww_mutex_head, entry) {93/* skip own thread */94if (other == &entry)95continue;96/*97* If another thread is owning our98* lock and is at the same time trying99* to acquire a lock this thread owns,100* that means deadlock.101*/102if (other->thread == owner &&103(struct thread *)SX_OWNER(104other->lock->base.sx.sx_lock) == curthread) {105retval = -EDEADLK;106goto done;107}108}109if (catch_signal) {110retval = -cv_wait_sig(&lock->condvar, &ww_mutex_global);111if (retval != 0) {112linux_schedule_save_interrupt_value(task, retval);113retval = -EINTR;114goto done;115}116} else {117cv_wait(&lock->condvar, &ww_mutex_global);118}119} while (sx_try_xlock(&lock->base.sx) == 0);120done:121TAILQ_REMOVE(&ww_mutex_head, &entry, entry);122123/* if the lock is free, wakeup next lock waiter, if any */124if ((struct thread *)SX_OWNER(lock->base.sx.sx_lock) == NULL)125cv_signal(&lock->condvar);126}127128if (retval == 0)129lock->ctx = ctx;130linux_ww_unlock();131return (retval);132}133134void135linux_ww_mutex_unlock_sub(struct ww_mutex *lock)136{137/* protect ww_mutex ownership change */138linux_ww_lock();139lock->ctx = NULL;140sx_xunlock(&lock->base.sx);141/* wakeup a lock waiter, if any */142cv_signal(&lock->condvar);143linux_ww_unlock();144}145146int147linux_mutex_lock_interruptible(mutex_t *m)148{149int error;150151error = -sx_xlock_sig(&m->sx);152if (error != 0) {153linux_schedule_save_interrupt_value(current, error);154error = -EINTR;155}156return (error);157}158159int160linux_down_read_killable(struct rw_semaphore *rw)161{162int error;163164error = -sx_slock_sig(&rw->sx);165if (error != 0) {166linux_schedule_save_interrupt_value(current, error);167error = -EINTR;168}169return (error);170}171172int173linux_down_write_killable(struct rw_semaphore *rw)174{175int error;176177error = -sx_xlock_sig(&rw->sx);178if (error != 0) {179linux_schedule_save_interrupt_value(current, error);180error = -EINTR;181}182return (error);183}184185186