1 /* 2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC. 3 * Copyright (C) 2007 The Regents of the University of California. 4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). 5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>. 6 * UCRL-CODE-235197 7 * 8 * This file is part of the SPL, Solaris Porting Layer. 9 * 10 * The SPL is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 * The SPL is distributed in the hope that it will be useful, but WITHOUT 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 * for more details. 19 * 20 * You should have received a copy of the GNU General Public License along 21 * with the SPL. If not, see <http://www.gnu.org/licenses/>. 22 */ 23 24 #ifndef _SPL_RWLOCK_H 25 #define _SPL_RWLOCK_H 26 27 #include <sys/types.h> 28 #include <linux/rwsem.h> 29 #include <linux/sched.h> 30 31 typedef enum { 32 RW_DRIVER = 2, 33 RW_DEFAULT = 4, 34 RW_NOLOCKDEP = 5 35 } krw_type_t; 36 37 typedef enum { 38 RW_NONE = 0, 39 RW_WRITER = 1, 40 RW_READER = 2 41 } krw_t; 42 43 typedef struct { 44 struct rw_semaphore rw_rwlock; 45 kthread_t *rw_owner; 46 #ifdef CONFIG_LOCKDEP 47 krw_type_t rw_type; 48 #endif /* CONFIG_LOCKDEP */ 49 } krwlock_t; 50 51 #define SEM(rwp) (&(rwp)->rw_rwlock) 52 53 static inline void 54 spl_rw_set_owner(krwlock_t *rwp) 55 { 56 rwp->rw_owner = current; 57 } 58 59 static inline void 60 spl_rw_clear_owner(krwlock_t *rwp) 61 { 62 rwp->rw_owner = NULL; 63 } 64 65 static inline kthread_t * 66 rw_owner(krwlock_t *rwp) 67 { 68 return (rwp->rw_owner); 69 } 70 71 #ifdef CONFIG_LOCKDEP 72 static inline void 73 spl_rw_set_type(krwlock_t *rwp, krw_type_t type) 74 { 75 rwp->rw_type = type; 76 } 77 static inline void 78 spl_rw_lockdep_off_maybe(krwlock_t *rwp) \ 79 { \ 80 if (rwp && rwp->rw_type == RW_NOLOCKDEP) \ 81 lockdep_off(); \ 82 } 83 static inline void 84 spl_rw_lockdep_on_maybe(krwlock_t *rwp) \ 85 { \ 86 if (rwp && rwp->rw_type == RW_NOLOCKDEP) \ 87 lockdep_on(); \ 88 } 89 #else /* CONFIG_LOCKDEP */ 90 #define spl_rw_set_type(rwp, type) 91 #define spl_rw_lockdep_off_maybe(rwp) 92 #define spl_rw_lockdep_on_maybe(rwp) 93 #endif /* CONFIG_LOCKDEP */ 94 95 static inline int 96 RW_LOCK_HELD(krwlock_t *rwp) 97 { 98 return (rwsem_is_locked(SEM(rwp))); 99 } 100 101 static inline int 102 RW_WRITE_HELD(krwlock_t *rwp) 103 { 104 return (rw_owner(rwp) == current); 105 } 106 107 static inline int 108 RW_READ_HELD(krwlock_t *rwp) 109 { 110 return (RW_LOCK_HELD(rwp) && rw_owner(rwp) == NULL); 111 } 112 113 /* 114 * The following functions must be a #define and not static inline. 115 * This ensures that the native linux semaphore functions (down/up) 116 * will be correctly located in the users code which is important 117 * for the built in kernel lock analysis tools 118 */ 119 #define rw_init(rwp, name, type, arg) /* CSTYLED */ \ 120 ({ \ 121 static struct lock_class_key __key; \ 122 ASSERT(type == RW_DEFAULT || type == RW_NOLOCKDEP); \ 123 \ 124 __init_rwsem(SEM(rwp), #rwp, &__key); \ 125 spl_rw_clear_owner(rwp); \ 126 spl_rw_set_type(rwp, type); \ 127 }) 128 129 /* 130 * The Linux rwsem implementation does not require a matching destroy. 131 */ 132 #define rw_destroy(rwp) ((void) 0) 133 134 /* 135 * Upgrading a rwsem from a reader to a writer is not supported by the 136 * Linux kernel. The lock must be dropped and reacquired as a writer. 137 */ 138 #define rw_tryupgrade(rwp) RW_WRITE_HELD(rwp) 139 140 #define rw_tryenter(rwp, rw) /* CSTYLED */ \ 141 ({ \ 142 int _rc_ = 0; \ 143 \ 144 spl_rw_lockdep_off_maybe(rwp); \ 145 switch (rw) { \ 146 case RW_READER: \ 147 _rc_ = down_read_trylock(SEM(rwp)); \ 148 break; \ 149 case RW_WRITER: \ 150 if ((_rc_ = down_write_trylock(SEM(rwp)))) \ 151 spl_rw_set_owner(rwp); \ 152 break; \ 153 default: \ 154 VERIFY(0); \ 155 } \ 156 spl_rw_lockdep_on_maybe(rwp); \ 157 _rc_; \ 158 }) 159 160 #define rw_enter(rwp, rw) /* CSTYLED */ \ 161 ({ \ 162 spl_rw_lockdep_off_maybe(rwp); \ 163 switch (rw) { \ 164 case RW_READER: \ 165 down_read(SEM(rwp)); \ 166 break; \ 167 case RW_WRITER: \ 168 down_write(SEM(rwp)); \ 169 spl_rw_set_owner(rwp); \ 170 break; \ 171 default: \ 172 VERIFY(0); \ 173 } \ 174 spl_rw_lockdep_on_maybe(rwp); \ 175 }) 176 177 #define rw_exit(rwp) /* CSTYLED */ \ 178 ({ \ 179 spl_rw_lockdep_off_maybe(rwp); \ 180 if (RW_WRITE_HELD(rwp)) { \ 181 spl_rw_clear_owner(rwp); \ 182 up_write(SEM(rwp)); \ 183 } else { \ 184 ASSERT(RW_READ_HELD(rwp)); \ 185 up_read(SEM(rwp)); \ 186 } \ 187 spl_rw_lockdep_on_maybe(rwp); \ 188 }) 189 190 #define rw_downgrade(rwp) /* CSTYLED */ \ 191 ({ \ 192 spl_rw_lockdep_off_maybe(rwp); \ 193 spl_rw_clear_owner(rwp); \ 194 downgrade_write(SEM(rwp)); \ 195 spl_rw_lockdep_on_maybe(rwp); \ 196 }) 197 198 #endif /* _SPL_RWLOCK_H */ 199