zfs/include/os/freebsd/spl/sys/rwlock.h

93 lines
3.1 KiB
C
Raw Normal View History

/*
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _OPENSOLARIS_SYS_RWLOCK_H_
#define _OPENSOLARIS_SYS_RWLOCK_H_
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/sx.h>
typedef enum {
RW_DEFAULT = 4 /* kernel default rwlock */
} krw_type_t;
typedef enum {
RW_NONE = 0,
RW_WRITER = 1,
RW_READER = 2
} krw_t;
typedef struct sx krwlock_t;
#ifndef OPENSOLARIS_WITNESS
spl: Don't check FreeBSD rwlocks for double initialization (#13019) This checking breaks KMSAN since it effectively loads from uninitialized memory to see if the lock is already initialized. This happens in dnode_cons() for example. This checking is not very useful, partly due to UMA's memory trashing, and is already disabled for mutexes. Make mutexes and rwlocks consistent: remove double-initialization checking for rwlocks, and pass SX_NEW to disable the same checking in lock_init(). No functional change intended, this affects only debug builds. As a side note, kmem cache constructors/destructors are implemented suboptimally on FreeBSD. FreeBSD's slab allocator, UMA, supports two pairs of constructors/destructors: ctor/dtor and init/fini. The former are called upon every allocation and free of an item, while the latter are called when an item is imported or released from a zone, respectively. That is, when a slab is allocated to a particular cache, it is subdivided into items, and init is called on each. fini is called when the slab is being prepared to be freed back to the system. The intent is for them to initialize static fields such as locks, which do not need to be initialized upon each allocation of an item. In illumos, kmem_cache constructors/destructors correspond to UMA's init/fini callbacks. However, in the SPL they are implemented as UMA ctor/dtors, meaning that they get called far more often than necessary. This may be difficult to fix, since new code may assume the kmem cache ctor/dtors are in fact called upon each allocation/free, and there doesn't seem to be a clear way to implement the intended semantics on Linux. Reviewed-by: Ryan Moeller <ryan@iXsystems.com> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Signed-off-by: Mark Johnston <markj@FreeBSD.org> Closes #13019
2022-01-31 18:58:45 +00:00
#define RW_FLAGS (SX_DUPOK | SX_NEW | SX_NOWITNESS)
#else
spl: Don't check FreeBSD rwlocks for double initialization (#13019) This checking breaks KMSAN since it effectively loads from uninitialized memory to see if the lock is already initialized. This happens in dnode_cons() for example. This checking is not very useful, partly due to UMA's memory trashing, and is already disabled for mutexes. Make mutexes and rwlocks consistent: remove double-initialization checking for rwlocks, and pass SX_NEW to disable the same checking in lock_init(). No functional change intended, this affects only debug builds. As a side note, kmem cache constructors/destructors are implemented suboptimally on FreeBSD. FreeBSD's slab allocator, UMA, supports two pairs of constructors/destructors: ctor/dtor and init/fini. The former are called upon every allocation and free of an item, while the latter are called when an item is imported or released from a zone, respectively. That is, when a slab is allocated to a particular cache, it is subdivided into items, and init is called on each. fini is called when the slab is being prepared to be freed back to the system. The intent is for them to initialize static fields such as locks, which do not need to be initialized upon each allocation of an item. In illumos, kmem_cache constructors/destructors correspond to UMA's init/fini callbacks. However, in the SPL they are implemented as UMA ctor/dtors, meaning that they get called far more often than necessary. This may be difficult to fix, since new code may assume the kmem cache ctor/dtors are in fact called upon each allocation/free, and there doesn't seem to be a clear way to implement the intended semantics on Linux. Reviewed-by: Ryan Moeller <ryan@iXsystems.com> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Signed-off-by: Mark Johnston <markj@FreeBSD.org> Closes #13019
2022-01-31 18:58:45 +00:00
#define RW_FLAGS (SX_DUPOK | SX_NEW)
#endif
#define RW_READ_HELD(x) (rw_read_held((x)))
#define RW_WRITE_HELD(x) (rw_write_held((x)))
#define RW_LOCK_HELD(x) (rw_lock_held((x)))
#define RW_ISWRITER(x) (rw_iswriter(x))
#define rw_init(lock, desc, type, arg) do { \
const char *_name; \
ASSERT((type) == 0 || (type) == RW_DEFAULT); \
for (_name = #lock; *_name != '\0'; _name++) { \
if (*_name >= 'a' && *_name <= 'z') \
break; \
} \
if (*_name == '\0') \
_name = #lock; \
sx_init_flags((lock), _name, RW_FLAGS); \
} while (0)
#define rw_destroy(lock) sx_destroy(lock)
#define rw_enter(lock, how) do { \
if ((how) == RW_READER) \
sx_slock(lock); \
else /* if ((how) == RW_WRITER) */ \
sx_xlock(lock); \
} while (0)
#define rw_tryenter(lock, how) \
((how) == RW_READER ? sx_try_slock(lock) : sx_try_xlock(lock))
#define rw_exit(lock) sx_unlock(lock)
#define rw_downgrade(lock) sx_downgrade(lock)
#define rw_tryupgrade(lock) sx_try_upgrade(lock)
#define rw_read_held(lock) \
((lock)->sx_lock != SX_LOCK_UNLOCKED && \
((lock)->sx_lock & SX_LOCK_SHARED))
#define rw_write_held(lock) sx_xlocked(lock)
#define rw_lock_held(lock) (rw_read_held(lock) || rw_write_held(lock))
#define rw_iswriter(lock) sx_xlocked(lock)
#define rw_owner(lock) sx_xholder(lock)
#endif /* _OPENSOLARIS_SYS_RWLOCK_H_ */