Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Jan 2010 10:22:25 -0800 (PST)
From:      "Pedro F. Giffuni" <giffunip@tutopia.com>
To:        FreeBSD-gnats-submit@FreeBSD.org, freebsd-bugs@FreeBSD.org
Subject:   Re: kern/142924: Small cleanup for the inode struct in ext2fs (based on UFS)
Message-ID:  <920788.12268.qm@web113508.mail.gq1.yahoo.com>

index | next in thread | raw e-mail

[-- Attachment #1 --]
Include two more simple patches from ufs_lookup.c:

CVS 1.54:
When compacting directories, ufs_direnter() always trusted DIRSIZ()
to supply the number of bytes to be bcopy()'d to move an entry. If
d_ino == 0 however, DIRSIZ() is not guaranteed to return a sensible
length, so ufs_direnter could end up corrupting a directory during
compaction.

CVS 1.45:
Extend the sanity checks in ufs_lookup to ensure that each directory
entry fits within its DIRBLKSIZ block.
_______

These were meant to fix issues found with dirhash on UFS but ext2fs
still works here with those changes so I think it's good to have
them, JIC we end up bringing over dirhash to ext2fs.


      
[-- Attachment #2 --]
diff -ru ext2fs.bsd/ext2_lookup.c ext2fs/ext2_lookup.c
--- ext2fs.bsd/ext2_lookup.c	2010-01-17 19:02:30.000000000 +0000
+++ ext2fs/ext2_lookup.c	2010-01-24 19:27:52.000000000 +0000
@@ -347,6 +347,7 @@
 		slotneeded = (sizeof(struct direct) - MAXNAMLEN +
 			cnp->cn_namelen + 3) &~ 3; */
 	}
+	bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
 
 	/*
 	 * If there is cached information on a previous search of
@@ -359,9 +360,8 @@
 	 * profiling time and hence has been removed in the interest
 	 * of simplicity.
 	 */
-	bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
 	if (nameiop != LOOKUP || i_diroff == 0 ||
-	    i_diroff > dp->i_size) {
+	    i_diroff >= dp->i_size) {
 		entryoffsetinblock = 0;
 		i_offset = 0;
 		numdirpasses = 1;
@@ -408,9 +408,9 @@
 		 * directory. Complete checks can be run by setting
 		 * "vfs.e2fs.dirchk" to be true.
 		 */
-		ep = (struct ext2fs_direct_2 *)
-			((char *)bp->b_data + entryoffsetinblock);
-		if (ep->e2d_reclen == 0 ||
+		ep = (struct ext2fs_direct_2 *)((char *)bp->b_data + entryoffsetinblock);
+		if (ep->e2d_reclen == 0 || ep->e2d_reclen >
+		    DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) ||
 		    (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
 			int i;
 			ext2_dirbad(dp, i_offset, "mangled entry");
@@ -550,10 +550,10 @@
 	 * Check that directory length properly reflects presence
 	 * of this entry.
 	 */
-	if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->e2d_namlen)
+	if (dp->i_offset + EXT2_DIR_REC_LEN(ep->e2d_namlen)
 		> dp->i_size) {
 		ext2_dirbad(dp, i_offset, "i_size too small");
-		dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->e2d_namlen);
+		dp->i_size = dp->i_offset+EXT2_DIR_REC_LEN(ep->e2d_namlen);
 		dp->i_flag |= IN_CHANGE | IN_UPDATE;
 	}
 	brelse(bp);
@@ -855,17 +855,30 @@
 	 * space.
 	 */
 	ep = (struct ext2fs_direct_2 *)dirbuf;
-	dsize = EXT2_DIR_REC_LEN(ep->e2d_namlen);
+	dsize = ep->e2d_ino ? EXT2_DIR_REC_LEN(ep->e2d_namlen) : 0;
 	spacefree = ep->e2d_reclen - dsize;
 	for (loc = ep->e2d_reclen; loc < dp->i_count; ) {
 		nep = (struct ext2fs_direct_2 *)(dirbuf + loc);
-		if (ep->e2d_ino) {
-			/* trim the existing slot */
-			ep->e2d_reclen = dsize;
-			ep = (struct ext2fs_direct_2 *)((char *)ep + dsize);
-		} else {
-			/* overwrite; nothing there; header is ours */
-			spacefree += dsize;
+
+		/* trim the existing slot (NB: dsize may be zero). */
+		ep->e2d_reclen = dsize;
+		ep = (struct ext2fs_direct_2 *)((char *)ep + dsize);
+
+		/* Read nep->e2d_reclen now as the bcopy() may clobber it. */
+		loc += nep->e2d_reclen;
+		if (nep->e2d_ino == 0) {
+			/*
+			 * A mid-block unused entry. Such entries are
+			 * never created by the kernel, but fsck
+			 * can create them (and not fix them).
+			 *
+			 * Add up the free space, and initialise the
+			 * relocated entry since we don't bcopy it.
+			 */
+			spacefree += nep->e2d_reclen;
+			ep->e2d_ino = 0;
+			dsize = 0;
+			continue;
 		}
 		dsize = EXT2_DIR_REC_LEN(nep->e2d_namlen);
 		spacefree += nep->e2d_reclen - dsize;
diff -ru ext2fs.bsd/ext2_vfsops.c ext2fs/ext2_vfsops.c
--- ext2fs.bsd/ext2_vfsops.c	2010-01-17 19:02:56.000000000 +0000
+++ ext2fs/ext2_vfsops.c	2010-01-18 15:43:20.000000000 +0000
@@ -945,9 +945,8 @@
 	}
 
 	/*
-	 * Finish inode initialization now that aliasing has been resolved.
+	 * Finish inode initialization.
 	 */
-	ip->i_devvp = ump->um_devvp;
 
 	/*
 	 * Set up a generation number for this inode if it does not
diff -ru ext2fs.bsd/inode.h ext2fs/inode.h
--- ext2fs.bsd/inode.h	2010-01-17 19:03:21.000000000 +0000
+++ ext2fs/inode.h	2010-01-18 15:43:20.000000000 +0000
@@ -62,7 +62,6 @@
  */
 struct inode {
 	struct	vnode  *i_vnode;/* Vnode associated with this inode. */
-	struct	vnode  *i_devvp;/* Vnode for block I/O. */
 	struct	ext2mount *i_ump;
 	u_int32_t i_flag;	/* flags, see below */
 	ino_t	  i_number;	/* The identity of the inode. */
@@ -143,6 +142,9 @@
 #define	IN_SPACECOUNTED	0x0080		/* Blocks to be freed in free count. */
 #define IN_LAZYACCESS   0x0100		/* Process IN_ACCESS after the
 					    suspension finished */
+
+#define i_devvp i_ump->um_devvp
+
 #ifdef _KERNEL
 /*
  * Structure used to pass around logical block paths generated by
help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?920788.12268.qm>