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