Module Name: src Committed By: riastradh Date: Mon Jun 4 19:46:00 UTC 2012
Modified Files: src/sys/ufs/ext2fs: ext2fs_rename.c Log Message: Fix ext2fs's scary cross-block directory message too. (See rev. 1.3 of sys/ufs/ufs/ufs_rename.c for the analysis.) To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/ufs/ext2fs/ext2fs_rename.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/ufs/ext2fs/ext2fs_rename.c diff -u src/sys/ufs/ext2fs/ext2fs_rename.c:1.2 src/sys/ufs/ext2fs/ext2fs_rename.c:1.3 --- src/sys/ufs/ext2fs/ext2fs_rename.c:1.2 Thu May 10 19:08:34 2012 +++ src/sys/ufs/ext2fs/ext2fs_rename.c Mon Jun 4 19:45:59 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ext2fs_rename.c,v 1.2 2012/05/10 19:08:34 riastradh Exp $ */ +/* $NetBSD: ext2fs_rename.c,v 1.3 2012/06/04 19:45:59 riastradh Exp $ */ /*- * Copyright (c) 2012 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ext2fs_rename.c,v 1.2 2012/05/10 19:08:34 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ext2fs_rename.c,v 1.3 2012/06/04 19:45:59 riastradh Exp $"); #include <sys/param.h> #include <sys/buf.h> @@ -487,10 +487,9 @@ ext2fs_gro_rename(struct mount *mp, kaut * inserting a new entry. That may invalidate fulr, which we * need in order to remove the old entry. In that case, we * need to recalculate what fulr should be. - * - * XXX I believe this is necessary only if tvp == NULL as well. */ - if (!reparent_p && ext2fs_rename_ulr_overlap_p(fulr, tulr)) { + if (!reparent_p && (tvp == NULL) && + ext2fs_rename_ulr_overlap_p(fulr, tulr)) { error = ext2fs_rename_recalculate_fulr(fdvp, fulr, tulr, fcnp); #if 0 /* XXX */ if (error) /* XXX Try to back out changes? */ @@ -571,13 +570,11 @@ ext2fs_rename_recalculate_fulr(struct vn struct mount *mp; struct ufsmount *ump; /* XXX int is a silly type for this; blame ufsmount::um_dirblksiz. */ - int directory_block_mask; - unsigned long io_block_mask; + int dirblksiz; + doff_t search_start, search_end; doff_t offset; /* Offset of entry we're examining. */ - doff_t search_end; /* Limit to our search. */ struct buf *bp; /* I/O block we're examining. */ - char *dirbuf; /* Pointer into bp's data. */ - doff_t dirbuf_offset; /* Offset of dirbuf from directory start. */ + char *dirbuf; /* Pointer into directory at search_start. */ struct ext2fs_direct *ep; /* Pointer to the entry we're examining. */ /* XXX direct::d_reclen is 16-bit; * ufs_lookup_results::ulr_reclen is 32-bit. Blah. */ @@ -598,66 +595,55 @@ ext2fs_rename_recalculate_fulr(struct vn KASSERT(ump != NULL); KASSERT(ump == VTOI(dvp)->i_ump); - KASSERT(0 < ump->um_dirblksiz); - KASSERT((ump->um_dirblksiz & (ump->um_dirblksiz - 1)) == 0); - directory_block_mask = (ump->um_dirblksiz - 1); - - KASSERT(0 < mp->mnt_stat.f_iosize); - KASSERT((mp->mnt_stat.f_iosize & (mp->mnt_stat.f_iosize - 1)) == 0); - io_block_mask = (mp->mnt_stat.f_iosize - 1); + dirblksiz = ump->um_dirblksiz; + KASSERT(0 < dirblksiz); + KASSERT((dirblksiz & (dirblksiz - 1)) == 0); - offset = tulr->ulr_offset; + /* A directory block may not span across multiple I/O blocks. */ + KASSERT(dirblksiz <= mp->mnt_stat.f_iosize); + + /* Find the bounds of the search. */ + search_start = tulr->ulr_offset; KASSERT(fulr->ulr_reclen < (EXT2FS_MAXDIRSIZE - fulr->ulr_offset)); search_end = (fulr->ulr_offset + fulr->ulr_reclen); + /* Compaction must happen only within a directory block. (*) */ + KASSERT(search_start <= search_end); + KASSERT((search_end - (search_start &~ (dirblksiz - 1))) <= dirblksiz); + dirbuf = NULL; bp = NULL; - dirbuf_offset = offset; - error = ext2fs_blkatoff(dvp, (off_t)dirbuf_offset, &dirbuf, &bp); + error = ext2fs_blkatoff(dvp, (off_t)search_start, &dirbuf, &bp); if (error) return error; KASSERT(dirbuf != NULL); KASSERT(bp != NULL); + /* + * Guarantee we sha'n't go past the end of the buffer we got. + * dirbuf is bp->b_data + (search_start & (iosize - 1)), and + * the valid range is [bp->b_data, bp->b_data + bp->b_bcount). + */ + KASSERT((search_end - search_start) <= + (bp->b_bcount - (search_start & (mp->mnt_stat.f_iosize - 1)))); + prev_reclen = fulr->ulr_count; + offset = search_start; /* - * Search from offset to search_end for the entry matching + * Search from search_start to search_end for the entry matching * fcnp, which must be there because we found it before and it * should only at most have moved earlier. */ for (;;) { + KASSERT(search_start <= offset); KASSERT(offset < search_end); /* - * If we are at an I/O block boundary, fetch the next block. - */ - if ((offset & io_block_mask) == 0) { -#ifdef DIAGNOSTIC /* XXX */ - printf("%s: directory block of inode 0x%llx" - " extends across I/O block boundary," - " which shouldn't happen!\n", - mp->mnt_stat.f_mntonname, - (unsigned long long)VTOI(dvp)->i_number); -#endif - brelse(bp, 0); - dirbuf = NULL; - bp = NULL; - dirbuf_offset = offset; - error = ext2fs_blkatoff(dvp, (off_t)dirbuf_offset, - &dirbuf, &bp); - if (error) - return error; - KASSERT(dirbuf != NULL); - KASSERT(bp != NULL); - } - - /* * Examine the directory entry at offset. */ - KASSERT(dirbuf_offset <= offset); ep = (struct ext2fs_direct *) - (dirbuf + (offset - dirbuf_offset)); + (dirbuf + (offset - search_start)); reclen = fs2h16(ep->e2d_reclen); if (ep->e2d_ino == 0) @@ -682,8 +668,17 @@ next: return EIO; /* XXX Panic? What? */ } + /* We may not move past the search end. */ KASSERT(reclen < search_end); KASSERT(offset < (search_end - reclen)); + + /* + * We may not move across a directory block boundary; + * see (*) above. + */ + KASSERT((offset &~ (dirblksiz - 1)) == + ((offset + reclen) &~ (dirblksiz - 1))); + prev_reclen = reclen; offset += reclen; } @@ -698,7 +693,7 @@ next: * Record the preceding record length, but not if we're at the * start of a directory block. */ - fulr->ulr_count = ((offset & directory_block_mask)? prev_reclen : 0); + fulr->ulr_count = ((offset & (dirblksiz - 1))? prev_reclen : 0); brelse(bp, 0); return 0;