diff options
-rw-r--r-- | sys/alpha/alpha/pmap.c | 26 | ||||
-rw-r--r-- | sys/amd64/amd64/pmap.c | 60 | ||||
-rw-r--r-- | sys/fs/specfs/spec_vnops.c | 16 | ||||
-rw-r--r-- | sys/i386/i386/pmap.c | 60 | ||||
-rw-r--r-- | sys/kern/vfs_bio.c | 18 | ||||
-rw-r--r-- | sys/miscfs/specfs/spec_vnops.c | 16 | ||||
-rw-r--r-- | sys/nfs/nfs_bio.c | 56 | ||||
-rw-r--r-- | sys/nfsclient/nfs_bio.c | 56 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_readwrite.c | 23 | ||||
-rw-r--r-- | sys/vm/pmap.h | 3 | ||||
-rw-r--r-- | sys/vm/vm_page.c | 156 | ||||
-rw-r--r-- | sys/vm/vm_page.h | 3 | ||||
-rw-r--r-- | sys/vm/vnode_pager.c | 33 |
13 files changed, 440 insertions, 86 deletions
diff --git a/sys/alpha/alpha/pmap.c b/sys/alpha/alpha/pmap.c index 7c42f95..7b32081 100644 --- a/sys/alpha/alpha/pmap.c +++ b/sys/alpha/alpha/pmap.c @@ -43,7 +43,7 @@ * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91 * from: i386 Id: pmap.c,v 1.193 1998/04/19 15:22:48 bde Exp * with some ideas from NetBSD's alpha pmap - * $Id: pmap.c,v 1.14 1999/01/24 06:04:50 dillon Exp $ + * $Id: pmap.c,v 1.15 1999/02/19 14:25:32 luoqi Exp $ */ /* @@ -2523,11 +2523,11 @@ pmap_kernel() } /* - * pmap_zero_page zeros the specified (machine independent) - * page by mapping the page into virtual memory and using - * bzero to clear its contents, one machine dependent page - * at a time. + * pmap_zero_page zeros the specified hardware page by + * mapping it into virtual memory and using bzero to clear + * its contents. */ + void pmap_zero_page(vm_offset_t pa) { @@ -2535,6 +2535,22 @@ pmap_zero_page(vm_offset_t pa) bzero((caddr_t) va, PAGE_SIZE); } + +/* + * pmap_zero_page_area zeros the specified hardware page by + * mapping it into virtual memory and using bzero to clear + * its contents. + * + * off and size must reside within a single page. + */ + +void +pmap_zero_page_area(vm_offset_t pa, int off, int size) +{ + vm_offset_t va = ALPHA_PHYS_TO_K0SEG(pa); + bzero((char *)(caddr_t)va + off, size); +} + /* * pmap_copy_page copies the specified (machine independent) * page by mapping the page into virtual memory and using diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index ec6c00c..c630306 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -39,7 +39,7 @@ * SUCH DAMAGE. * * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91 - * $Id: pmap.c,v 1.225 1999/03/13 07:31:29 alc Exp $ + * $Id: pmap.c,v 1.226 1999/04/02 17:59:38 alc Exp $ */ /* @@ -2818,10 +2818,8 @@ pmap_kernel() } /* - * pmap_zero_page zeros the specified (machine independent) - * page by mapping the page into virtual memory and using - * bzero to clear its contents, one machine dependent page - * at a time. + * pmap_zero_page zeros the specified hardware page by mapping + * the page into KVM and using bzero to clear its contents. */ void pmap_zero_page(phys) @@ -2868,6 +2866,58 @@ pmap_zero_page(phys) } /* + * pmap_zero_page_area zeros the specified hardware page by mapping + * the page into KVM and using bzero to clear its contents. + * + * off and size may not cover an area beyond a single hardware page. + */ +void +pmap_zero_page_area(phys, off, size) + vm_offset_t phys; + int off; + int size; +{ +#ifdef SMP +#if !defined(MAX_PERF) + if (*(int *) prv_CMAP3) + panic("pmap_zero_page: prv_CMAP3 busy"); +#endif + + *(int *) prv_CMAP3 = PG_V | PG_RW | (phys & PG_FRAME) | PG_A | PG_M; + cpu_invlpg(&prv_CPAGE3); + +#if defined(I686_CPU) + if (cpu_class == CPUCLASS_686 && off == 0 && size == PAGE_SIZE) + i686_pagezero(&prv_CPAGE3); + else +#endif + bzero((char *)&prv_CPAGE3 + off, size); + + *(int *) prv_CMAP3 = 0; +#else +#if !defined(MAX_PERF) + if (*(int *) CMAP2) + panic("pmap_zero_page: CMAP2 busy"); +#endif + + *(int *) CMAP2 = PG_V | PG_RW | (phys & PG_FRAME) | PG_A | PG_M; + if (cpu_class == CPUCLASS_386) { + invltlb(); + } else { + invlpg((u_int)CADDR2); + } + +#if defined(I686_CPU) + if (cpu_class == CPUCLASS_686 && off == 0 && size == PAGE_SIZE) + i686_pagezero(CADDR2); + else +#endif + bzero((char *)CADDR2 + off, size); + *(int *) CMAP2 = 0; +#endif +} + +/* * pmap_copy_page copies the specified (machine independent) * page by mapping the page into virtual memory and using * bcopy to copy the page, one machine dependent page at a diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c index 3f29d9362..7f76209 100644 --- a/sys/fs/specfs/spec_vnops.c +++ b/sys/fs/specfs/spec_vnops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95 - * $Id: spec_vnops.c,v 1.80 1999/01/27 22:42:07 dillon Exp $ + * $Id: spec_vnops.c,v 1.81 1999/02/25 05:22:30 dillon Exp $ */ #include <sys/param.h> @@ -866,8 +866,12 @@ spec_getpages(ap) m->valid = VM_PAGE_BITS_ALL; m->dirty = 0; } else if (toff < nread) { - int nvalid = ((nread + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1); - vm_page_set_validclean(m, 0, nvalid); + /* + * Since this is a VM request, we have to supply the + * unaligned offset to allow vm_page_set_validclean() + * to zero sub-DEV_BSIZE'd portions of the page. + */ + vm_page_set_validclean(m, 0, nread - toff); } else { m->valid = 0; m->dirty = 0; @@ -894,6 +898,12 @@ spec_getpages(ap) } } else if (m->valid) { gotreqpage = 1; + /* + * Since this is a VM request, we need to make the + * entire page presentable by zeroing invalid sections. + */ + if (m->valid != VM_PAGE_BITS_ALL) + vm_page_zero_invalid(m, FALSE); } } if (!gotreqpage) { diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index ec6c00c..c630306 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -39,7 +39,7 @@ * SUCH DAMAGE. * * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91 - * $Id: pmap.c,v 1.225 1999/03/13 07:31:29 alc Exp $ + * $Id: pmap.c,v 1.226 1999/04/02 17:59:38 alc Exp $ */ /* @@ -2818,10 +2818,8 @@ pmap_kernel() } /* - * pmap_zero_page zeros the specified (machine independent) - * page by mapping the page into virtual memory and using - * bzero to clear its contents, one machine dependent page - * at a time. + * pmap_zero_page zeros the specified hardware page by mapping + * the page into KVM and using bzero to clear its contents. */ void pmap_zero_page(phys) @@ -2868,6 +2866,58 @@ pmap_zero_page(phys) } /* + * pmap_zero_page_area zeros the specified hardware page by mapping + * the page into KVM and using bzero to clear its contents. + * + * off and size may not cover an area beyond a single hardware page. + */ +void +pmap_zero_page_area(phys, off, size) + vm_offset_t phys; + int off; + int size; +{ +#ifdef SMP +#if !defined(MAX_PERF) + if (*(int *) prv_CMAP3) + panic("pmap_zero_page: prv_CMAP3 busy"); +#endif + + *(int *) prv_CMAP3 = PG_V | PG_RW | (phys & PG_FRAME) | PG_A | PG_M; + cpu_invlpg(&prv_CPAGE3); + +#if defined(I686_CPU) + if (cpu_class == CPUCLASS_686 && off == 0 && size == PAGE_SIZE) + i686_pagezero(&prv_CPAGE3); + else +#endif + bzero((char *)&prv_CPAGE3 + off, size); + + *(int *) prv_CMAP3 = 0; +#else +#if !defined(MAX_PERF) + if (*(int *) CMAP2) + panic("pmap_zero_page: CMAP2 busy"); +#endif + + *(int *) CMAP2 = PG_V | PG_RW | (phys & PG_FRAME) | PG_A | PG_M; + if (cpu_class == CPUCLASS_386) { + invltlb(); + } else { + invlpg((u_int)CADDR2); + } + +#if defined(I686_CPU) + if (cpu_class == CPUCLASS_686 && off == 0 && size == PAGE_SIZE) + i686_pagezero(CADDR2); + else +#endif + bzero((char *)CADDR2 + off, size); + *(int *) CMAP2 = 0; +#endif +} + +/* * pmap_copy_page copies the specified (machine independent) * page by mapping the page into virtual memory and using * bcopy to copy the page, one machine dependent page at a diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 1741488..3cc6b94 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -11,7 +11,7 @@ * 2. Absolutely no warranty of function or purpose is made by the author * John S. Dyson. * - * $Id: vfs_bio.c,v 1.202 1999/03/12 02:24:56 julian Exp $ + * $Id: vfs_bio.c,v 1.203 1999/03/19 10:17:44 bde Exp $ */ /* @@ -2489,21 +2489,37 @@ vfs_page_set_valid(struct buf *bp, vm_ooffset_t off, int pageno, vm_page_t m) struct vnode *vp = bp->b_vp; vm_ooffset_t soff, eoff; + /* + * Start and end offsets in buffer. eoff - soff may not cross a + * page boundry or cross the end of the buffer. + */ soff = off; eoff = (off + PAGE_SIZE) & ~PAGE_MASK; if (eoff > bp->b_offset + bp->b_bufsize) eoff = bp->b_offset + bp->b_bufsize; + if (vp->v_tag == VT_NFS && vp->v_type != VBLK) { vm_ooffset_t sv, ev; vm_page_set_invalid(m, (vm_offset_t) (soff & PAGE_MASK), (vm_offset_t) (eoff - soff)); + /* + * bp->b_validoff and bp->b_validend restrict the valid range + * that we can set. Note that these offsets are not DEV_BSIZE + * aligned. vm_page_set_validclean() must know what + * sub-DEV_BSIZE ranges to clear. + */ +#if 0 sv = (bp->b_offset + bp->b_validoff + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); ev = (bp->b_offset + bp->b_validend + (DEV_BSIZE - 1)) & ~(DEV_BSIZE - 1); +#endif + sv = bp->b_offset + bp->b_validoff; + ev = bp->b_offset + bp->b_validend; soff = qmax(sv, soff); eoff = qmin(ev, eoff); } + if (eoff > soff) vm_page_set_validclean(m, (vm_offset_t) (soff & PAGE_MASK), diff --git a/sys/miscfs/specfs/spec_vnops.c b/sys/miscfs/specfs/spec_vnops.c index 3f29d9362..7f76209 100644 --- a/sys/miscfs/specfs/spec_vnops.c +++ b/sys/miscfs/specfs/spec_vnops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95 - * $Id: spec_vnops.c,v 1.80 1999/01/27 22:42:07 dillon Exp $ + * $Id: spec_vnops.c,v 1.81 1999/02/25 05:22:30 dillon Exp $ */ #include <sys/param.h> @@ -866,8 +866,12 @@ spec_getpages(ap) m->valid = VM_PAGE_BITS_ALL; m->dirty = 0; } else if (toff < nread) { - int nvalid = ((nread + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1); - vm_page_set_validclean(m, 0, nvalid); + /* + * Since this is a VM request, we have to supply the + * unaligned offset to allow vm_page_set_validclean() + * to zero sub-DEV_BSIZE'd portions of the page. + */ + vm_page_set_validclean(m, 0, nread - toff); } else { m->valid = 0; m->dirty = 0; @@ -894,6 +898,12 @@ spec_getpages(ap) } } else if (m->valid) { gotreqpage = 1; + /* + * Since this is a VM request, we need to make the + * entire page presentable by zeroing invalid sections. + */ + if (m->valid != VM_PAGE_BITS_ALL) + vm_page_zero_invalid(m, FALSE); } } if (!gotreqpage) { diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c index 2fb5353..1d573ea 100644 --- a/sys/nfs/nfs_bio.c +++ b/sys/nfs/nfs_bio.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95 - * $Id: nfs_bio.c,v 1.66 1999/01/21 08:29:07 dillon Exp $ + * $Id: nfs_bio.c,v 1.67 1999/03/12 02:24:58 julian Exp $ */ @@ -144,6 +144,12 @@ nfs_getpages(ap) return VM_PAGER_ERROR; } + /* + * Calculate the number of bytes read and validate only that number + * of bytes. Note that due to pending writes, size may be 0. This + * does not mean that the remaining data is invalid! + */ + size = count - uio.uio_resid; for (i = 0, toff = 0; i < npages; i++, toff = nextoff) { @@ -154,11 +160,19 @@ nfs_getpages(ap) m->flags &= ~PG_ZERO; if (nextoff <= size) { + /* + * Read operation filled an entire page + */ m->valid = VM_PAGE_BITS_ALL; m->dirty = 0; - } else { - int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1); - vm_page_set_validclean(m, 0, nvalid); + } else if (size > toff) { + /* + * Read operation filled a partial page, set valid + * bits properly. validclean will zero out + * any cruft in the buffer when setting a valid bit, + * if the size is not DEV_BSIZE aligned. + */ + vm_page_set_validclean(m, 0, size - toff); } if (i != ap->a_reqpage) { @@ -183,6 +197,13 @@ nfs_getpages(ap) } else { vnode_pager_freepage(m); } + } else { + /* + * This page is being mapped, clear out any other + * cruft in the invalid areas of the page. + */ + if (m->valid && m->valid != VM_PAGE_BITS_ALL) + vm_page_zero_invalid(m, FALSE); } } return 0; @@ -784,8 +805,16 @@ again: } np->n_flag |= NMODIFIED; + /* + * If dirtyend exceeds file size, chop it down. If this + * creates a reverse-indexed or degenerate situation with + * dirtyoff/end, 0 them. + */ + if ((off_t)bp->b_blkno * DEV_BSIZE + bp->b_dirtyend > np->n_size) bp->b_dirtyend = np->n_size - (off_t)bp->b_blkno * DEV_BSIZE; + if (bp->b_dirtyoff >= bp->b_dirtyend) + bp->b_dirtyoff = bp->b_dirtyend = 0; /* * If the new write will leave a contiguous dirty @@ -838,13 +867,20 @@ again: */ nfs_prot_buf(bp, on, n); - if (bp->b_dirtyend > 0) { - bp->b_dirtyoff = min(on, bp->b_dirtyoff); - bp->b_dirtyend = max((on + n), bp->b_dirtyend); - } else { - bp->b_dirtyoff = on; - bp->b_dirtyend = on + n; + /* + * Only update dirtyoff/dirtyend if not a degenerate + * condition. + */ + if (n) { + if (bp->b_dirtyend > 0) { + bp->b_dirtyoff = min(on, bp->b_dirtyoff); + bp->b_dirtyend = max((on + n), bp->b_dirtyend); + } else { + bp->b_dirtyoff = on; + bp->b_dirtyend = on + n; + } } + /* * To avoid code complexity, we may have to throw away * previously valid ranges when merging the new dirty range diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c index 2fb5353..1d573ea 100644 --- a/sys/nfsclient/nfs_bio.c +++ b/sys/nfsclient/nfs_bio.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95 - * $Id: nfs_bio.c,v 1.66 1999/01/21 08:29:07 dillon Exp $ + * $Id: nfs_bio.c,v 1.67 1999/03/12 02:24:58 julian Exp $ */ @@ -144,6 +144,12 @@ nfs_getpages(ap) return VM_PAGER_ERROR; } + /* + * Calculate the number of bytes read and validate only that number + * of bytes. Note that due to pending writes, size may be 0. This + * does not mean that the remaining data is invalid! + */ + size = count - uio.uio_resid; for (i = 0, toff = 0; i < npages; i++, toff = nextoff) { @@ -154,11 +160,19 @@ nfs_getpages(ap) m->flags &= ~PG_ZERO; if (nextoff <= size) { + /* + * Read operation filled an entire page + */ m->valid = VM_PAGE_BITS_ALL; m->dirty = 0; - } else { - int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1); - vm_page_set_validclean(m, 0, nvalid); + } else if (size > toff) { + /* + * Read operation filled a partial page, set valid + * bits properly. validclean will zero out + * any cruft in the buffer when setting a valid bit, + * if the size is not DEV_BSIZE aligned. + */ + vm_page_set_validclean(m, 0, size - toff); } if (i != ap->a_reqpage) { @@ -183,6 +197,13 @@ nfs_getpages(ap) } else { vnode_pager_freepage(m); } + } else { + /* + * This page is being mapped, clear out any other + * cruft in the invalid areas of the page. + */ + if (m->valid && m->valid != VM_PAGE_BITS_ALL) + vm_page_zero_invalid(m, FALSE); } } return 0; @@ -784,8 +805,16 @@ again: } np->n_flag |= NMODIFIED; + /* + * If dirtyend exceeds file size, chop it down. If this + * creates a reverse-indexed or degenerate situation with + * dirtyoff/end, 0 them. + */ + if ((off_t)bp->b_blkno * DEV_BSIZE + bp->b_dirtyend > np->n_size) bp->b_dirtyend = np->n_size - (off_t)bp->b_blkno * DEV_BSIZE; + if (bp->b_dirtyoff >= bp->b_dirtyend) + bp->b_dirtyoff = bp->b_dirtyend = 0; /* * If the new write will leave a contiguous dirty @@ -838,13 +867,20 @@ again: */ nfs_prot_buf(bp, on, n); - if (bp->b_dirtyend > 0) { - bp->b_dirtyoff = min(on, bp->b_dirtyoff); - bp->b_dirtyend = max((on + n), bp->b_dirtyend); - } else { - bp->b_dirtyoff = on; - bp->b_dirtyend = on + n; + /* + * Only update dirtyoff/dirtyend if not a degenerate + * condition. + */ + if (n) { + if (bp->b_dirtyend > 0) { + bp->b_dirtyoff = min(on, bp->b_dirtyoff); + bp->b_dirtyend = max((on + n), bp->b_dirtyend); + } else { + bp->b_dirtyoff = on; + bp->b_dirtyend = on + n; + } } + /* * To avoid code complexity, we may have to throw away * previously valid ranges when merging the new dirty range diff --git a/sys/ufs/ufs/ufs_readwrite.c b/sys/ufs/ufs/ufs_readwrite.c index 368608b..d12a802 100644 --- a/sys/ufs/ufs/ufs_readwrite.c +++ b/sys/ufs/ufs/ufs_readwrite.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ufs_readwrite.c 8.11 (Berkeley) 5/8/95 - * $Id: ufs_readwrite.c,v 1.56 1999/01/21 08:29:09 dillon Exp $ + * $Id: ufs_readwrite.c,v 1.57 1999/01/28 00:57:56 dillon Exp $ */ #define BLKSIZE(a, b, c) blksize(a, b, c) @@ -189,6 +189,13 @@ READ(ap) lbn = lblkno(fs, uio->uio_offset); nextlbn = lbn + 1; + + /* + * size of buffer. The buffer representing the + * end of the file is rounded up to the size of + * the block type ( fragment or full block, + * depending ). + */ size = BLKSIZE(fs, ip, lbn); blkoffset = blkoff(fs, uio->uio_offset); @@ -536,11 +543,14 @@ ffs_getpages(ap) firstindex = ap->a_m[0]->pindex; /* - * if ANY DEV_BSIZE blocks are valid on a large filesystem block - * then, the entire page is valid -- + * if ANY DEV_BSIZE blocks are valid on a large filesystem block, + * then the entire page is valid. Since the page may be mapped, + * user programs might reference data beyond the actual end of file + * occuring within the page. We have to zero that data. */ if (mreq->valid) { - mreq->valid = VM_PAGE_BITS_ALL; + if (mreq->valid != VM_PAGE_BITS_ALL) + vm_page_zero_invalid(mreq, TRUE); for (i = 0; i < pcount; i++) { if (i != ap->a_reqpage) { vm_page_free(ap->a_m[i]); @@ -568,6 +578,7 @@ ffs_getpages(ap) (firstindex != 0) && (firstindex <= vp->v_lastr) && ((firstindex + pcount) > vp->v_lastr)) || (obj->behavior == OBJ_SEQUENTIAL)) { + struct uio auio; struct iovec aiov; int error; @@ -620,8 +631,8 @@ ffs_getpages(ap) if (mreq->valid == 0) return VM_PAGER_ERROR; - - mreq->valid = VM_PAGE_BITS_ALL; + if (mreq->valid != VM_PAGE_BITS_ALL) + vm_page_zero_invalid(mreq, TRUE); return VM_PAGER_OK; } diff --git a/sys/vm/pmap.h b/sys/vm/pmap.h index 1f35a6f..2fe5c18 100644 --- a/sys/vm/pmap.h +++ b/sys/vm/pmap.h @@ -61,7 +61,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: pmap.h,v 1.27 1998/02/01 20:08:39 bde Exp $ + * $Id: pmap.h,v 1.28 1998/07/26 18:15:20 dfr Exp $ */ /* @@ -129,6 +129,7 @@ void pmap_release __P((pmap_t)); void pmap_remove __P((pmap_t, vm_offset_t, vm_offset_t)); void pmap_remove_pages __P((pmap_t, vm_offset_t, vm_offset_t)); void pmap_zero_page __P((vm_offset_t)); +void pmap_zero_page_area __P((vm_offset_t, int off, int size)); void pmap_prefault __P((pmap_t, vm_offset_t, vm_map_entry_t)); int pmap_mincore __P((pmap_t pmap, vm_offset_t addr)); void pmap_new_proc __P((struct proc *p)); diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index 1cadc5b..e07ea63 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)vm_page.c 7.4 (Berkeley) 5/7/91 - * $Id: vm_page.c,v 1.127 1999/02/24 21:26:26 dillon Exp $ + * $Id: vm_page.c,v 1.128 1999/03/19 05:21:03 alc Exp $ */ /* @@ -146,15 +146,6 @@ static vm_size_t page_mask; static int page_shift; int vm_page_zero_count = 0; -/* - * map of contiguous valid DEV_BSIZE chunks in a page - * (this list is valid for page sizes upto 16*DEV_BSIZE) - */ -static u_short vm_page_dev_bsize_chunks[] = { - 0x0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, - 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - static __inline int vm_page_hash __P((vm_object_t object, vm_pindex_t pindex)); static void vm_page_free_wakeup __P((void)); @@ -1442,30 +1433,41 @@ retrylookup: } /* - * mapping function for valid bits or for dirty bits in + * Mapping function for valid bits or for dirty bits in * a page. May not block. + * + * Inputs are required to range within a page. */ + __inline int vm_page_bits(int base, int size) { - u_short chunk; + int first_bit; + int last_bit; - if ((base == 0) && (size >= PAGE_SIZE)) - return VM_PAGE_BITS_ALL; + KASSERT( + base + size <= PAGE_SIZE, + ("vm_page_bits: illegal base/size %d/%d", base, size) + ); - size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); - base &= PAGE_MASK; - if (size > PAGE_SIZE - base) { - size = PAGE_SIZE - base; - } + if (size == 0) /* handle degenerate case */ + return(0); - base = base / DEV_BSIZE; - chunk = vm_page_dev_bsize_chunks[size / DEV_BSIZE]; - return (chunk << base) & VM_PAGE_BITS_ALL; + first_bit = base >> DEV_BSHIFT; + last_bit = (base + size - 1) >> DEV_BSHIFT; + + return ((2 << last_bit) - (1 << first_bit)); } /* * set a page valid and clean. May not block. + * + * In order to maintain consistancy due to the DEV_BSIZE granularity + * of the valid bits, we have to zero non-DEV_BSIZE aligned portions of + * the page at the beginning and end of the valid range when the + * associated valid bits are not already set. + * + * (base + size) must be less then or equal to PAGE_SIZE. */ void vm_page_set_validclean(m, base, size) @@ -1473,10 +1475,57 @@ vm_page_set_validclean(m, base, size) int base; int size; { - int pagebits = vm_page_bits(base, size); + int pagebits; + int frag; + int endoff; + + if (size == 0) /* handle degenerate case */ + return; + + /* + * If the base is not DEV_BSIZE aligned and the valid + * bit is clear, we have to zero out a portion of the + * first block. + */ + + if ((frag = base & ~(DEV_BSIZE - 1)) != base && + (m->valid & (1 << (base >> DEV_BSHIFT))) == 0 + ) { + pmap_zero_page_area( + VM_PAGE_TO_PHYS(m), + frag, + base - frag + ); + } + + /* + * If the ending offset is not DEV_BSIZE aligned and the + * valid bit is clear, we have to zero out a portion of + * the last block. + */ + + endoff = base + size; + + if ((frag = endoff & ~(DEV_BSIZE - 1)) != endoff && + (m->valid & (1 << (endoff >> DEV_BSHIFT))) == 0 + ) { + pmap_zero_page_area( + VM_PAGE_TO_PHYS(m), + endoff, + DEV_BSIZE - (endoff & (DEV_BSIZE - 1)) + ); + } + + /* + * Set valid, clear dirty bits. If validating the entire + * page we can safely clear the pmap modify bit. + */ + + pagebits = vm_page_bits(base, size); m->valid |= pagebits; m->dirty &= ~pagebits; - if( base == 0 && size == PAGE_SIZE) + + if (base == 0 && size == PAGE_SIZE) pmap_clear_modify(VM_PAGE_TO_PHYS(m)); } @@ -1498,8 +1547,65 @@ vm_page_set_invalid(m, base, size) } /* - * is (partial) page valid? May not block. + * vm_page_zero_invalid() + * + * The kernel assumes that the invalid portions of a page contain + * garbage, but such pages can be mapped into memory by user code. + * When this occurs, we must zero out the non-valid portions of the + * page so user code sees what it expects. + * + * Pages are most often semi-valid when the end of a file is mapped + * into memory and the file's size is not page aligned. + */ + +void +vm_page_zero_invalid(vm_page_t m, boolean_t setvalid) +{ + int b; + int i; + + /* + * Scan the valid bits looking for invalid sections that + * must be zerod. Invalid sub-DEV_BSIZE'd areas ( where the + * valid bit may be set ) have already been zerod by + * vm_page_set_validclean(). + */ + + for (b = i = 0; i <= PAGE_SIZE / DEV_BSIZE; ++i) { + if (i == (PAGE_SIZE / DEV_BSIZE) || + (m->valid & (1 << i)) + ) { + if (i > b) { + pmap_zero_page_area( + VM_PAGE_TO_PHYS(m), + b << DEV_BSHIFT, + (i - b) << DEV_BSHIFT + ); + } + b = i + 1; + } + } + + /* + * setvalid is TRUE when we can safely set the zero'd areas + * as being valid. We can do this if there are no cache consistancy + * issues. e.g. it is ok to do with UFS, but not ok to do with NFS. + */ + + if (setvalid) + m->valid = VM_PAGE_BITS_ALL; +} + +/* + * vm_page_is_valid: + * + * Is (partial) page valid? Note that the case where size == 0 + * will return FALSE in the degenerate case where the page is + * entirely invalid, and TRUE otherwise. + * + * May not block. */ + int vm_page_is_valid(m, base, size) vm_page_t m; diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index 78c51f2..8072f66 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -61,7 +61,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_page.h,v 1.57 1999/03/14 20:40:15 julian Exp $ + * $Id: vm_page.h,v 1.58 1999/03/15 05:09:48 julian Exp $ */ /* @@ -415,6 +415,7 @@ int vm_page_queue_index __P((vm_offset_t, int)); int vm_page_sleep(vm_page_t m, char *msg, char *busy); int vm_page_asleep(vm_page_t m, char *msg, char *busy); #endif +void vm_page_zero_invalid(vm_page_t m, boolean_t setvalid); void vm_page_free_toq(vm_page_t m); /* diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index b645ee3..39f1c35 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -38,7 +38,7 @@ * SUCH DAMAGE. * * from: @(#)vnode_pager.c 7.5 (Berkeley) 4/20/91 - * $Id: vnode_pager.c,v 1.104 1999/02/27 23:39:28 alc Exp $ + * $Id: vnode_pager.c,v 1.105 1999/03/27 02:39:01 eivind Exp $ */ /* @@ -624,23 +624,21 @@ vnode_pager_generic_getpages(vp, m, bytecount, reqpage) cnt.v_vnodepgsin++; return vnode_pager_input_smlfs(object, m[reqpage]); } + /* - * if ANY DEV_BSIZE blocks are valid on a large filesystem block - * then, the entire page is valid -- - * XXX no it isn't + * If we have a completely valid page available to us, we can + * clean up and return. Otherwise we have to re-read the + * media. */ - if (m[reqpage]->valid != VM_PAGE_BITS_ALL) - m[reqpage]->valid = 0; - - if (m[reqpage]->valid) { - m[reqpage]->valid = VM_PAGE_BITS_ALL; + if (m[reqpage]->valid == VM_PAGE_BITS_ALL) { for (i = 0; i < count; i++) { if (i != reqpage) vnode_pager_freepage(m[i]); } return VM_PAGER_OK; } + m[reqpage]->valid = 0; /* * here on direct device I/O @@ -773,12 +771,25 @@ vnode_pager_generic_getpages(vp, m, bytecount, reqpage) mt = m[i]; if (nextoff <= size) { + /* + * Read filled up entire page. + */ mt->valid = VM_PAGE_BITS_ALL; mt->dirty = 0; pmap_clear_modify(VM_PAGE_TO_PHYS(mt)); } else { - int nvalid = ((size + DEV_BSIZE - 1) - tfoff) & ~(DEV_BSIZE - 1); - vm_page_set_validclean(mt, 0, nvalid); + /* + * Read did not fill up entire page. Since this + * is getpages, the page may be mapped, so we have + * to zero the invalid portions of the page even + * though we aren't setting them valid. + * + * Currently we do not set the entire page valid, + * we just try to clear the piece that we couldn't + * read. + */ + vm_page_set_validclean(mt, 0, size - tfoff); + vm_page_zero_invalid(mt, FALSE); } vm_page_flag_clear(mt, PG_ZERO); |