summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_bio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/vfs_bio.c')
-rw-r--r--sys/kern/vfs_bio.c319
1 files changed, 166 insertions, 153 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 829a796..c6adf9a 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -18,7 +18,7 @@
* 5. Modifications may be freely made to this file if the above conditions
* are met.
*
- * $Id: vfs_bio.c,v 1.82 1996/01/06 23:23:02 davidg Exp $
+ * $Id: vfs_bio.c,v 1.83 1996/01/06 23:58:03 davidg Exp $
*/
/*
@@ -78,6 +78,7 @@ static void vm_hold_load_pages(struct buf * bp, vm_offset_t from,
vm_offset_t to);
static void vfs_clean_pages(struct buf * bp);
static void vfs_setdirty(struct buf *bp);
+static void vfs_vmio_release(struct buf *bp);
int needsbuffer;
@@ -108,6 +109,8 @@ static int bufspace, maxbufspace;
static struct bufhashhdr bufhashtbl[BUFHSZ], invalhash;
static struct bqueues bufqueues[BUFFER_QUEUES];
+extern int vm_swap_size;
+
#define BUF_MAXUSE 8
/*
@@ -363,7 +366,7 @@ bdwrite(struct buf * bp)
* out on the next sync, or perhaps the cluster will be completed.
*/
vfs_clean_pages(bp);
- brelse(bp);
+ bqrelse(bp);
return;
}
@@ -412,8 +415,11 @@ brelse(struct buf * bp)
(bp->b_bufsize <= 0)) {
bp->b_flags |= B_INVAL;
bp->b_flags &= ~(B_DELWRI | B_CACHE);
- if (((bp->b_flags & B_VMIO) == 0) && bp->b_vp)
+ if (((bp->b_flags & B_VMIO) == 0) && bp->b_vp) {
+ if (bp->b_bufsize)
+ allocbuf(bp, 0);
brelvp(bp);
+ }
}
/*
@@ -470,57 +476,23 @@ brelse(struct buf * bp)
vm_page_protect(m, VM_PROT_NONE);
}
}
- }
- foff += resid;
- iototal -= resid;
- }
- }
-
- if (bp->b_flags & (B_INVAL | B_RELBUF)) {
- for(i = 0; i < bp->b_npages; i++) {
- m = bp->b_pages[i];
- --m->bmapped;
- if (m->bmapped == 0) {
- if (m->flags & PG_WANTED) {
- m->flags &= ~PG_WANTED;
- wakeup(m);
- }
- if ((m->busy == 0) && ((m->flags & PG_BUSY) == 0)) {
- if (m->object->flags & OBJ_MIGHTBEDIRTY) {
- vm_page_test_dirty(m);
+ if (resid >= PAGE_SIZE) {
+ if ((m->valid & VM_PAGE_BITS_ALL) != VM_PAGE_BITS_ALL) {
+ bp->b_flags |= B_INVAL;
}
- /*
- * if page isn't valid, no sense in keeping it around
- */
- if (m->valid == 0) {
- vm_page_protect(m, VM_PROT_NONE);
- vm_page_free(m);
- /*
- * if page isn't dirty and hasn't been referenced by
- * a process, then cache it
- */
- } else if ((m->dirty & m->valid) == 0 &&
- (m->flags & PG_REFERENCED) == 0 &&
- !pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
- vm_page_cache(m);
- /*
- * otherwise activate it
- */
- } else if ((m->flags & PG_ACTIVE) == 0) {
- vm_page_activate(m);
- m->act_count = 0;
+ } else {
+ if (!vm_page_is_valid(m,
+ (((vm_offset_t) bp->b_data) & PAGE_MASK), resid)) {
+ bp->b_flags |= B_INVAL;
}
}
}
+ foff += resid;
+ iototal -= resid;
}
- bufspace -= bp->b_bufsize;
- pmap_qremove(trunc_page((vm_offset_t) bp->b_data), bp->b_npages);
- bp->b_npages = 0;
- bp->b_bufsize = 0;
- bp->b_flags &= ~B_VMIO;
- if (bp->b_vp)
- brelvp(bp);
}
+ if (bp->b_flags & (B_INVAL | B_RELBUF))
+ vfs_vmio_release(bp);
}
if (bp->b_qindex != QUEUE_NONE)
panic("brelse: free buffer onto another queue???");
@@ -560,6 +532,85 @@ brelse(struct buf * bp)
}
/*
+ * Release a buffer.
+ */
+void
+bqrelse(struct buf * bp)
+{
+ int s;
+
+ s = splbio();
+
+ if (needsbuffer) {
+ needsbuffer = 0;
+ wakeup(&needsbuffer);
+ }
+
+ /* anyone need this block? */
+ if (bp->b_flags & B_WANTED) {
+ bp->b_flags &= ~(B_WANTED | B_AGE);
+ wakeup(bp);
+ }
+
+ if (bp->b_qindex != QUEUE_NONE)
+ panic("bqrelse: free buffer onto another queue???");
+
+ if (bp->b_flags & B_LOCKED) {
+ bp->b_flags &= ~B_ERROR;
+ bp->b_qindex = QUEUE_LOCKED;
+ TAILQ_INSERT_TAIL(&bufqueues[QUEUE_LOCKED], bp, b_freelist);
+ /* buffers with stale but valid contents */
+ } else {
+ bp->b_qindex = QUEUE_LRU;
+ TAILQ_INSERT_TAIL(&bufqueues[QUEUE_LRU], bp, b_freelist);
+ }
+
+ /* unlock */
+ bp->b_flags &= ~(B_WANTED | B_BUSY | B_ASYNC | B_NOCACHE | B_AGE | B_RELBUF);
+ splx(s);
+}
+
+static void
+vfs_vmio_release(bp)
+ struct buf *bp;
+{
+ int i;
+ vm_page_t m;
+
+ for (i = 0; i < bp->b_npages; i++) {
+ m = bp->b_pages[i];
+ bp->b_pages[i] = NULL;
+ if (m->flags & PG_WANTED) {
+ m->flags &= ~PG_WANTED;
+ wakeup(m);
+ }
+ vm_page_unwire(m);
+ if (m->wire_count == 0) {
+ if (m->valid) {
+ /*
+ * this keeps pressure off of the process memory
+ */
+ if ((vm_swap_size == 0) ||
+ (cnt.v_free_count < cnt.v_free_min))
+ vm_page_cache(m);
+ } else if ((m->hold_count == 0) &&
+ ((m->flags & PG_BUSY) == 0) &&
+ (m->busy == 0)) {
+ vm_page_protect(m, VM_PROT_NONE);
+ vm_page_free(m);
+ }
+ }
+ }
+ bufspace -= bp->b_bufsize;
+ pmap_qremove(trunc_page((vm_offset_t) bp->b_data), bp->b_npages);
+ bp->b_npages = 0;
+ bp->b_bufsize = 0;
+ bp->b_flags &= ~B_VMIO;
+ if (bp->b_vp)
+ brelvp(bp);
+}
+
+/*
* Check to see if a block is currently memory resident.
*/
__inline struct buf *
@@ -666,6 +717,7 @@ start:
if (bp->b_qindex != QUEUE_EMPTY)
panic("getnewbuf: inconsistent EMPTY queue, qindex=%d",
bp->b_qindex);
+ bp->b_flags |= B_BUSY;
bremfree(bp);
goto fillbuf;
}
@@ -717,12 +769,10 @@ trytofreespace:
wakeup(bp);
}
bremfree(bp);
+ bp->b_flags |= B_BUSY;
- if (bp->b_flags & B_VMIO) {
- bp->b_flags |= B_RELBUF | B_BUSY | B_DONE;
- brelse(bp);
- bremfree(bp);
- }
+ if (bp->b_flags & B_VMIO)
+ vfs_vmio_release(bp);
if (bp->b_vp)
brelvp(bp);
@@ -737,7 +787,7 @@ fillbuf:
crfree(bp->b_wcred);
bp->b_wcred = NOCRED;
}
- bp->b_flags |= B_BUSY;
+
LIST_REMOVE(bp, b_hash);
LIST_INSERT_HEAD(&invalhash, bp, b_hash);
splx(s);
@@ -776,19 +826,7 @@ incore(struct vnode * vp, daddr_t blkno)
struct bufhashhdr *bh;
int s = splbio();
-
- bh = BUFHASH(vp, blkno);
- bp = bh->lh_first;
-
- /* Search hash chain */
- while (bp != NULL) {
- /* hit */
- if (bp->b_vp == vp && bp->b_lblkno == blkno &&
- (bp->b_flags & B_INVAL) == 0) {
- break;
- }
- bp = bp->b_hash.le_next;
- }
+ bp = gbincore(vp, blkno);
splx(s);
return (bp);
}
@@ -933,35 +971,6 @@ loop:
}
}
- /*
- * make sure that all pages in the buffer are valid, if they
- * aren't, clear the cache flag.
- * ASSUMPTION:
- * if the buffer is greater than 1 page in size, it is assumed
- * that the buffer address starts on a page boundary...
- */
- if (bp->b_flags & B_VMIO) {
- int szleft, i;
- szleft = size;
- for (i=0;i<bp->b_npages;i++) {
- if (szleft > PAGE_SIZE) {
- if ((bp->b_pages[i]->valid & VM_PAGE_BITS_ALL) !=
- VM_PAGE_BITS_ALL) {
- bp->b_flags &= ~(B_CACHE|B_DONE);
- break;
- }
- szleft -= PAGE_SIZE;
- } else {
- if (!vm_page_is_valid(bp->b_pages[i],
- (((vm_offset_t) bp->b_data) & PAGE_MASK),
- szleft)) {
- bp->b_flags &= ~(B_CACHE|B_DONE);
- break;
- }
- szleft = 0;
- }
- }
- }
if (bp->b_usecount < BUF_MAXUSE)
++bp->b_usecount;
splx(s);
@@ -1035,6 +1044,7 @@ geteblk(int size)
return (bp);
}
+
/*
* This code constitutes the buffer memory from either anonymous system
* memory (in the case of non-VMIO operations) or from an associated
@@ -1084,9 +1094,11 @@ allocbuf(struct buf * bp, int size)
if (newbsize < bp->b_bufsize) {
if (desiredpages < bp->b_npages) {
- pmap_qremove((vm_offset_t) trunc_page(bp->b_data) +
- (desiredpages << PAGE_SHIFT), (bp->b_npages - desiredpages));
for (i = desiredpages; i < bp->b_npages; i++) {
+ /*
+ * the page is not freed here -- it
+ * is the responsibility of vnode_pager_setsize
+ */
m = bp->b_pages[i];
s = splhigh();
while ((m->flags & PG_BUSY) || (m->busy != 0)) {
@@ -1095,17 +1107,11 @@ allocbuf(struct buf * bp, int size)
}
splx(s);
- if (m->bmapped == 0) {
- printf("allocbuf: bmapped is zero for page %d\n", i);
- panic("allocbuf: error");
- }
- --m->bmapped;
- if (m->bmapped == 0) {
- vm_page_protect(m, VM_PROT_NONE);
- vm_page_free(m);
- }
bp->b_pages[i] = NULL;
+ vm_page_unwire(m);
}
+ pmap_qremove((vm_offset_t) trunc_page(bp->b_data) +
+ (desiredpages << PAGE_SHIFT), (bp->b_npages - desiredpages));
bp->b_npages = desiredpages;
}
} else if (newbsize > bp->b_bufsize) {
@@ -1141,46 +1147,39 @@ allocbuf(struct buf * bp, int size)
if (pageindex < curbpnpages) {
m = bp->b_pages[pageindex];
+#ifdef VFS_BIO_DIAG
if (m->pindex != objoff)
panic("allocbuf: page changed offset??!!!?");
+#endif
bytesinpage = tinc;
if (tinc > (newbsize - toff))
bytesinpage = newbsize - toff;
- if (!vm_page_is_valid(m,
+ if ((bp->b_flags & B_CACHE) &&
+ !vm_page_is_valid(m,
(vm_offset_t) ((toff + off) & (PAGE_SIZE - 1)),
bytesinpage)) {
bp->b_flags &= ~B_CACHE;
}
- if ((m->flags & PG_ACTIVE) == 0) {
- vm_page_activate(m);
- m->act_count = 0;
- }
continue;
}
m = vm_page_lookup(obj, objoff);
if (!m) {
m = vm_page_alloc(obj, objoff, VM_ALLOC_NORMAL);
if (!m) {
- int j;
-
- for (j = bp->b_npages; j < pageindex; j++) {
- PAGE_WAKEUP(bp->b_pages[j]);
- }
VM_WAIT;
goto doretry;
}
- vm_page_activate(m);
- m->act_count = 0;
- m->valid = 0;
+ /*
+ * Normally it is unwise to clear PG_BUSY without
+ * PAGE_WAKEUP -- but it is okay here, as there is
+ * no chance for blocking between here and vm_page_alloc
+ */
+ m->flags &= ~PG_BUSY;
+ vm_page_wire(m);
bp->b_flags &= ~B_CACHE;
} else if (m->flags & PG_BUSY) {
- int j;
-
- for (j = bp->b_npages; j < pageindex; j++) {
- PAGE_WAKEUP(bp->b_pages[j]);
- }
- s = splbio();
+ s = splhigh();
m->flags |= PG_WANTED;
tsleep(m, PVM, "pgtblk", 0);
splx(s);
@@ -1188,36 +1187,33 @@ allocbuf(struct buf * bp, int size)
goto doretry;
} else {
if ((curproc != pageproc) &&
- (m->flags & PG_CACHE) &&
- (cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min) {
+ (m->queue == PQ_CACHE) &&
+ ((cnt.v_free_count + cnt.v_cache_count) <
+ (cnt.v_free_min + cnt.v_cache_min))) {
pagedaemon_wakeup();
}
bytesinpage = tinc;
if (tinc > (newbsize - toff))
bytesinpage = newbsize - toff;
- if (!vm_page_is_valid(m,
+ if ((bp->b_flags & B_CACHE) &&
+ !vm_page_is_valid(m,
(vm_offset_t) ((toff + off) & (PAGE_SIZE - 1)),
bytesinpage)) {
bp->b_flags &= ~B_CACHE;
}
- if ((m->flags & PG_ACTIVE) == 0) {
- vm_page_activate(m);
- m->act_count = 0;
- }
- m->flags |= PG_BUSY;
+ vm_page_wire(m);
}
bp->b_pages[pageindex] = m;
curbpnpages = pageindex + 1;
}
- for (i = bp->b_npages; i < curbpnpages; i++) {
- m = bp->b_pages[i];
- m->bmapped++;
- PAGE_WAKEUP(m);
- }
- bp->b_npages = curbpnpages;
+/*
bp->b_data = buffers_kva + (bp - buf) * MAXBSIZE;
- pmap_qenter((vm_offset_t) bp->b_data, bp->b_pages, bp->b_npages);
- bp->b_data += off & (PAGE_SIZE - 1);
+*/
+ bp->b_data = (caddr_t) trunc_page(bp->b_data);
+ bp->b_npages = curbpnpages;
+ pmap_qenter((vm_offset_t) bp->b_data,
+ bp->b_pages, bp->b_npages);
+ ((vm_offset_t) bp->b_data) |= off & (PAGE_SIZE - 1);
}
}
}
@@ -1363,8 +1359,8 @@ biodone(register struct buf * bp)
printf(" VDEV, lblkno: %d, flags: 0x%lx, npages: %d\n",
(int) bp->b_lblkno,
bp->b_flags, bp->b_npages);
- printf(" valid: 0x%x, dirty: 0x%x, mapped: %d\n",
- m->valid, m->dirty, m->bmapped);
+ printf(" valid: 0x%x, dirty: 0x%x, wired: %d\n",
+ m->valid, m->dirty, m->wire_count);
panic("biodone: page busy < 0\n");
}
--m->busy;
@@ -1389,7 +1385,10 @@ biodone(register struct buf * bp)
*/
if (bp->b_flags & B_ASYNC) {
- brelse(bp);
+ if ((bp->b_flags & (B_NOCACHE | B_INVAL | B_ERROR | B_RELBUF)) != 0)
+ brelse(bp);
+ else
+ bqrelse(bp);
} else {
wakeup(bp);
}
@@ -1568,6 +1567,7 @@ vfs_clean_pages(struct buf * bp)
void
vfs_bio_clrbuf(struct buf *bp) {
int i;
+ int remapbuffer = 0;
if( bp->b_flags & B_VMIO) {
if( (bp->b_npages == 1) && (bp->b_bufsize < PAGE_SIZE)) {
int mask;
@@ -1585,8 +1585,9 @@ vfs_bio_clrbuf(struct buf *bp) {
if( bp->b_pages[i]->valid == VM_PAGE_BITS_ALL)
continue;
if( bp->b_pages[i]->valid == 0) {
- if ((bp->b_pages[i]->flags & PG_ZERO) == 0)
+ if ((bp->b_pages[i]->flags & PG_ZERO) == 0) {
bzero(bp->b_data + (i << PAGE_SHIFT), PAGE_SIZE);
+ }
} else {
int j;
for(j=0;j<PAGE_SIZE/DEV_BSIZE;j++) {
@@ -1600,6 +1601,8 @@ vfs_bio_clrbuf(struct buf *bp) {
} else {
clrbuf(bp);
}
+ if (remapbuffer)
+ pmap_qenter(trunc_page(bp->b_data), bp->b_pages, bp->b_npages);
}
/*
@@ -1612,10 +1615,13 @@ vm_hold_load_pages(struct buf * bp, vm_offset_t from, vm_offset_t to)
{
vm_offset_t pg;
vm_page_t p;
+ int index;
to = round_page(to);
+ from = round_page(from);
+ index = (from - trunc_page(bp->b_data)) >> PAGE_SHIFT;
- for (pg = round_page(from); pg < to; pg += PAGE_SIZE) {
+ for (pg = from; pg < to; pg += PAGE_SIZE, index++) {
tryagain:
@@ -1627,10 +1633,10 @@ tryagain:
}
vm_page_wire(p);
pmap_kenter(pg, VM_PAGE_TO_PHYS(p));
- bp->b_pages[(pg - trunc_page(bp->b_data)) >> PAGE_SHIFT] = p;
+ bp->b_pages[index] = p;
PAGE_WAKEUP(p);
- bp->b_npages++;
}
+ bp->b_npages = to >> PAGE_SHIFT;
}
void
@@ -1646,9 +1652,16 @@ vm_hold_free_pages(struct buf * bp, vm_offset_t from, vm_offset_t to)
for (pg = from; pg < to; pg += PAGE_SIZE, index++) {
p = bp->b_pages[index];
- bp->b_pages[index] = 0;
- pmap_kremove(pg);
- vm_page_free(p);
- --bp->b_npages;
+ if (p && (index < bp->b_npages)) {
+ if (p->busy) {
+ printf("vm_hold_free_pages: blkno: %d, lblkno: %d\n",
+ bp->b_blkno, bp->b_lblkno);
+ }
+ bp->b_pages[index] = NULL;
+ pmap_kremove(pg);
+ vm_page_unwire(p);
+ vm_page_free(p);
+ }
}
+ bp->b_npages = from >> PAGE_SHIFT;
}
OpenPOWER on IntegriCloud