diff options
author | dillon <dillon@FreeBSD.org> | 2001-11-04 06:18:55 +0000 |
---|---|---|
committer | dillon <dillon@FreeBSD.org> | 2001-11-04 06:18:55 +0000 |
commit | 25ccde64e70426c9f01780231c5af9e5b8920f7a (patch) | |
tree | 51a32c1f9f3651c12713bd32a7e8c0bf3f653162 /sys | |
parent | 27968acc29d3f4c68ae15494f6d6aad76f5d6258 (diff) | |
download | FreeBSD-src-25ccde64e70426c9f01780231c5af9e5b8920f7a.zip FreeBSD-src-25ccde64e70426c9f01780231c5af9e5b8920f7a.tar.gz |
Fix a bug in CD9660 when vmiodirenable is turned on. CD9660 was assuming
that a buffer's b_blkno would be valid. This is true when vmiodirenable
is turned off because the B_MALLOC'd buffer's data is invalidated when
the buffer is destroyed. But when vmiodirenable is turned on a buffer
can be reconstituted from its VMIO backing store. The reconstituted buffer
will have no knowledge of the physical block translation and the result is
serious directory corruption of the CDROM.
The solution is to fix cd9660_blkatoff() to always BMAP the buffer if
b_lblkno == b_blkno.
MFC after: 0 days
Diffstat (limited to 'sys')
-rw-r--r-- | sys/fs/cd9660/cd9660_lookup.c | 24 | ||||
-rw-r--r-- | sys/isofs/cd9660/cd9660_lookup.c | 24 |
2 files changed, 46 insertions, 2 deletions
diff --git a/sys/fs/cd9660/cd9660_lookup.c b/sys/fs/cd9660/cd9660_lookup.c index 979c0bd..90dd62b 100644 --- a/sys/fs/cd9660/cd9660_lookup.c +++ b/sys/fs/cd9660/cd9660_lookup.c @@ -415,12 +415,34 @@ cd9660_blkatoff(vp, offset, res, bpp) imp = ip->i_mnt; lbn = lblkno(imp, offset); bsize = blksize(imp, ip, lbn); - + if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) { brelse(bp); *bpp = NULL; return (error); } + + /* + * We must BMAP the buffer because the directory code may use b_blkno + * to calculate the inode for certain types of directory entries. + * We could get away with not doing it before we VMIO-backed the + * directories because the buffers would get freed atomically with + * the invalidation of their data. But with VMIO-backed buffers + * the buffers may be freed and then later reconstituted - and the + * reconstituted buffer will have no knowledge of b_blkno. + */ + if (bp->b_blkno == bp->b_lblkno) { + error = VOP_BMAP(vp, bp->b_lblkno, NULL, + &bp->b_blkno, NULL, NULL); + if (error) { + bp->b_error = error; + bp->b_flags |= B_ERROR; + brelse(bp); + *bpp = NULL; + return (error); + } + } + if (res) *res = (char *)bp->b_data + blkoff(imp, offset); *bpp = bp; diff --git a/sys/isofs/cd9660/cd9660_lookup.c b/sys/isofs/cd9660/cd9660_lookup.c index 979c0bd..90dd62b 100644 --- a/sys/isofs/cd9660/cd9660_lookup.c +++ b/sys/isofs/cd9660/cd9660_lookup.c @@ -415,12 +415,34 @@ cd9660_blkatoff(vp, offset, res, bpp) imp = ip->i_mnt; lbn = lblkno(imp, offset); bsize = blksize(imp, ip, lbn); - + if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) { brelse(bp); *bpp = NULL; return (error); } + + /* + * We must BMAP the buffer because the directory code may use b_blkno + * to calculate the inode for certain types of directory entries. + * We could get away with not doing it before we VMIO-backed the + * directories because the buffers would get freed atomically with + * the invalidation of their data. But with VMIO-backed buffers + * the buffers may be freed and then later reconstituted - and the + * reconstituted buffer will have no knowledge of b_blkno. + */ + if (bp->b_blkno == bp->b_lblkno) { + error = VOP_BMAP(vp, bp->b_lblkno, NULL, + &bp->b_blkno, NULL, NULL); + if (error) { + bp->b_error = error; + bp->b_flags |= B_ERROR; + brelse(bp); + *bpp = NULL; + return (error); + } + } + if (res) *res = (char *)bp->b_data + blkoff(imp, offset); *bpp = bp; |