rf_stripelocks.c revision 1.6
1/* $NetBSD: rf_stripelocks.c,v 1.6 2000/12/04 11:35:46 fvdl Exp $ */ 2/* 3 * Copyright (c) 1995 Carnegie-Mellon University. 4 * All rights reserved. 5 * 6 * Authors: Mark Holland, Jim Zelenka 7 * 8 * Permission to use, copy, modify and distribute this software and 9 * its documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 16 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 */ 28 29/* 30 * stripelocks.c -- code to lock stripes for read and write access 31 * 32 * The code distinguishes between read locks and write locks. There can be 33 * as many readers to given stripe as desired. When a write request comes 34 * in, no further readers are allowed to enter, and all subsequent requests 35 * are queued in FIFO order. When a the number of readers goes to zero, the 36 * writer is given the lock. When a writer releases the lock, the list of 37 * queued requests is scanned, and all readersq up to the next writer are 38 * given the lock. 39 * 40 * The lock table size must be one less than a power of two, but HASH_STRIPEID 41 * is the only function that requires this. 42 * 43 * The code now supports "range locks". When you ask to lock a stripe, you 44 * specify a range of addresses in that stripe that you want to lock. When 45 * you acquire the lock, you've locked only this range of addresses, and 46 * other threads can concurrently read/write any non-overlapping portions 47 * of the stripe. The "addresses" that you lock are abstract in that you 48 * can pass in anything you like. The expectation is that you'll pass in 49 * the range of physical disk offsets of the parity bits you're planning 50 * to update. The idea behind this, of course, is to allow sub-stripe 51 * locking. The implementation is perhaps not the best imaginable; in the 52 * worst case a lock release is O(n^2) in the total number of outstanding 53 * requests to a given stripe. Note that if you're striping with a 54 * stripe unit size equal to an entire disk (i.e. not striping), there will 55 * be only one stripe and you may spend some significant number of cycles 56 * searching through stripe lock descriptors. 57 */ 58 59#include "rf_types.h" 60#include "rf_raid.h" 61#include "rf_stripelocks.h" 62#include "rf_alloclist.h" 63#include "rf_general.h" 64#include "rf_freelist.h" 65#include "rf_debugprint.h" 66#include "rf_driver.h" 67#include "rf_shutdown.h" 68 69#define Dprintf1(s,a) rf_debug_printf(s,(void *)((unsigned long)a),NULL,NULL,NULL,NULL,NULL,NULL,NULL) 70#define Dprintf2(s,a,b) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),NULL,NULL,NULL,NULL,NULL,NULL) 71#define Dprintf3(s,a,b,c) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),NULL,NULL,NULL,NULL,NULL) 72#define Dprintf4(s,a,b,c,d) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),NULL,NULL,NULL,NULL) 73#define Dprintf5(s,a,b,c,d,e) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),(void *)((unsigned long)e),NULL,NULL,NULL) 74#define Dprintf6(s,a,b,c,d,e,f) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),(void *)((unsigned long)e),(void *)((unsigned long)f),NULL,NULL) 75#define Dprintf7(s,a,b,c,d,e,f,g) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),(void *)((unsigned long)e),(void *)((unsigned long)f),(void *)((unsigned long)g),NULL) 76#define Dprintf8(s,a,b,c,d,e,f,g,h) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),(void *)((unsigned long)e),(void *)((unsigned long)f),(void *)((unsigned long)g),(void *)((unsigned long)h)) 77 78#define FLUSH 79 80#define HASH_STRIPEID(_sid_) ( (_sid_) & (rf_lockTableSize-1) ) 81 82static void AddToWaitersQueue(RF_LockTableEntry_t * lockTable, RF_StripeLockDesc_t * lockDesc, RF_LockReqDesc_t * lockReqDesc); 83static RF_StripeLockDesc_t *AllocStripeLockDesc(RF_StripeNum_t stripeID); 84static void FreeStripeLockDesc(RF_StripeLockDesc_t * p); 85static void PrintLockedStripes(RF_LockTableEntry_t * lockTable); 86 87/* determines if two ranges overlap. always yields false if either start value is negative */ 88#define SINGLE_RANGE_OVERLAP(_strt1, _stop1, _strt2, _stop2) \ 89 ( (_strt1 >= 0) && (_strt2 >= 0) && (RF_MAX(_strt1, _strt2) <= RF_MIN(_stop1, _stop2)) ) 90 91/* determines if any of the ranges specified in the two lock descriptors overlap each other */ 92#define RANGE_OVERLAP(_cand, _pred) \ 93 ( SINGLE_RANGE_OVERLAP((_cand)->start, (_cand)->stop, (_pred)->start, (_pred)->stop ) || \ 94 SINGLE_RANGE_OVERLAP((_cand)->start2, (_cand)->stop2, (_pred)->start, (_pred)->stop ) || \ 95 SINGLE_RANGE_OVERLAP((_cand)->start, (_cand)->stop, (_pred)->start2, (_pred)->stop2) || \ 96 SINGLE_RANGE_OVERLAP((_cand)->start2, (_cand)->stop2, (_pred)->start2, (_pred)->stop2) ) 97 98/* Determines if a candidate lock request conflicts with a predecessor lock req. 99 * Note that the arguments are not interchangeable. 100 * The rules are: 101 * a candidate read conflicts with a predecessor write if any ranges overlap 102 * a candidate write conflicts with a predecessor read if any ranges overlap 103 * a candidate write conflicts with a predecessor write if any ranges overlap 104 */ 105#define STRIPELOCK_CONFLICT(_cand, _pred) \ 106 RANGE_OVERLAP((_cand), (_pred)) && \ 107 ( ( (((_cand)->type == RF_IO_TYPE_READ) && ((_pred)->type == RF_IO_TYPE_WRITE)) || \ 108 (((_cand)->type == RF_IO_TYPE_WRITE) && ((_pred)->type == RF_IO_TYPE_READ)) || \ 109 (((_cand)->type == RF_IO_TYPE_WRITE) && ((_pred)->type == RF_IO_TYPE_WRITE)) \ 110 ) \ 111 ) 112 113static RF_FreeList_t *rf_stripelock_freelist; 114#define RF_MAX_FREE_STRIPELOCK 128 115#define RF_STRIPELOCK_INC 8 116#define RF_STRIPELOCK_INITIAL 32 117 118static void rf_ShutdownStripeLockFreeList(void *); 119static void rf_RaidShutdownStripeLocks(void *); 120 121static void 122rf_ShutdownStripeLockFreeList(ignored) 123 void *ignored; 124{ 125 RF_FREELIST_DESTROY(rf_stripelock_freelist, next, (RF_StripeLockDesc_t *)); 126} 127 128int 129rf_ConfigureStripeLockFreeList(listp) 130 RF_ShutdownList_t **listp; 131{ 132 unsigned mask; 133 int rc; 134 135 RF_FREELIST_CREATE(rf_stripelock_freelist, RF_MAX_FREE_STRIPELOCK, 136 RF_STRIPELOCK_INITIAL, sizeof(RF_StripeLockDesc_t)); 137 rc = rf_ShutdownCreate(listp, rf_ShutdownStripeLockFreeList, NULL); 138 if (rc) { 139 RF_ERRORMSG3("Unable to add to shutdown list file %s line %d rc=%d\n", 140 __FILE__, __LINE__, rc); 141 rf_ShutdownStripeLockFreeList(NULL); 142 return (rc); 143 } 144 RF_FREELIST_PRIME(rf_stripelock_freelist, RF_STRIPELOCK_INITIAL, next, 145 (RF_StripeLockDesc_t *)); 146 for (mask = 0x1; mask; mask <<= 1) 147 if (rf_lockTableSize == mask) 148 break; 149 if (!mask) { 150 printf("[WARNING: lock table size must be a power of two. Setting to %d.]\n", RF_DEFAULT_LOCK_TABLE_SIZE); 151 rf_lockTableSize = RF_DEFAULT_LOCK_TABLE_SIZE; 152 } 153 return (0); 154} 155 156RF_LockTableEntry_t * 157rf_MakeLockTable() 158{ 159 RF_LockTableEntry_t *lockTable; 160 int i, rc; 161 162 RF_Calloc(lockTable, ((int) rf_lockTableSize), sizeof(RF_LockTableEntry_t), (RF_LockTableEntry_t *)); 163 if (lockTable == NULL) 164 return (NULL); 165 for (i = 0; i < rf_lockTableSize; i++) { 166 rc = rf_mutex_init(&lockTable[i].mutex); 167 if (rc) { 168 RF_ERRORMSG3("Unable to init mutex file %s line %d rc=%d\n", __FILE__, 169 __LINE__, rc); 170 /* XXX clean up other mutexes */ 171 return (NULL); 172 } 173 } 174 return (lockTable); 175} 176 177void 178rf_ShutdownStripeLocks(RF_LockTableEntry_t * lockTable) 179{ 180 int i; 181 182 if (rf_stripeLockDebug) { 183 PrintLockedStripes(lockTable); 184 } 185 for (i = 0; i < rf_lockTableSize; i++) { 186 rf_mutex_destroy(&lockTable[i].mutex); 187 } 188 RF_Free(lockTable, rf_lockTableSize * sizeof(RF_LockTableEntry_t)); 189} 190 191static void 192rf_RaidShutdownStripeLocks(arg) 193 void *arg; 194{ 195 RF_Raid_t *raidPtr = (RF_Raid_t *) arg; 196 rf_ShutdownStripeLocks(raidPtr->lockTable); 197} 198 199int 200rf_ConfigureStripeLocks( 201 RF_ShutdownList_t ** listp, 202 RF_Raid_t * raidPtr, 203 RF_Config_t * cfgPtr) 204{ 205 int rc; 206 207 raidPtr->lockTable = rf_MakeLockTable(); 208 if (raidPtr->lockTable == NULL) 209 return (ENOMEM); 210 rc = rf_ShutdownCreate(listp, rf_RaidShutdownStripeLocks, raidPtr); 211 if (rc) { 212 RF_ERRORMSG3("Unable to add to shutdown list file %s line %d rc=%d\n", 213 __FILE__, __LINE__, rc); 214 rf_ShutdownStripeLocks(raidPtr->lockTable); 215 return (rc); 216 } 217 return (0); 218} 219/* returns 0 if you've got the lock, and non-zero if you have to wait. 220 * if and only if you have to wait, we'll cause cbFunc to get invoked 221 * with cbArg when you are granted the lock. We store a tag in *releaseTag 222 * that you need to give back to us when you release the lock. 223 */ 224int 225rf_AcquireStripeLock( 226 RF_LockTableEntry_t * lockTable, 227 RF_StripeNum_t stripeID, 228 RF_LockReqDesc_t * lockReqDesc) 229{ 230 RF_StripeLockDesc_t *lockDesc; 231 RF_LockReqDesc_t *p; 232 int tid = 0, hashval = HASH_STRIPEID(stripeID); 233 int retcode = 0; 234 235 RF_ASSERT(RF_IO_IS_R_OR_W(lockReqDesc->type)); 236 237 if (rf_stripeLockDebug) { 238 if (stripeID == -1) 239 Dprintf1("[%d] Lock acquisition supressed (stripeID == -1)\n", tid); 240 else { 241 Dprintf8("[%d] Trying to acquire stripe lock table 0x%lx SID %ld type %c range %ld-%ld, range2 %ld-%ld hashval %d\n", 242 tid, (unsigned long) lockTable, stripeID, lockReqDesc->type, lockReqDesc->start, 243 lockReqDesc->stop, lockReqDesc->start2, lockReqDesc->stop2); 244 Dprintf3("[%d] lock %ld hashval %d\n", tid, stripeID, hashval); 245 FLUSH; 246 } 247 } 248 if (stripeID == -1) 249 return (0); 250 lockReqDesc->next = NULL; /* just to be sure */ 251 252 RF_LOCK_MUTEX(lockTable[hashval].mutex); 253 for (lockDesc = lockTable[hashval].descList; lockDesc; lockDesc = lockDesc->next) { 254 if (lockDesc->stripeID == stripeID) 255 break; 256 } 257 258 if (!lockDesc) { /* no entry in table => no one reading or 259 * writing */ 260 lockDesc = AllocStripeLockDesc(stripeID); 261 lockDesc->next = lockTable[hashval].descList; 262 lockTable[hashval].descList = lockDesc; 263 if (lockReqDesc->type == RF_IO_TYPE_WRITE) 264 lockDesc->nWriters++; 265 lockDesc->granted = lockReqDesc; 266 if (rf_stripeLockDebug) { 267 Dprintf7("[%d] no one waiting: lock %ld %c %ld-%ld %ld-%ld granted\n", 268 tid, stripeID, lockReqDesc->type, lockReqDesc->start, lockReqDesc->stop, lockReqDesc->start2, lockReqDesc->stop2); 269 FLUSH; 270 } 271 } else { 272 273 if (lockReqDesc->type == RF_IO_TYPE_WRITE) 274 lockDesc->nWriters++; 275 276 if (lockDesc->nWriters == 0) { /* no need to search any lists 277 * if there are no writers 278 * anywhere */ 279 lockReqDesc->next = lockDesc->granted; 280 lockDesc->granted = lockReqDesc; 281 if (rf_stripeLockDebug) { 282 Dprintf7("[%d] no writers: lock %ld %c %ld-%ld %ld-%ld granted\n", 283 tid, stripeID, lockReqDesc->type, lockReqDesc->start, lockReqDesc->stop, lockReqDesc->start2, lockReqDesc->stop2); 284 FLUSH; 285 } 286 } else { 287 288 /* search the granted & waiting lists for a conflict. 289 * stop searching as soon as we find one */ 290 retcode = 0; 291 for (p = lockDesc->granted; p; p = p->next) 292 if (STRIPELOCK_CONFLICT(lockReqDesc, p)) { 293 retcode = 1; 294 break; 295 } 296 if (!retcode) 297 for (p = lockDesc->waitersH; p; p = p->next) 298 if (STRIPELOCK_CONFLICT(lockReqDesc, p)) { 299 retcode = 2; 300 break; 301 } 302 if (!retcode) { 303 lockReqDesc->next = lockDesc->granted; /* no conflicts found => 304 * grant lock */ 305 lockDesc->granted = lockReqDesc; 306 if (rf_stripeLockDebug) { 307 Dprintf7("[%d] no conflicts: lock %ld %c %ld-%ld %ld-%ld granted\n", 308 tid, stripeID, lockReqDesc->type, lockReqDesc->start, lockReqDesc->stop, 309 lockReqDesc->start2, lockReqDesc->stop2); 310 FLUSH; 311 } 312 } else { 313 if (rf_stripeLockDebug) { 314 Dprintf6("[%d] conflict: lock %ld %c %ld-%ld hashval=%d not granted\n", 315 tid, stripeID, lockReqDesc->type, lockReqDesc->start, lockReqDesc->stop, 316 hashval); 317 Dprintf3("[%d] lock %ld retcode=%d\n", tid, stripeID, retcode); 318 FLUSH; 319 } 320 AddToWaitersQueue(lockTable, lockDesc, lockReqDesc); /* conflict => the 321 * current access must 322 * wait */ 323 } 324 } 325 } 326 327 RF_UNLOCK_MUTEX(lockTable[hashval].mutex); 328 return (retcode); 329} 330 331void 332rf_ReleaseStripeLock( 333 RF_LockTableEntry_t * lockTable, 334 RF_StripeNum_t stripeID, 335 RF_LockReqDesc_t * lockReqDesc) 336{ 337 RF_StripeLockDesc_t *lockDesc, *ld_t; 338 RF_LockReqDesc_t *lr, *lr_t, *callbacklist, *t; 339 RF_IoType_t type = lockReqDesc->type; 340 int tid = 0, hashval = HASH_STRIPEID(stripeID); 341 int release_it, consider_it; 342 RF_LockReqDesc_t *candidate, *candidate_t, *predecessor; 343 344 RF_ASSERT(RF_IO_IS_R_OR_W(type)); 345 346 if (rf_stripeLockDebug) { 347 if (stripeID == -1) 348 Dprintf1("[%d] Lock release supressed (stripeID == -1)\n", tid); 349 else { 350 Dprintf8("[%d] Releasing stripe lock on stripe ID %ld, type %c range %ld-%ld %ld-%ld table 0x%lx\n", 351 tid, stripeID, lockReqDesc->type, lockReqDesc->start, lockReqDesc->stop, lockReqDesc->start2, lockReqDesc->stop2, lockTable); 352 FLUSH; 353 } 354 } 355 if (stripeID == -1) 356 return; 357 358 RF_LOCK_MUTEX(lockTable[hashval].mutex); 359 360 /* find the stripe lock descriptor */ 361 for (ld_t = NULL, lockDesc = lockTable[hashval].descList; lockDesc; ld_t = lockDesc, lockDesc = lockDesc->next) { 362 if (lockDesc->stripeID == stripeID) 363 break; 364 } 365 RF_ASSERT(lockDesc); /* major error to release a lock that doesn't 366 * exist */ 367 368 /* find the stripe lock request descriptor & delete it from the list */ 369 for (lr_t = NULL, lr = lockDesc->granted; lr; lr_t = lr, lr = lr->next) 370 if (lr == lockReqDesc) 371 break; 372 373 RF_ASSERT(lr && (lr == lockReqDesc)); /* major error to release a 374 * lock that hasn't been 375 * granted */ 376 if (lr_t) 377 lr_t->next = lr->next; 378 else { 379 RF_ASSERT(lr == lockDesc->granted); 380 lockDesc->granted = lr->next; 381 } 382 lr->next = NULL; 383 384 if (lockReqDesc->type == RF_IO_TYPE_WRITE) 385 lockDesc->nWriters--; 386 387 /* search through the waiters list to see if anyone needs to be woken 388 * up. for each such descriptor in the wait list, we check it against 389 * everything granted and against everything _in front_ of it in the 390 * waiters queue. If it conflicts with none of these, we release it. 391 * 392 * DON'T TOUCH THE TEMPLINK POINTER OF ANYTHING IN THE GRANTED LIST HERE. 393 * This will roach the case where the callback tries to acquire a new 394 * lock in the same stripe. There are some asserts to try and detect 395 * this. 396 * 397 * We apply 2 performance optimizations: (1) if releasing this lock 398 * results in no more writers to this stripe, we just release 399 * everybody waiting, since we place no restrictions on the number of 400 * concurrent reads. (2) we consider as candidates for wakeup only 401 * those waiters that have a range overlap with either the descriptor 402 * being woken up or with something in the callbacklist (i.e. 403 * something we've just now woken up). This allows us to avoid the 404 * long evaluation for some descriptors. */ 405 406 callbacklist = NULL; 407 if (lockDesc->nWriters == 0) { /* performance tweak (1) */ 408 while (lockDesc->waitersH) { 409 410 lr = lockDesc->waitersH; /* delete from waiters 411 * list */ 412 lockDesc->waitersH = lr->next; 413 414 RF_ASSERT(lr->type == RF_IO_TYPE_READ); 415 416 lr->next = lockDesc->granted; /* add to granted list */ 417 lockDesc->granted = lr; 418 419 RF_ASSERT(!lr->templink); 420 lr->templink = callbacklist; /* put on callback list 421 * so that we'll invoke 422 * callback below */ 423 callbacklist = lr; 424 if (rf_stripeLockDebug) { 425 Dprintf8("[%d] No writers: granting lock stripe ID %ld, type %c range %ld-%ld %ld-%ld table 0x%lx\n", 426 tid, stripeID, lr->type, lr->start, lr->stop, lr->start2, lr->stop2, (unsigned long) lockTable); 427 FLUSH; 428 } 429 } 430 lockDesc->waitersT = NULL; /* we've purged the whole 431 * waiters list */ 432 433 } else 434 for (candidate_t = NULL, candidate = lockDesc->waitersH; candidate;) { 435 436 /* performance tweak (2) */ 437 consider_it = 0; 438 if (RANGE_OVERLAP(lockReqDesc, candidate)) 439 consider_it = 1; 440 else 441 for (t = callbacklist; t; t = t->templink) 442 if (RANGE_OVERLAP(t, candidate)) { 443 consider_it = 1; 444 break; 445 } 446 if (!consider_it) { 447 if (rf_stripeLockDebug) { 448 Dprintf8("[%d] No overlap: rejecting candidate stripeID %ld, type %c range %ld-%ld %ld-%ld table 0x%lx\n", 449 tid, stripeID, candidate->type, candidate->start, candidate->stop, candidate->start2, candidate->stop2, 450 (unsigned long) lockTable); 451 FLUSH; 452 } 453 candidate_t = candidate; 454 candidate = candidate->next; 455 continue; 456 } 457 /* we have a candidate for release. check to make 458 * sure it is not blocked by any granted locks */ 459 release_it = 1; 460 for (predecessor = lockDesc->granted; predecessor; predecessor = predecessor->next) { 461 if (STRIPELOCK_CONFLICT(candidate, predecessor)) { 462 if (rf_stripeLockDebug) { 463 Dprintf8("[%d] Conflicts with granted lock: rejecting candidate stripeID %ld, type %c range %ld-%ld %ld-%ld table 0x%lx\n", 464 tid, stripeID, candidate->type, candidate->start, candidate->stop, candidate->start2, candidate->stop2, 465 (unsigned long) lockTable); 466 FLUSH; 467 } 468 release_it = 0; 469 break; 470 } 471 } 472 473 /* now check to see if the candidate is blocked by any 474 * waiters that occur before it it the wait queue */ 475 if (release_it) 476 for (predecessor = lockDesc->waitersH; predecessor != candidate; predecessor = predecessor->next) { 477 if (STRIPELOCK_CONFLICT(candidate, predecessor)) { 478 if (rf_stripeLockDebug) { 479 Dprintf8("[%d] Conflicts with waiting lock: rejecting candidate stripeID %ld, type %c range %ld-%ld %ld-%ld table 0x%lx\n", 480 tid, stripeID, candidate->type, candidate->start, candidate->stop, candidate->start2, candidate->stop2, 481 (unsigned long) lockTable); 482 FLUSH; 483 } 484 release_it = 0; 485 break; 486 } 487 } 488 489 /* release it if indicated */ 490 if (release_it) { 491 if (rf_stripeLockDebug) { 492 Dprintf8("[%d] Granting lock to candidate stripeID %ld, type %c range %ld-%ld %ld-%ld table 0x%lx\n", 493 tid, stripeID, candidate->type, candidate->start, candidate->stop, candidate->start2, candidate->stop2, 494 (unsigned long) lockTable); 495 FLUSH; 496 } 497 if (candidate_t) { 498 candidate_t->next = candidate->next; 499 if (lockDesc->waitersT == candidate) 500 lockDesc->waitersT = candidate_t; /* cannot be waitersH 501 * since candidate_t is 502 * not NULL */ 503 } else { 504 RF_ASSERT(candidate == lockDesc->waitersH); 505 lockDesc->waitersH = lockDesc->waitersH->next; 506 if (!lockDesc->waitersH) 507 lockDesc->waitersT = NULL; 508 } 509 candidate->next = lockDesc->granted; /* move it to the 510 * granted list */ 511 lockDesc->granted = candidate; 512 513 RF_ASSERT(!candidate->templink); 514 candidate->templink = callbacklist; /* put it on the list of 515 * things to be called 516 * after we release the 517 * mutex */ 518 callbacklist = candidate; 519 520 if (!candidate_t) 521 candidate = lockDesc->waitersH; 522 else 523 candidate = candidate_t->next; /* continue with the 524 * rest of the list */ 525 } else { 526 candidate_t = candidate; 527 candidate = candidate->next; /* continue with the 528 * rest of the list */ 529 } 530 } 531 532 /* delete the descriptor if no one is waiting or active */ 533 if (!lockDesc->granted && !lockDesc->waitersH) { 534 RF_ASSERT(lockDesc->nWriters == 0); 535 if (rf_stripeLockDebug) { 536 Dprintf3("[%d] Last lock released (table 0x%lx): deleting desc for stripeID %ld\n", tid, (unsigned long) lockTable, stripeID); 537 FLUSH; 538 } 539 if (ld_t) 540 ld_t->next = lockDesc->next; 541 else { 542 RF_ASSERT(lockDesc == lockTable[hashval].descList); 543 lockTable[hashval].descList = lockDesc->next; 544 } 545 FreeStripeLockDesc(lockDesc); 546 lockDesc = NULL;/* only for the ASSERT below */ 547 } 548 RF_UNLOCK_MUTEX(lockTable[hashval].mutex); 549 550 /* now that we've unlocked the mutex, invoke the callback on all the 551 * descriptors in the list */ 552 RF_ASSERT(!((callbacklist) && (!lockDesc))); /* if we deleted the 553 * descriptor, we should 554 * have no callbacks to 555 * do */ 556 for (candidate = callbacklist; candidate;) { 557 t = candidate; 558 candidate = candidate->templink; 559 t->templink = NULL; 560 (t->cbFunc) (t->cbArg); 561 } 562} 563/* must have the indicated lock table mutex upon entry */ 564static void 565AddToWaitersQueue( 566 RF_LockTableEntry_t * lockTable, 567 RF_StripeLockDesc_t * lockDesc, 568 RF_LockReqDesc_t * lockReqDesc) 569{ 570#if 0 /* XXX fvdl -- unitialized use of 'tid' */ 571 int tid; 572 573 if (rf_stripeLockDebug) { 574 Dprintf3("[%d] Waiting on lock for stripe %ld table 0x%lx\n", tid, lockDesc->stripeID, (unsigned long) lockTable); 575 FLUSH; 576 } 577#endif 578 if (!lockDesc->waitersH) { 579 lockDesc->waitersH = lockDesc->waitersT = lockReqDesc; 580 } else { 581 lockDesc->waitersT->next = lockReqDesc; 582 lockDesc->waitersT = lockReqDesc; 583 } 584} 585 586static RF_StripeLockDesc_t * 587AllocStripeLockDesc(RF_StripeNum_t stripeID) 588{ 589 RF_StripeLockDesc_t *p; 590 591 RF_FREELIST_GET(rf_stripelock_freelist, p, next, (RF_StripeLockDesc_t *)); 592 if (p) { 593 p->stripeID = stripeID; 594 } 595 return (p); 596} 597 598static void 599FreeStripeLockDesc(RF_StripeLockDesc_t * p) 600{ 601 RF_FREELIST_FREE(rf_stripelock_freelist, p, next); 602} 603 604static void 605PrintLockedStripes(lockTable) 606 RF_LockTableEntry_t *lockTable; 607{ 608 int i, j, foundone = 0, did; 609 RF_StripeLockDesc_t *p; 610 RF_LockReqDesc_t *q; 611 612 RF_LOCK_MUTEX(rf_printf_mutex); 613 printf("Locked stripes:\n"); 614 for (i = 0; i < rf_lockTableSize; i++) 615 if (lockTable[i].descList) { 616 foundone = 1; 617 for (p = lockTable[i].descList; p; p = p->next) { 618 printf("Stripe ID 0x%lx (%d) nWriters %d\n", 619 (long) p->stripeID, (int) p->stripeID, p->nWriters); 620 621 if (!(p->granted)) 622 printf("Granted: (none)\n"); 623 else 624 printf("Granted:\n"); 625 for (did = 1, j = 0, q = p->granted; q; j++, q = q->next) { 626 printf(" %c(%ld-%ld", q->type, (long) q->start, (long) q->stop); 627 if (q->start2 != -1) 628 printf(",%ld-%ld) ", (long) q->start2, 629 (long) q->stop2); 630 else 631 printf(") "); 632 if (j && !(j % 4)) { 633 printf("\n"); 634 did = 1; 635 } else 636 did = 0; 637 } 638 if (!did) 639 printf("\n"); 640 641 if (!(p->waitersH)) 642 printf("Waiting: (none)\n"); 643 else 644 printf("Waiting:\n"); 645 for (did = 1, j = 0, q = p->waitersH; q; j++, q = q->next) { 646 printf("%c(%ld-%ld", q->type, (long) q->start, (long) q->stop); 647 if (q->start2 != -1) 648 printf(",%ld-%ld) ", (long) q->start2, (long) q->stop2); 649 else 650 printf(") "); 651 if (j && !(j % 4)) { 652 printf("\n "); 653 did = 1; 654 } else 655 did = 0; 656 } 657 if (!did) 658 printf("\n"); 659 } 660 } 661 if (!foundone) 662 printf("(none)\n"); 663 else 664 printf("\n"); 665 RF_UNLOCK_MUTEX(rf_printf_mutex); 666} 667