svn commit: r337453 - head/sys/fs/ext2fs

Fedor Uporov fsu at FreeBSD.org
Wed Aug 8 12:07:47 UTC 2018


Author: fsu
Date: Wed Aug  8 12:07:45 2018
New Revision: 337453
URL: https://svnweb.freebsd.org/changeset/base/337453

Log:
  Fix directory blocks checksum updating logic.
  
  The checksum updating functions were not called in case of dir index inode splitting
  and in case of dir entry removing, when the entry was first in the block.
  Fix and move the dir entry adding logic when i_count == 0 to new function.
  
  MFC after:      3 months

Modified:
  head/sys/fs/ext2fs/ext2_htree.c
  head/sys/fs/ext2fs/ext2_lookup.c

Modified: head/sys/fs/ext2fs/ext2_htree.c
==============================================================================
--- head/sys/fs/ext2fs/ext2_htree.c	Wed Aug  8 07:58:29 2018	(r337452)
+++ head/sys/fs/ext2fs/ext2_htree.c	Wed Aug  8 12:07:45 2018	(r337453)
@@ -800,7 +800,7 @@ ext2_htree_add_entry(struct vnode *dvp, struct ext2fs_
 		cursize = roundup(ip->i_size, blksize);
 		dirsize = cursize + blksize;
 		blknum = dirsize / blksize - 1;
-
+		ext2_dx_csum_set(ip, (struct ext2fs_direct_2 *)newidxblock);
 		error = ext2_htree_append_block(dvp, newidxblock,
 		    cnp, blksize);
 		if (error)

Modified: head/sys/fs/ext2fs/ext2_lookup.c
==============================================================================
--- head/sys/fs/ext2fs/ext2_lookup.c	Wed Aug  8 07:58:29 2018	(r337452)
+++ head/sys/fs/ext2fs/ext2_lookup.c	Wed Aug  8 12:07:45 2018	(r337453)
@@ -859,6 +859,68 @@ ext2_dirbadentry(struct vnode *dp, struct ext2fs_direc
 }
 
 /*
+ * Insert an entry into the fresh directory block.
+ * Initialize entry tail if the metadata_csum feature is turned on.
+ */
+static int
+ext2_add_first_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry,
+    struct componentname *cnp)
+{
+	struct inode *dp;
+	struct iovec aiov;
+	struct uio auio;
+	char* buf = NULL;
+	int dirblksize, error;
+
+	dp = VTOI(dvp);
+	dirblksize = dp->i_e2fs->e2fs_bsize;
+
+	if (dp->i_offset & (dirblksize - 1))
+		panic("ext2_add_first_entry: bad directory offset");
+
+	if (EXT2_HAS_RO_COMPAT_FEATURE(dp->i_e2fs,
+	    EXT2F_ROCOMPAT_METADATA_CKSUM)) {
+		entry->e2d_reclen = dirblksize - sizeof(struct ext2fs_direct_tail);
+		buf = malloc(dirblksize, M_TEMP, M_WAITOK);
+		if (!buf) {
+			error = ENOMEM;
+			goto out;
+		}
+		memcpy(buf, entry, EXT2_DIR_REC_LEN(entry->e2d_namlen));
+		ext2_init_dirent_tail(EXT2_DIRENT_TAIL(buf, dirblksize));
+		ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)buf);
+
+		auio.uio_offset = dp->i_offset;
+		auio.uio_resid = dirblksize;
+		aiov.iov_len = auio.uio_resid;
+		aiov.iov_base = (caddr_t)buf;
+	} else {
+		entry->e2d_reclen = dirblksize;
+		auio.uio_offset = dp->i_offset;
+		auio.uio_resid = EXT2_DIR_REC_LEN(entry->e2d_namlen);
+		aiov.iov_len = auio.uio_resid;
+		aiov.iov_base = (caddr_t)entry;
+	}
+
+	auio.uio_iov = &aiov;
+	auio.uio_iovcnt = 1;
+	auio.uio_rw = UIO_WRITE;
+	auio.uio_segflg = UIO_SYSSPACE;
+	auio.uio_td = (struct thread *)0;
+	error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
+	if (error)
+		goto out;
+
+	dp->i_size = roundup2(dp->i_size, dirblksize);
+	dp->i_flag |= IN_CHANGE;
+
+out:
+	free(buf, M_TEMP);
+	return (error);
+
+}
+
+/*
  * Write a directory entry after a call to namei, using the parameters
  * that it left in nameidata.  The argument ip is the inode which the new
  * directory entry will refer to.  Dvp is a pointer to the directory to
@@ -871,7 +933,6 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, str
 {
 	struct inode *dp;
 	struct ext2fs_direct_2 newdir;
-	struct buf *bp;
 	int DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
 	int error;
 
@@ -911,36 +972,15 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, str
 		}
 	}
 
-	if (dp->i_count == 0) {
-		/*
-		 * If dp->i_count is 0, then namei could find no
-		 * space in the directory. Here, dp->i_offset will
-		 * be on a directory block boundary and we will write the
-		 * new entry into a fresh block.
-		 */
-		if (dp->i_offset & (DIRBLKSIZ - 1))
-			panic("ext2_direnter: newblk");
+	/*
+	 * If dp->i_count is 0, then namei could find no
+	 * space in the directory. Here, dp->i_offset will
+	 * be on a directory block boundary and we will write the
+	 * new entry into a fresh block.
+	 */
+	if (dp->i_count == 0)
+		return ext2_add_first_entry(dvp, &newdir, cnp);
 
-		newdir.e2d_reclen = DIRBLKSIZ;
-
-		bp = getblk(ip->i_devvp, lblkno(dp->i_e2fs, dp->i_offset),
-		    DIRBLKSIZ, 0, 0, 0);
-		if (!bp)
-			return (EIO);
-
-		memcpy(bp->b_data, &newdir, sizeof(struct ext2fs_direct_2));
-
-		ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)bp->b_data);
-		error = bwrite(bp);
-		if (error)
-			return (error);
-
-		dp->i_size = roundup2(dp->i_size, DIRBLKSIZ);
-		dp->i_flag |= IN_CHANGE;
-
-		return (0);
-	}
-
 	error = ext2_add_entry(dvp, &newdir);
 	if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
 		error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC,
@@ -1071,6 +1111,7 @@ ext2_dirremove(struct vnode *dvp, struct componentname
 		    &bp)) != 0)
 			return (error);
 		ep->e2d_ino = 0;
+		ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)bp->b_data);
 		error = bwrite(bp);
 		dp->i_flag |= IN_CHANGE | IN_UPDATE;
 		return (error);


More information about the svn-src-head mailing list