#ifdef AFS_FBSD_ENV
#define timecounter afs_timecounter
#endif
-/* The locks for individual buffer entries are now sometimes obtained while holding the
- * afs_bufferLock. Thus we now have a locking hierarchy: afs_bufferLock -> Buffers[].lock.
+
+/* A note on locking in 'struct buffer'
+ *
+ * afs_bufferLock protects the hash chain, and the 'lockers' field where that
+ * has a zero value. It must be held whenever lockers is incremented from zero.
+ *
+ * The individual buffer lock protects the contents of the structure, including
+ * the lockers field.
+ *
+ * For safety: afs_bufferLock and the individual buffer lock must be held
+ * when obtaining a reference on a structure. Only the individual buffer lock
+ * need be held when releasing a reference.
+ *
+ * The locking hierarchy is afs_bufferLock-> buffer.lock
+ *
*/
+
static afs_lock_t afs_bufferLock;
static struct buffer *phTable[PHSIZE]; /* page hash table */
static int nbuffers;
if ((tb = phTable[pHash(adc->index, page)])) {
if (bufmatch(tb)) {
MObtainWriteLock(&tb->lock, 257);
- ReleaseWriteLock(&afs_bufferLock);
tb->lockers++;
+ ReleaseWriteLock(&afs_bufferLock);
tb->accesstime = timecounter++;
AFS_STATS(afs_stats_cmperf.bufHits++);
MReleaseWriteLock(&tb->lock);
if (bufmatch(tb2)) {
buf_Front(bufhead, tb, tb2);
MObtainWriteLock(&tb2->lock, 258);
- ReleaseWriteLock(&afs_bufferLock);
tb2->lockers++;
+ ReleaseWriteLock(&afs_bufferLock);
tb2->accesstime = timecounter++;
AFS_STATS(afs_stats_cmperf.bufHits++);
MReleaseWriteLock(&tb2->lock);
if (bufmatch(tb)) {
buf_Front(bufhead, tb2, tb);
MObtainWriteLock(&tb->lock, 259);
- ReleaseWriteLock(&afs_bufferLock);
tb->lockers++;
+ ReleaseWriteLock(&afs_bufferLock);
tb->accesstime = timecounter++;
AFS_STATS(afs_stats_cmperf.bufHits++);
MReleaseWriteLock(&tb->lock);
return NULL;
}
MObtainWriteLock(&tb->lock, 260);
- MReleaseWriteLock(&afs_bufferLock);
tb->lockers++;
+ MReleaseWriteLock(&afs_bufferLock);
if (page * AFS_BUFFER_PAGESIZE >= adc->f.chunkBytes) {
tb->fid = NULLIDX;
afs_reset_inode(&tb->inode);
{
/* Find a usable buffer slot */
register afs_int32 i;
- afs_int32 lt;
+ afs_int32 lt = 0;
register struct buffer *tp;
struct osi_file *tfile;
if (lp && (lp->lockers == 0)) {
lt = lp->accesstime;
} else {
- lp = 0;
- lt = BUF_TIME_MAX;
+ lp = NULL;
}
/* timecounter might have wrapped, if machine is very very busy
tp = Buffers;
for (i = 0; i < nbuffers; i++, tp++) {
if (tp->lockers == 0) {
- if (tp->accesstime < lt) {
+ if (!lp || tp->accesstime < lt) {
lp = tp;
lt = tp->accesstime;
}
afs_WriteDCache(adc, 1);
}
MObtainWriteLock(&tb->lock, 265);
- MReleaseWriteLock(&afs_bufferLock);
tb->lockers++;
+ MReleaseWriteLock(&afs_bufferLock);
MReleaseWriteLock(&tb->lock);
return tb->data;
}