[BACK]Return to rf_stripelocks.c CVS log [TXT][DIR] Up to [local] / sys / dev / raidframe

Annotation of sys/dev/raidframe/rf_stripelocks.c, Revision 1.1.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