1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 27 * All rights reserved. 28 */ 29 30 /* 31 * A homegrown reader/writer lock implementation. It addresses 32 * two requirements not addressed by the system primitives. They 33 * are that the `enter" operation is optionally interruptible and 34 * that that they can be re`enter'ed by writers without deadlock. 35 * 36 * All of this was borrowed from NFS. 37 * See: uts/common/fs/nfs/nfs_subr.c 38 * 39 * XXX: Could we make this serve our needs instead? 40 * See: uts/common/os/rwstlock.c 41 * (and then use it for NFS too) 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/errno.h> 47 #include <sys/time.h> 48 #include <sys/vnode.h> 49 50 #include <smbfs/smbfs.h> 51 #include <smbfs/smbfs_node.h> 52 #include <smbfs/smbfs_subr.h> 53 54 55 /* 56 * Only can return non-zero if intr != 0. 57 */ 58 int 59 smbfs_rw_enter_sig(smbfs_rwlock_t *l, krw_t rw, int intr) 60 { 61 62 mutex_enter(&l->lock); 63 64 /* 65 * If this is a nested enter, then allow it. There 66 * must be as many exits as enters through. 67 */ 68 if (l->owner == curthread) { 69 /* lock is held for writing by current thread */ 70 ASSERT(rw == RW_READER || rw == RW_WRITER); 71 l->count--; 72 } else if (rw == RW_READER) { 73 /* 74 * While there is a writer active or writers waiting, 75 * then wait for them to finish up and move on. Then, 76 * increment the count to indicate that a reader is 77 * active. 78 */ 79 while (l->count < 0 || l->waiters > 0) { 80 if (intr) { 81 // lwp_nostop stuff... 82 (void) cv_wait_sig(&l->cv, &l->lock); 83 } else 84 cv_wait(&l->cv, &l->lock); 85 } 86 ASSERT(l->count < INT_MAX); 87 #ifdef SMBDEBUG 88 if ((l->count % 10000) == 9999) 89 cmn_err(CE_WARN, "smbfs_rw_enter_sig: count %d on" 90 "rwlock @ %p\n", l->count, (void *)&l); 91 #endif 92 l->count++; 93 } else { 94 ASSERT(rw == RW_WRITER); 95 /* 96 * While there are readers active or a writer 97 * active, then wait for all of the readers 98 * to finish or for the writer to finish. 99 * Then, set the owner field to curthread and 100 * decrement count to indicate that a writer 101 * is active. 102 */ 103 while (l->count > 0 || l->owner != NULL) { 104 l->waiters++; 105 if (intr) { 106 // lwp_nostop stuff... 107 if (!cv_wait_sig(&l->cv, &l->lock)) { 108 l->waiters--; 109 cv_broadcast(&l->cv); 110 mutex_exit(&l->lock); 111 return (EINTR); 112 } 113 } else 114 cv_wait(&l->cv, &l->lock); 115 l->waiters--; 116 } 117 l->owner = curthread; 118 l->count--; 119 } 120 121 mutex_exit(&l->lock); 122 123 return (0); 124 } 125 126 /* 127 * If the lock is available, obtain it and return non-zero. If there is 128 * already a conflicting lock, return 0 immediately. 129 */ 130 131 int 132 smbfs_rw_tryenter(smbfs_rwlock_t *l, krw_t rw) 133 { 134 mutex_enter(&l->lock); 135 136 /* 137 * If this is a nested enter, then allow it. There 138 * must be as many exits as enters through. 139 */ 140 if (l->owner == curthread) { 141 /* lock is held for writing by current thread */ 142 ASSERT(rw == RW_READER || rw == RW_WRITER); 143 l->count--; 144 } else if (rw == RW_READER) { 145 /* 146 * If there is a writer active or writers waiting, deny the 147 * lock. Otherwise, bump the count of readers. 148 */ 149 if (l->count < 0 || l->waiters > 0) { 150 mutex_exit(&l->lock); 151 return (0); 152 } 153 l->count++; 154 } else { 155 ASSERT(rw == RW_WRITER); 156 /* 157 * If there are readers active or a writer active, deny the 158 * lock. Otherwise, set the owner field to curthread and 159 * decrement count to indicate that a writer is active. 160 */ 161 if (l->count > 0 || l->owner != NULL) { 162 mutex_exit(&l->lock); 163 return (0); 164 } 165 l->owner = curthread; 166 l->count--; 167 } 168 169 mutex_exit(&l->lock); 170 171 return (1); 172 } 173 174 void 175 smbfs_rw_exit(smbfs_rwlock_t *l) 176 { 177 178 mutex_enter(&l->lock); 179 /* 180 * If this is releasing a writer lock, then increment count to 181 * indicate that there is one less writer active. If this was 182 * the last of possibly nested writer locks, then clear the owner 183 * field as well to indicate that there is no writer active 184 * and wakeup any possible waiting writers or readers. 185 * 186 * If releasing a reader lock, then just decrement count to 187 * indicate that there is one less reader active. If this was 188 * the last active reader and there are writer(s) waiting, 189 * then wake up the first. 190 */ 191 if (l->owner != NULL) { 192 ASSERT(l->owner == curthread); 193 l->count++; 194 if (l->count == 0) { 195 l->owner = NULL; 196 cv_broadcast(&l->cv); 197 } 198 } else { 199 ASSERT(l->count > 0); 200 l->count--; 201 if (l->count == 0 && l->waiters > 0) 202 cv_broadcast(&l->cv); 203 } 204 mutex_exit(&l->lock); 205 } 206 207 int 208 smbfs_rw_lock_held(smbfs_rwlock_t *l, krw_t rw) 209 { 210 211 if (rw == RW_READER) 212 return (l->count > 0); 213 ASSERT(rw == RW_WRITER); 214 return (l->count < 0); 215 } 216 217 /* ARGSUSED */ 218 void 219 smbfs_rw_init(smbfs_rwlock_t *l, char *name, krw_type_t type, void *arg) 220 { 221 222 l->count = 0; 223 l->waiters = 0; 224 l->owner = NULL; 225 mutex_init(&l->lock, NULL, MUTEX_DEFAULT, NULL); 226 cv_init(&l->cv, NULL, CV_DEFAULT, NULL); 227 } 228 229 void 230 smbfs_rw_destroy(smbfs_rwlock_t *l) 231 { 232 233 mutex_destroy(&l->lock); 234 cv_destroy(&l->cv); 235 } 236