summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/vinum/vinumlock.c203
1 files changed, 64 insertions, 139 deletions
diff --git a/sys/dev/vinum/vinumlock.c b/sys/dev/vinum/vinumlock.c
index 1834b84..7d6562b 100644
--- a/sys/dev/vinum/vinumlock.c
+++ b/sys/dev/vinum/vinumlock.c
@@ -37,19 +37,13 @@
* otherwise) arising in any way out of the use of this software, even if
* advised of the possibility of such damage.
*
- * $Id: vinumlock.c,v 1.12 2000/01/05 22:17:25 grog Exp grog $
+ * $Id: vinumlock.c,v 1.14 2001/01/10 04:10:30 grog Exp grog $
* $FreeBSD$
*/
#include <dev/vinum/vinumhdr.h>
#include <dev/vinum/request.h>
-/*
- * Lock routines. Currently, we lock either an individual volume
- * or the global configuration. I don't think tsleep and
- * wakeup are SMP safe. FIXME XXX
- */
-
/* Lock a drive, wait if it's in use */
#if VINUMDEBUG
int
@@ -112,85 +106,13 @@ unlockdrive(struct drive *drive)
wakeup(&lockdrive);
}
-/* Lock a volume, wait if it's in use */
-int
-lockvol(struct volume *vol)
-{
- int error;
-
- while ((vol->flags & VF_LOCKED) != 0) {
- vol->flags |= VF_LOCKING;
- /*
- * It would seem to make more sense to sleep on
- * the address 'vol'. Unfortuntaly we can't
- * guarantee that this address won't change due to
- * table expansion. The address we choose won't change.
- */
- if ((error = tsleep(&vinum_conf.volume + vol->volno,
- PRIBIO,
- "volock",
- 0)) != 0)
- return error;
- }
- vol->flags |= VF_LOCKED;
- return 0;
-}
-
-/* Unlock a volume and let the next one at it */
-void
-unlockvol(struct volume *vol)
-{
- vol->flags &= ~VF_LOCKED;
- if ((vol->flags & VF_LOCKING) != 0) {
- vol->flags &= ~VF_LOCKING;
- wakeup(&vinum_conf.volume + vol->volno);
- }
-}
-
-/* Lock a plex, wait if it's in use */
-int
-lockplex(struct plex *plex)
-{
- int error;
-
- while ((plex->flags & VF_LOCKED) != 0) {
- plex->flags |= VF_LOCKING;
- /*
- * It would seem to make more sense to sleep on
- * the address 'plex'. Unfortunately we can't
- * guarantee that this address won't change due to
- * table expansion. The address we choose won't change.
- */
- if ((error = tsleep(&vinum_conf.plex + plex->sdnos[0],
- PRIBIO,
- "plexlk",
- 0)) != 0)
- return error;
- }
- plex->flags |= VF_LOCKED;
- return 0;
-}
-
-/* Unlock a plex and let the next one at it */
-void
-unlockplex(struct plex *plex)
-{
- plex->flags &= ~VF_LOCKED;
- if ((plex->flags & VF_LOCKING) != 0) {
- plex->flags &= ~VF_LOCKING;
- wakeup(&vinum_conf.plex + plex->plexno);
- }
-}
-
/* Lock a stripe of a plex, wait if it's in use */
struct rangelock *
lockrange(daddr_t stripe, struct buf *bp, struct plex *plex)
{
- int s;
struct rangelock *lock;
struct rangelock *pos; /* position of first free lock */
int foundlocks; /* number of locks found */
- int newlock;
/*
* We could get by without counting the number
@@ -210,72 +132,65 @@ lockrange(daddr_t stripe, struct buf *bp, struct plex *plex)
* increment all addresses by 1.
*/
stripe++;
- /*
- * We give the locks back from an interrupt
- * context, so we need to raise the spl here.
- */
- s = splbio();
+ mtx_enter(&plex->lockmtx, MTX_DEF);
- /* Search the lock table for our stripe */
- for (lock = plex->lock;
- lock < &plex->lock[plex->alloclocks]
- && foundlocks < plex->usedlocks;
- lock++) {
- if (lock->stripe) { /* in use */
- foundlocks++; /* found another one in use */
- if ((lock->stripe == stripe) /* it's our stripe */
-&&(lock->plexno == plex->plexno) /* and our plex */
- &&(lock->bp != bp)) { /* but not our request */
- /*
- * It would be nice to sleep on the lock
- * itself, but it could get moved if the
- * table expands during the wait. Wait on
- * the lock address + 1 (since waiting on
- * 0 isn't allowed) instead. It isn't
- * exactly unique, but we won't have many
- * conflicts. The worst effect of a
- * conflict would be an additional
- * schedule and time through this loop.
- */
-#ifdef VINUMDEBUG
- if (debug & DEBUG_LASTREQS) {
- struct rangelock info;
+ /* Wait here if the table is full */
+ while (plex->usedlocks == PLEX_LOCKS) /* all in use */
+ msleep(&plex->usedlocks, &plex->lockmtx, PRIBIO, "vlock", 0);
- info.stripe = stripe;
- info.bp = bp;
- info.plexno = plex->plexno;
- logrq(loginfo_lockwait, (union rqinfou) &info, bp);
- }
+#ifdef DIAGNOSTIC
+ if (plex->usedlocks >= PLEX_LOCKS)
+ panic("lockrange: Too many locks in use");
#endif
- plex->lockwaits++; /* waited one more time */
- tsleep((void *) lock->stripe, PRIBIO, "vrlock", 2 * hz);
- lock = plex->lock; /* start again */
- foundlocks = 0;
- pos = NULL;
- }
- } else if (pos == NULL) /* still looking for somewhere? */
+
+ lock = plex->lock; /* pointer in lock table */
+ if (plex->usedlocks > 0) /* something locked, */
+ /* Search the lock table for our stripe */
+ for (; lock < &plex->lock[PLEX_LOCKS]
+ && foundlocks < plex->usedlocks;
+ lock++) {
+ if (lock->stripe) { /* in use */
+ foundlocks++; /* found another one in use */
+ if ((lock->stripe == stripe) /* it's our stripe */
+ &&(lock->plexno == plex->plexno) /* and our plex */
+ &&(lock->bp != bp)) { /* but not our request */
+#ifdef VINUMDEBUG
+ if (debug & DEBUG_LASTREQS) {
+ struct rangelock info;
+
+ info.stripe = stripe;
+ info.bp = bp;
+ info.plexno = plex->plexno;
+ logrq(loginfo_lockwait, (union rqinfou) &info, bp);
+ }
+#endif
+ plex->lockwaits++; /* waited one more time */
+ msleep(lock, &plex->lockmtx, PRIBIO, "vrlock", 0);
+ lock = plex->lock; /* start again */
+ foundlocks = 0;
+ pos = NULL;
+ }
+ } else if (pos == NULL) /* still looking for somewhere? */
pos = lock; /* a place to put this one */
- }
+ }
+ /*
+ * This untidy looking code ensures that we'll
+ * always end up pointing to the first free lock
+ * entry, thus minimizing the number of
+ * iterations necessary.
+ */
+ if (pos == NULL) /* didn't find one on the way, */
+ pos = lock; /* use the one we're pointing to */
/*
- * The address range is free. Add our lock
- * entry.
+ * The address range is free, and we're pointing
+ * to the first unused entry. Make it ours.
*/
- if (pos == NULL) { /* Didn't find an entry */
- if (foundlocks >= plex->alloclocks) { /* searched the lot, */
- newlock = plex->alloclocks;
- EXPAND(plex->lock, struct rangelock, plex->alloclocks, INITIAL_LOCKS);
- pos = &plex->lock[newlock];
- while (newlock < plex->alloclocks)
- plex->lock[newlock++].stripe = 0;
- } else
- pos = lock; /* put it at the end */
- }
pos->stripe = stripe;
pos->bp = bp;
pos->plexno = plex->plexno;
plex->usedlocks++; /* one more lock */
- splx(s);
+ mtx_exit(&plex->lockmtx, MTX_DEF);
#ifdef VINUMDEBUG
if (debug & DEBUG_LASTREQS)
logrq(loginfo_lock, (union rqinfou) pos, bp);
@@ -287,16 +202,26 @@ lockrange(daddr_t stripe, struct buf *bp, struct plex *plex)
void
unlockrange(int plexno, struct rangelock *lock)
{
- daddr_t lockaddr;
-
+ struct plex *plex;
+
+ plex = &PLEX[plexno];
+#ifdef DIAGNOSTIC
+ if (lock < &plex->lock[0] || lock >= &plex->lock[PLEX_LOCKS])
+ panic("vinum: rangelock %p on plex %d invalid, not between %p and %p",
+ lock,
+ plexno,
+ &plex->lock[0],
+ &plex->lock[PLEX_LOCKS]);
+#endif
#ifdef VINUMDEBUG
if (debug & DEBUG_LASTREQS)
logrq(loginfo_unlock, (union rqinfou) lock, lock->bp);
#endif
- lockaddr = lock->stripe;
lock->stripe = 0; /* no longer used */
- PLEX[plexno].usedlocks--; /* one less lock */
- wakeup((void *) lockaddr);
+ plex->usedlocks--; /* one less lock */
+ if (plex->usedlocks == PLEX_LOCKS - 1) /* we were full, */
+ wakeup_one(&plex->usedlocks); /* get a waiter if one's there */
+ wakeup_one((void *) lock);
}
/* Get a lock for the global config, wait if it's not available */
OpenPOWER on IntegriCloud