Skip site navigation (1)Skip section navigation (2)
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>