18d59ecb2SHans Petter Selasky /*-
28d59ecb2SHans Petter Selasky * Copyright (c) 2010 Isilon Systems, Inc.
38d59ecb2SHans Petter Selasky * Copyright (c) 2010 iX Systems, Inc.
48d59ecb2SHans Petter Selasky * Copyright (c) 2010 Panasas, Inc.
54f688d19SHans Petter Selasky * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
68d59ecb2SHans Petter Selasky * All rights reserved.
78d59ecb2SHans Petter Selasky *
88d59ecb2SHans Petter Selasky * Redistribution and use in source and binary forms, with or without
98d59ecb2SHans Petter Selasky * modification, are permitted provided that the following conditions
108d59ecb2SHans Petter Selasky * are met:
118d59ecb2SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright
128d59ecb2SHans Petter Selasky * notice unmodified, this list of conditions, and the following
138d59ecb2SHans Petter Selasky * disclaimer.
148d59ecb2SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright
158d59ecb2SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the
168d59ecb2SHans Petter Selasky * documentation and/or other materials provided with the distribution.
178d59ecb2SHans Petter Selasky *
188d59ecb2SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
198d59ecb2SHans Petter Selasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
208d59ecb2SHans Petter Selasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
218d59ecb2SHans Petter Selasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
228d59ecb2SHans Petter Selasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
238d59ecb2SHans Petter Selasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
248d59ecb2SHans Petter Selasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
258d59ecb2SHans Petter Selasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
268d59ecb2SHans Petter Selasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
278d59ecb2SHans Petter Selasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288d59ecb2SHans Petter Selasky */
29307f78f3SVladimir Kondratyev #ifndef _LINUXKPI_LINUX_MUTEX_H_
30307f78f3SVladimir Kondratyev #define _LINUXKPI_LINUX_MUTEX_H_
318d59ecb2SHans Petter Selasky
328d59ecb2SHans Petter Selasky #include <sys/param.h>
334f688d19SHans Petter Selasky #include <sys/proc.h>
348d59ecb2SHans Petter Selasky #include <sys/lock.h>
358d59ecb2SHans Petter Selasky #include <sys/sx.h>
368d59ecb2SHans Petter Selasky
3742bb5861SJean-Sébastien Pédron #include <linux/kernel.h>
38*059136a9SBjoern A. Zeeb #include <linux/cleanup.h>
3942bb5861SJean-Sébastien Pédron #include <linux/list.h>
408d59ecb2SHans Petter Selasky #include <linux/spinlock.h>
417708d3d7SEmmanuel Vadot #include <asm/atomic.h>
428d59ecb2SHans Petter Selasky
438d59ecb2SHans Petter Selasky typedef struct mutex {
448d59ecb2SHans Petter Selasky struct sx sx;
458d59ecb2SHans Petter Selasky } mutex_t;
468d59ecb2SHans Petter Selasky
474f688d19SHans Petter Selasky /*
484f688d19SHans Petter Selasky * By defining CONFIG_NO_MUTEX_SKIP LinuxKPI mutexes and asserts will
494f688d19SHans Petter Selasky * not be skipped during panic().
504f688d19SHans Petter Selasky */
514f688d19SHans Petter Selasky #ifdef CONFIG_NO_MUTEX_SKIP
524f688d19SHans Petter Selasky #define MUTEX_SKIP(void) 0
534f688d19SHans Petter Selasky #else
544f688d19SHans Petter Selasky #define MUTEX_SKIP(void) unlikely(SCHEDULER_STOPPED() || kdb_active)
554f688d19SHans Petter Selasky #endif
564f688d19SHans Petter Selasky
574f688d19SHans Petter Selasky #define mutex_lock(_m) do { \
584f688d19SHans Petter Selasky if (MUTEX_SKIP()) \
594f688d19SHans Petter Selasky break; \
604f688d19SHans Petter Selasky sx_xlock(&(_m)->sx); \
614f688d19SHans Petter Selasky } while (0)
624f688d19SHans Petter Selasky
638d59ecb2SHans Petter Selasky #define mutex_lock_nested(_m, _s) mutex_lock(_m)
644f688d19SHans Petter Selasky #define mutex_lock_nest_lock(_m, _s) mutex_lock(_m)
654f688d19SHans Petter Selasky
664f688d19SHans Petter Selasky #define mutex_lock_interruptible(_m) ({ \
674f688d19SHans Petter Selasky MUTEX_SKIP() ? 0 : \
6894944062SHans Petter Selasky linux_mutex_lock_interruptible(_m); \
694f688d19SHans Petter Selasky })
704f688d19SHans Petter Selasky
712d946b2eSEmmanuel Vadot #define mutex_lock_interruptible_nested(m, c) mutex_lock_interruptible(m)
722d946b2eSEmmanuel Vadot
731bbbe083SHans Petter Selasky /*
741bbbe083SHans Petter Selasky * Reuse the interruptable method since the SX
751bbbe083SHans Petter Selasky * lock handles both signals and interrupts:
761bbbe083SHans Petter Selasky */
771bbbe083SHans Petter Selasky #define mutex_lock_killable(_m) ({ \
781bbbe083SHans Petter Selasky MUTEX_SKIP() ? 0 : \
791bbbe083SHans Petter Selasky linux_mutex_lock_interruptible(_m); \
801bbbe083SHans Petter Selasky })
811bbbe083SHans Petter Selasky
821bbbe083SHans Petter Selasky #define mutex_lock_killable_nested(_m, _sub) \
831bbbe083SHans Petter Selasky mutex_lock_killable(_m)
841bbbe083SHans Petter Selasky
854f688d19SHans Petter Selasky #define mutex_unlock(_m) do { \
864f688d19SHans Petter Selasky if (MUTEX_SKIP()) \
874f688d19SHans Petter Selasky break; \
884f688d19SHans Petter Selasky sx_xunlock(&(_m)->sx); \
894f688d19SHans Petter Selasky } while (0)
904f688d19SHans Petter Selasky
914f688d19SHans Petter Selasky #define mutex_trylock(_m) ({ \
924f688d19SHans Petter Selasky MUTEX_SKIP() ? 1 : \
934f688d19SHans Petter Selasky !!sx_try_xlock(&(_m)->sx); \
944f688d19SHans Petter Selasky })
954f688d19SHans Petter Selasky
96f4824a02SHans Petter Selasky enum mutex_trylock_recursive_enum {
97f4824a02SHans Petter Selasky MUTEX_TRYLOCK_FAILED = 0,
98f4824a02SHans Petter Selasky MUTEX_TRYLOCK_SUCCESS = 1,
99f4824a02SHans Petter Selasky MUTEX_TRYLOCK_RECURSIVE = 2,
100f4824a02SHans Petter Selasky };
101f4824a02SHans Petter Selasky
102f4824a02SHans Petter Selasky static inline __must_check enum mutex_trylock_recursive_enum
mutex_trylock_recursive(struct mutex * lock)103f4824a02SHans Petter Selasky mutex_trylock_recursive(struct mutex *lock)
104f4824a02SHans Petter Selasky {
105f4824a02SHans Petter Selasky if (unlikely(sx_xholder(&lock->sx) == curthread))
106f4824a02SHans Petter Selasky return (MUTEX_TRYLOCK_RECURSIVE);
107f4824a02SHans Petter Selasky
108f4824a02SHans Petter Selasky return (mutex_trylock(lock));
109f4824a02SHans Petter Selasky }
110f4824a02SHans Petter Selasky
1114f688d19SHans Petter Selasky #define mutex_init(_m) \
1124f688d19SHans Petter Selasky linux_mutex_init(_m, mutex_name(#_m), SX_NOWITNESS)
1134f688d19SHans Petter Selasky
114d003cc43SEmmanuel Vadot #define __mutex_init(_m, _n, _l) \
115d003cc43SEmmanuel Vadot linux_mutex_init(_m, _n, SX_NOWITNESS)
116d003cc43SEmmanuel Vadot
1174f688d19SHans Petter Selasky #define mutex_init_witness(_m) \
1184f688d19SHans Petter Selasky linux_mutex_init(_m, mutex_name(#_m), SX_DUPOK)
1194f688d19SHans Petter Selasky
1204f688d19SHans Petter Selasky #define mutex_destroy(_m) \
1214f688d19SHans Petter Selasky linux_mutex_destroy(_m)
1224f688d19SHans Petter Selasky
1234f688d19SHans Petter Selasky static inline bool
mutex_is_locked(mutex_t * m)1244f688d19SHans Petter Selasky mutex_is_locked(mutex_t *m)
1254f688d19SHans Petter Selasky {
1264f688d19SHans Petter Selasky return ((struct thread *)SX_OWNER(m->sx.sx_lock) != NULL);
1274f688d19SHans Petter Selasky }
1284f688d19SHans Petter Selasky
1294f688d19SHans Petter Selasky static inline bool
mutex_is_owned(mutex_t * m)1304f688d19SHans Petter Selasky mutex_is_owned(mutex_t *m)
1314f688d19SHans Petter Selasky {
1324f688d19SHans Petter Selasky return (sx_xlocked(&m->sx));
1334f688d19SHans Petter Selasky }
1344f688d19SHans Petter Selasky
atomic_dec_and_mutex_lock(atomic_t * cnt,struct mutex * m)1357708d3d7SEmmanuel Vadot static inline int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *m)
1367708d3d7SEmmanuel Vadot {
1377708d3d7SEmmanuel Vadot if (atomic_dec_and_test(cnt)) {
1387708d3d7SEmmanuel Vadot mutex_lock(m);
1397708d3d7SEmmanuel Vadot return (1);
1407708d3d7SEmmanuel Vadot }
1417708d3d7SEmmanuel Vadot
1427708d3d7SEmmanuel Vadot return (0);
1437708d3d7SEmmanuel Vadot }
1447708d3d7SEmmanuel Vadot
1454f688d19SHans Petter Selasky #ifdef WITNESS_ALL
1464f688d19SHans Petter Selasky /* NOTE: the maximum WITNESS name is 64 chars */
1474f688d19SHans Petter Selasky #define __mutex_name(name, file, line) \
1484f688d19SHans Petter Selasky (((const char *){file ":" #line "-" name}) + \
1494f688d19SHans Petter Selasky (sizeof(file) > 16 ? sizeof(file) - 16 : 0))
1504f688d19SHans Petter Selasky #else
1514f688d19SHans Petter Selasky #define __mutex_name(name, file, line) name
1524f688d19SHans Petter Selasky #endif
1534f688d19SHans Petter Selasky #define _mutex_name(...) __mutex_name(__VA_ARGS__)
1544f688d19SHans Petter Selasky #define mutex_name(name) _mutex_name(name, __FILE__, __LINE__)
1558d59ecb2SHans Petter Selasky
1568d59ecb2SHans Petter Selasky #define DEFINE_MUTEX(lock) \
1578d59ecb2SHans Petter Selasky mutex_t lock; \
1584f688d19SHans Petter Selasky SX_SYSINIT_FLAGS(lock, &(lock).sx, mutex_name(#lock), SX_DUPOK)
1598d59ecb2SHans Petter Selasky
1608d59ecb2SHans Petter Selasky static inline void
linux_mutex_init(mutex_t * m,const char * name,int flags)1614f688d19SHans Petter Selasky linux_mutex_init(mutex_t *m, const char *name, int flags)
1628d59ecb2SHans Petter Selasky {
1634f688d19SHans Petter Selasky memset(m, 0, sizeof(*m));
1644f688d19SHans Petter Selasky sx_init_flags(&m->sx, name, flags);
1658d59ecb2SHans Petter Selasky }
1668d59ecb2SHans Petter Selasky
1674f688d19SHans Petter Selasky static inline void
linux_mutex_destroy(mutex_t * m)1684f688d19SHans Petter Selasky linux_mutex_destroy(mutex_t *m)
1694f688d19SHans Petter Selasky {
1704f688d19SHans Petter Selasky if (mutex_is_owned(m))
1714f688d19SHans Petter Selasky mutex_unlock(m);
1724f688d19SHans Petter Selasky sx_destroy(&m->sx);
1734f688d19SHans Petter Selasky }
1748d59ecb2SHans Petter Selasky
17594944062SHans Petter Selasky extern int linux_mutex_lock_interruptible(mutex_t *m);
17694944062SHans Petter Selasky
177307f78f3SVladimir Kondratyev #endif /* _LINUXKPI_LINUX_MUTEX_H_ */
178