Date: Tue, 29 Sep 1998 12:12:47 +1000 From: Bruce Evans <bde@zeta.org.au> To: bugs@FreeBSD.ORG Subject: vfs_bio_clrbuf() broken for sub-page buffers Message-ID: <199809290212.MAA32074@godzilla.zeta.org.au>
next in thread | raw e-mail | index | archive | help
vfs_bio_clrbuf() seems to be quite broken for sub-page VMIO buffers at a nonzero offset in the page. Such buffers are common for filesystems with a sub-page blocksize, e.g., ext2fs. The diff has a fixed(?) version ifdefed out so that the bug can be found by the test function vfs_bio_clrbuf_check(). The unfixed version looks at the wrong `valid' bits and clears `valid' bits that it hasn't even looked at. I don't understand why `valid' parts of pages are guaranteed to be zero. Bruce diff -c2 vfs_bio.c~ vfs_bio.c *** vfs_bio.c~ Sun Sep 27 10:59:38 1998 --- vfs_bio.c Tue Sep 29 11:54:22 1998 *************** *** 2295,2298 **** --- 2337,2368 ---- } + static void + vfs_bio_clrbuf_check(struct buf *bp) + { + int i, n; + int32_t *p; + + p = (int32_t *)bp->b_data; + n = bp->b_bcount / 4; + for (i = 0; i < n; i++) + if (p[i] != 0) + break; + if (i != n) { + Debugger("not clear 1"); + clrbuf(bp); + } + if (bp->b_bufsize / 4 == n) + return; + p = (int32_t *)bp->b_data; + n = bp->b_bufsize / 4; + for (i = 0; i < n; i++) + if (p[i] != 0) + break; + if (i != n) { + clrbuf(bp); + Debugger("not clear 2"); + } + } + void vfs_bio_clrbuf(struct buf *bp) { *************** *** 2301,2304 **** --- 2371,2397 ---- if( (bp->b_npages == 1) && (bp->b_bufsize < PAGE_SIZE)) { int mask; + u_int off; + + #if 0 + /* + * The mask calculation can be optimized to + * ((1 << x) - (1 << y)), where (I think) + * x = (off + bp->b_bufsize) / DEV_BSIZE and + * y = off / DEV_BSIZE. See also vm_page_bits() + * for a (probably worse) lookup table method. + */ + mask = 0; + off = (vm_offset_t)bp->b_data & PAGE_MASK; + if (off + bp->b_bufsize > PAGE_SIZE) + panic("vfs_bio_clrbuf: page overrun"); + for(i=0;i<bp->b_bufsize;i+=DEV_BSIZE) + mask |= 1 << ((off + i) / DEV_BSIZE); + if(((bp->b_pages[0]->flags & PG_ZERO) == 0) && + (bp->b_pages[0]->valid & mask) != mask) { + bzero(bp->b_data, bp->b_bufsize); + bp->b_pages[0]->valid |= mask; + } + bp->b_resid = 0; + #else mask = 0; for(i=0;i<bp->b_bufsize;i+=DEV_BSIZE) *************** *** 2310,2313 **** --- 2403,2408 ---- bp->b_pages[0]->valid = mask; bp->b_resid = 0; + #endif + vfs_bio_clrbuf_check(bp); return; } *************** *** 2331,2336 **** --- 2426,2435 ---- } bp->b_resid = 0; + vfs_bio_clrbuf_check(bp); } else { + if (bp->b_bcount != bp->b_bufsize) + Debugger("bcount != bufsize"); clrbuf(bp); + vfs_bio_clrbuf_check(bp); } } To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199809290212.MAA32074>