/* * Release a buffer on to the free lists. * Described in Bach (p. 46). */ void brelse(struct buf *bp) { struct bqueues *bufq; int s; /* Block disk interrupts. */ s = splbio(); /* * Determine which queue the buffer should be on, then put it there. */ /* If it's locked, don't report an error; try again later. */ if (ISSET(bp->b_flags, (B_LOCKED|B_ERROR)) == (B_LOCKED|B_ERROR)) CLR(bp->b_flags, B_ERROR); /* If it's not cacheable, or an error, mark it invalid. */ if (ISSET(bp->b_flags, (B_NOCACHE|B_ERROR))) SET(bp->b_flags, B_INVAL); if ((bp->b_bufsize <= 0) || ISSET(bp->b_flags, B_INVAL)) { /* * If it's invalid or empty, dissociate it from its vnode * and put on the head of the appropriate queue. */ if (LIST_FIRST(&bp->b_dep) != NULL) buf_deallocate(bp); if (ISSET(bp->b_flags, B_DELWRI)) { CLR(bp->b_flags, B_DELWRI); } if (bp->b_vp) { reassignbuf(bp); brelvp(bp); } if (bp->b_bufsize <= 0) { /* no data */ bufq = &bufqueues[BQ_EMPTY]; numemptybufs++; } else { /* invalid data */ bufq = &bufqueues[BQ_CLEAN]; numfreepages += btoc(bp->b_bufsize); numcleanpages += btoc(bp->b_bufsize); } binsheadfree(bp, bufq); } else { /* * It has valid data. Put it on the end of the appropriate * queue, so that it'll stick around for as long as possible. */ if (ISSET(bp->b_flags, B_LOCKED)) /* locked in core */ bufq = &bufqueues[BQ_LOCKED]; else { numfreepages += btoc(bp->b_bufsize); if (!ISSET(bp->b_flags, B_DELWRI)) { numcleanpages += btoc(bp->b_bufsize); bufq = &bufqueues[BQ_CLEAN]; } else { numdirtypages += btoc(bp->b_bufsize); bufq = &bufqueues[BQ_DIRTY]; } } if (ISSET(bp->b_flags, B_AGE)) binsheadfree(bp, bufq); else binstailfree(bp, bufq); } /* Unlock the buffer. */ CLR(bp->b_flags, (B_AGE | B_ASYNC | B_BUSY | B_NOCACHE | B_DEFERRED)); /* Wake up syncer and cleaner processes waiting for buffers */ if (nobuffers) { wakeup(&nobuffers); nobuffers = 0; } /* Wake up any processes waiting for any buffer to become free. */ if (needbuffer && (numcleanpages > locleanpages)) { needbuffer--; wakeup_one(&needbuffer); } splx(s); /* Wake up any processes waiting for _this_ buffer to become free. */ if (ISSET(bp->b_flags, B_WANTED)) { CLR(bp->b_flags, B_WANTED); wakeup(bp); } }
/* * Release a buffer on to the free lists. * Described in Bach (p. 46). */ void brelse(struct buf *bp) { int s; s = splbio(); if (bp->b_data != NULL) KASSERT(bp->b_bufsize > 0); /* * Determine which queue the buffer should be on, then put it there. */ /* If it's not cacheable, or an error, mark it invalid. */ if (ISSET(bp->b_flags, (B_NOCACHE|B_ERROR))) SET(bp->b_flags, B_INVAL); if (ISSET(bp->b_flags, B_INVAL)) { /* * If the buffer is invalid, free it now rather than leaving * it in a queue and wasting memory. */ if (LIST_FIRST(&bp->b_dep) != NULL) buf_deallocate(bp); if (ISSET(bp->b_flags, B_DELWRI)) { CLR(bp->b_flags, B_DELWRI); } if (bp->b_vp) { RB_REMOVE(buf_rb_bufs, &bp->b_vp->v_bufs_tree, bp); brelvp(bp); } bp->b_vp = NULL; /* * Wake up any processes waiting for _this_ buffer to * become free. They are not allowed to grab it * since it will be freed. But the only sleeper is * getblk and it will restart the operation after * sleep. */ if (ISSET(bp->b_flags, B_WANTED)) { CLR(bp->b_flags, B_WANTED); wakeup(bp); } buf_put(bp); } else { /* * It has valid data. Put it on the end of the appropriate * queue, so that it'll stick around for as long as possible. */ bufcache_release(bp); /* Unlock the buffer. */ CLR(bp->b_flags, (B_AGE | B_ASYNC | B_NOCACHE | B_DEFERRED)); buf_release(bp); /* Wake up any processes waiting for _this_ buffer to * become free. */ if (ISSET(bp->b_flags, B_WANTED)) { CLR(bp->b_flags, B_WANTED); wakeup(bp); } } /* Wake up syncer and cleaner processes waiting for buffers. */ if (nobuffers) { nobuffers = 0; wakeup(&nobuffers); } /* Wake up any processes waiting for any buffer to become free. */ if (needbuffer && bcstats.numbufpages < targetpages && bcstats.kvaslots_avail > RESERVE_SLOTS) { needbuffer = 0; wakeup(&needbuffer); } splx(s); }