diff options
author | julian <julian@FreeBSD.org> | 1999-04-05 19:38:30 +0000 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 1999-04-05 19:38:30 +0000 |
commit | 0ed09d2ad576c0a64797f8ca9bebd32873f770ae (patch) | |
tree | 6de1ee6b7f198b11b20d471fbc1a36de8329d82e /sys/nfsclient/nfs_bio.c | |
parent | 9ac433dd352fdfe7f3038aa0e1a4333686bc07fc (diff) | |
download | FreeBSD-src-0ed09d2ad576c0a64797f8ca9bebd32873f770ae.zip FreeBSD-src-0ed09d2ad576c0a64797f8ca9bebd32873f770ae.tar.gz |
Catch a case spotted by Tor where files mmapped could leave garbage in the
unallocated parts of the last page when the file ended on a frag
but not a page boundary.
Delimitted by tags PRE_MATT_MMAP_EOF and POST_MATT_MMAP_EOF,
in files alpha/alpha/pmap.c i386/i386/pmap.c nfs/nfs_bio.c vm/pmap.h
vm/vm_page.c vm/vm_page.h vm/vnode_pager.c miscfs/specfs/spec_vnops.c
ufs/ufs/ufs_readwrite.c kern/vfs_bio.c
Submitted by: Matt Dillon <dillon@freebsd.org>
Reviewed by: Alan Cox <alc@freebsd.org>
Diffstat (limited to 'sys/nfsclient/nfs_bio.c')
-rw-r--r-- | sys/nfsclient/nfs_bio.c | 56 |
1 files changed, 46 insertions, 10 deletions
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 |