From 21ab32bd5136ed2dc3034cb7b406e1310dbd18f7 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 29 Jan 2005 19:17:06 +0000 Subject: [PATCH] getblk() has an old crufty API in which the logical block size is not a well known quantity. Device drivers standardize on using DEV_BSIZE (512), while file ops are supposed to use mount->mnt_stat.f_iosize. The existing code was testing for a non-NULL vnode->v_mountedhere field but this field is part of a union and only valid for VDIR types. It was being improperly tested on non-VDIR vnode types. In particular, if vn_isdisk() fails due to the disk device being ripped out from under a filesystem, the code would fall through and try to use v_mountedhere, leading to a crash. It also makes no sense to use the target mount to calculate the block size for the underlying mount point's vnode, so this test has been removed entirely. The vn_isdisk() test has been replaced with an explicit VBLK/VCHR test. Finally, note that filesystems like UFS use varying buffer cache buffer sizes for different areas of the same block device (e.g. bitmap areas, inode area, file data areas, superblock), which is why DEV_BSIZE is being used here. What really needs to happen is for b_blkno to be entirely removed in favor of a 64 bit offset. Crash-Reported-by: Vyacheslav Bocharov --- sys/kern/vfs_bio.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 963b4d924e..5cda44657e 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -12,7 +12,7 @@ * John S. Dyson. * * $FreeBSD: src/sys/kern/vfs_bio.c,v 1.242.2.20 2003/05/28 18:38:10 alc Exp $ - * $DragonFly: src/sys/kern/vfs_bio.c,v 1.32 2004/11/09 17:36:41 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_bio.c,v 1.33 2005/01/29 19:17:06 dillon Exp $ */ /* @@ -2293,14 +2293,27 @@ loop: * Buffer is not in-core, create new buffer. The buffer * returned by getnewbuf() is locked. Note that the returned * buffer is also considered valid (not marked B_INVAL). + * + * Calculating the offset for the I/O requires figuring out + * the block size. We use DEV_BSIZE for VBLK or VCHR and + * the mount's f_iosize otherwise. If the vnode does not + * have an associated mount we assume that the passed size is + * the block size. + * + * Note that vn_isdisk() cannot be used here since it may + * return a failure for numerous reasons. Note that the + * buffer size may be larger then the block size (the caller + * will use block numbers with the proper multiple). Beware + * of using any v_* fields which are part of unions. In + * particular, in DragonFly the mount point overloading + * mechanism is such that the underlying directory (with a + * non-NULL v_mountedhere) is not a special case. */ int bsize, maxsize, vmio; off_t offset; - if (vn_isdisk(vp, NULL)) + if (vp->v_type == VBLK || vp->v_type == VCHR) bsize = DEV_BSIZE; - else if (vp->v_mountedhere) - bsize = vp->v_mountedhere->mnt_stat.f_iosize; else if (vp->v_mount) bsize = vp->v_mount->mnt_stat.f_iosize; else -- 2.41.0