root/dev/raidframe/rf_stripelocks.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rf_ShutdownStripeLockFreeList
  2. rf_ConfigureStripeLockFreeList
  3. rf_MakeLockTable
  4. rf_ShutdownStripeLocks
  5. rf_RaidShutdownStripeLocks
  6. rf_ConfigureStripeLocks
  7. rf_AcquireStripeLock
  8. rf_ReleaseStripeLock
  9. rf_AddToWaitersQueue
  10. rf_AllocStripeLockDesc
  11. rf_FreeStripeLockDesc
  12. rf_PrintLockedStripes

    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 }

/* [<][>][^][v][top][bottom][index][help] */