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 /* BEGIN CSTYLED */ 120 #define rw_init(rwp, name, type, arg) \ 121 ({ \ 122 static struct lock_class_key __key; \ 123 ASSERT(type == RW_DEFAULT || type == RW_NOLOCKDEP); \ 124 \ 125 __init_rwsem(SEM(rwp), #rwp, &__key); \ 126 spl_rw_clear_owner(rwp); \ 127 spl_rw_set_type(rwp, type); \ 128 }) 129 130 /* 131 * The Linux rwsem implementation does not require a matching destroy. 132 */ 133 #define rw_destroy(rwp) ((void) 0) 134 135 /* 136 * Upgrading a rwsem from a reader to a writer is not supported by the 137 * Linux kernel. The lock must be dropped and reacquired as a writer. 138 */ 139 #define rw_tryupgrade(rwp) RW_WRITE_HELD(rwp) 140 141 #define rw_tryenter(rwp, rw) \ 142 ({ \ 143 int _rc_ = 0; \ 144 \ 145 spl_rw_lockdep_off_maybe(rwp); \ 146 switch (rw) { \ 147 case RW_READER: \ 148 _rc_ = down_read_trylock(SEM(rwp)); \ 149 break; \ 150 case RW_WRITER: \ 151 if ((_rc_ = down_write_trylock(SEM(rwp)))) \ 152 spl_rw_set_owner(rwp); \ 153 break; \ 154 default: \ 155 VERIFY(0); \ 156 } \ 157 spl_rw_lockdep_on_maybe(rwp); \ 158 _rc_; \ 159 }) 160 161 #define rw_enter(rwp, rw) \ 162 ({ \ 163 spl_rw_lockdep_off_maybe(rwp); \ 164 switch (rw) { \ 165 case RW_READER: \ 166 down_read(SEM(rwp)); \ 167 break; \ 168 case RW_WRITER: \ 169 down_write(SEM(rwp)); \ 170 spl_rw_set_owner(rwp); \ 171 break; \ 172 default: \ 173 VERIFY(0); \ 174 } \ 175 spl_rw_lockdep_on_maybe(rwp); \ 176 }) 177 178 #define rw_exit(rwp) \ 179 ({ \ 180 spl_rw_lockdep_off_maybe(rwp); \ 181 if (RW_WRITE_HELD(rwp)) { \ 182 spl_rw_clear_owner(rwp); \ 183 up_write(SEM(rwp)); \ 184 } else { \ 185 ASSERT(RW_READ_HELD(rwp)); \ 186 up_read(SEM(rwp)); \ 187 } \ 188 spl_rw_lockdep_on_maybe(rwp); \ 189 }) 190 191 #define rw_downgrade(rwp) \ 192 ({ \ 193 spl_rw_lockdep_off_maybe(rwp); \ 194 spl_rw_clear_owner(rwp); \ 195 downgrade_write(SEM(rwp)); \ 196 spl_rw_lockdep_on_maybe(rwp); \ 197 }) 198 /* END CSTYLED */ 199 200 #endif /* _SPL_RWLOCK_H */ 201