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