1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-16 15:11:52 +00:00

Two critical bugfixes:

1) "obj" was't initialized properly, resulting in an important vm_page_lookup
   always failing (resulting in a panic).
2) busy pages could be put on the cache queue or freed (resulting in a panic).
This commit is contained in:
David Greenman 1995-10-01 05:50:27 +00:00
parent 1a44ab0cf5
commit 7329854ac4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=11101

View File

@ -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.63 1995/09/09 18:10:14 davidg Exp $
* $Id: vfs_bio.c,v 1.64 1995/09/23 21:12:43 dyson Exp $
*/
/*
@ -428,55 +428,53 @@ brelse(struct buf * bp)
vm_object_t obj;
int i, resid;
vm_page_t m;
struct vnode *vp;
int iototal = bp->b_bufsize;
foff = 0;
obj = 0;
vp = bp->b_vp;
if (!vp)
panic("brelse: missing vp");
if (!vp->v_mount)
panic("brelse: missing mount info");
if (bp->b_npages) {
if (bp->b_vp && bp->b_vp->v_mount) {
foff = bp->b_vp->v_mount->mnt_stat.f_iosize * bp->b_lblkno;
} else {
/*
* vnode pointer has been ripped away --
* probably file gone...
*/
foff = bp->b_pages[0]->offset;
}
}
for (i = 0; i < bp->b_npages; i++) {
m = bp->b_pages[i];
if (m == bogus_page) {
m = vm_page_lookup(obj, foff);
if (!m) {
panic("brelse: page missing\n");
obj = (vm_object_t) vp->v_object;
foff = trunc_page(vp->v_mount->mnt_stat.f_iosize * bp->b_lblkno);
for (i = 0; i < bp->b_npages; i++) {
m = bp->b_pages[i];
if (m == bogus_page) {
m = vm_page_lookup(obj, foff);
if (!m) {
panic("brelse: page missing\n");
}
bp->b_pages[i] = m;
pmap_qenter(trunc_page(bp->b_data), bp->b_pages, bp->b_npages);
}
bp->b_pages[i] = m;
pmap_qenter(trunc_page(bp->b_data), bp->b_pages, bp->b_npages);
}
resid = (m->offset + PAGE_SIZE) - foff;
if (resid > iototal)
resid = iototal;
if (resid > 0) {
/*
* Don't invalidate the page if the local machine has already
* modified it. This is the lesser of two evils, and should
* be fixed.
*/
if (bp->b_flags & (B_NOCACHE | B_ERROR)) {
vm_page_test_dirty(m);
if (m->dirty == 0) {
vm_page_set_invalid(m, foff, resid);
if (m->valid == 0)
vm_page_protect(m, VM_PROT_NONE);
resid = (m->offset + PAGE_SIZE) - foff;
if (resid > iototal)
resid = iototal;
if (resid > 0) {
/*
* Don't invalidate the page if the local machine has already
* modified it. This is the lesser of two evils, and should
* be fixed.
*/
if (bp->b_flags & (B_NOCACHE | B_ERROR)) {
vm_page_test_dirty(m);
if (m->dirty == 0) {
vm_page_set_invalid(m, foff, resid);
if (m->valid == 0)
vm_page_protect(m, VM_PROT_NONE);
}
}
}
foff += resid;
iototal -= resid;
}
foff += resid;
iototal -= resid;
}
if (bp->b_flags & (B_INVAL | B_RELBUF)) {
for(i=0;i<bp->b_npages;i++) {
for(i = 0; i < bp->b_npages; i++) {
m = bp->b_pages[i];
--m->bmapped;
if (m->bmapped == 0) {
@ -484,27 +482,29 @@ brelse(struct buf * bp)
wakeup(m);
m->flags &= ~PG_WANTED;
}
vm_page_test_dirty(m);
/*
* if page isn't valid, no sense in keeping it around
*/
if (m->valid == 0) {
pmap_page_protect(VM_PAGE_TO_PHYS(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;
if ((m->busy == 0) && ((m->flags & PG_BUSY) == 0)) {
vm_page_test_dirty(m);
/*
* 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;
}
}
}
}