summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2006-10-02 02:06:27 +0000
committertegge <tegge@FreeBSD.org>2006-10-02 02:06:27 +0000
commit4d26d3d4d7b97a3bbb360a06b061e0af9728920f (patch)
treee5d5e1e8f49a36219f541a75afc21293e49757cd
parentc12a3c74f93c0808b4c8f0664df6c80b08a2f570 (diff)
downloadFreeBSD-src-4d26d3d4d7b97a3bbb360a06b061e0af9728920f.zip
FreeBSD-src-4d26d3d4d7b97a3bbb360a06b061e0af9728920f.tar.gz
If the buffer lock has waiters after the buffer has changed identity then
getnewbuf() needs to drop the buffer in order to wake waiters that might sleep on the buffer in the context of the old identity.
-rw-r--r--sys/kern/kern_lock.c15
-rw-r--r--sys/kern/vfs_bio.c11
-rw-r--r--sys/sys/buf.h11
-rw-r--r--sys/sys/lockmgr.h1
4 files changed, 38 insertions, 0 deletions
diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c
index c0b929a..32b43b8 100644
--- a/sys/kern/kern_lock.c
+++ b/sys/kern/kern_lock.c
@@ -566,6 +566,21 @@ lockcount(lkp)
}
/*
+ * Determine the number of waiters on a lock.
+ */
+int
+lockwaiters(lkp)
+ struct lock *lkp;
+{
+ int count;
+
+ mtx_lock(lkp->lk_interlock);
+ count = lkp->lk_waitcount;
+ mtx_unlock(lkp->lk_interlock);
+ return (count);
+}
+
+/*
* Print out information about state of a lock. Used by VOP_PRINT
* routines to display status about contained locks.
*/
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 37ef552..904e84c 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -1890,6 +1890,17 @@ restart:
}
/*
+ * Notify any waiters for the buffer lock about
+ * identity change by freeing the buffer.
+ */
+ if (qindex == QUEUE_CLEAN && BUF_LOCKWAITERS(bp) > 0) {
+ bp->b_flags |= B_INVAL;
+ bfreekva(bp);
+ brelse(bp);
+ goto restart;
+ }
+
+ /*
* If we are overcomitted then recover the buffer and its
* KVM space. This occurs in rare situations when multiple
* processes are blocked in getnewbuf() or allocbuf().
diff --git a/sys/sys/buf.h b/sys/sys/buf.h
index afa3e23..359be84 100644
--- a/sys/sys/buf.h
+++ b/sys/sys/buf.h
@@ -371,6 +371,17 @@ BUF_REFCNT(struct buf *bp)
return ret;
}
+
+/*
+ * Find out the number of waiters on a lock.
+ */
+static __inline int BUF_LOCKWAITERS(struct buf *);
+static __inline int
+BUF_LOCKWAITERS(struct buf *bp)
+{
+ return (lockwaiters(&bp->b_lock));
+}
+
#endif /* _KERNEL */
struct buf_queue_head {
diff --git a/sys/sys/lockmgr.h b/sys/sys/lockmgr.h
index dd0eed9..9c9b59b 100644
--- a/sys/sys/lockmgr.h
+++ b/sys/sys/lockmgr.h
@@ -203,6 +203,7 @@ void transferlockers(struct lock *, struct lock *);
void lockmgr_printinfo(struct lock *);
int lockstatus(struct lock *, struct thread *);
int lockcount(struct lock *);
+int lockwaiters(struct lock *);
#ifdef DDB
int lockmgr_chain(struct thread *td, struct thread **ownerp);
#endif
OpenPOWER on IntegriCloud