diff mbox

[05/31] libext2fs: Add space for metadata checksum when unconverting a hashed directory block

Message ID 20131001012714.28415.87579.stgit@birch.djwong.org
State Accepted, archived
Headers show

Commit Message

Darrick Wong Oct. 1, 2013, 1:27 a.m. UTC
The ext2fs_link function has the unfortunate habit of converting hashed
directories into unhashed directories.  It doesn't notice that it's slicing
and dicing directory entries from a former dx_{root,node} block, and therefore
doesn't write a protective dirent into the end of the block to store the
checksum.  Teach it to do this.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 lib/ext2fs/link.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)



--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Theodore Ts'o Oct. 13, 2013, 3:16 a.m. UTC | #1
On Mon, Sep 30, 2013 at 06:27:14PM -0700, Darrick J. Wong wrote:
> The ext2fs_link function has the unfortunate habit of converting hashed
> directories into unhashed directories.  It doesn't notice that it's slicing
> and dicing directory entries from a former dx_{root,node} block, and therefore
> doesn't write a protective dirent into the end of the block to store the
> checksum.  Teach it to do this.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>

Thanks, applied to the next branch.

					- Ted
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
index e3ff450..24fa083 100644
--- a/lib/ext2fs/link.c
+++ b/lib/ext2fs/link.c
@@ -42,6 +42,7 @@  static int link_proc(struct ext2_dir_entry *dirent,
 	unsigned int rec_len, min_rec_len, curr_rec_len;
 	int ret = 0;
 	int csum_size = 0;
+	struct ext2_dir_entry_tail *t;
 
 	if (ls->done)
 		return 0;
@@ -71,6 +72,40 @@  static int link_proc(struct ext2_dir_entry *dirent,
 	}
 
 	/*
+	 * Since ext2fs_link blows away htree data, we need to be careful --
+	 * if metadata_csum is enabled and we're passed in a dirent that
+	 * contains htree data, we need to create the fake entry at the end
+	 * of the block that hides the checksum.
+	 */
+
+	/* De-convert a dx_node block */
+	if (csum_size &&
+	    curr_rec_len == ls->fs->blocksize &&
+	    !dirent->inode) {
+		curr_rec_len -= csum_size;
+		ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
+		if (ls->err)
+			return DIRENT_ABORT;
+		t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize);
+		ext2fs_initialize_dirent_tail(ls->fs, t);
+		ret = DIRENT_CHANGED;
+	}
+
+	/* De-convert a dx_root block */
+	if (csum_size &&
+	    curr_rec_len == ls->fs->blocksize - EXT2_DIR_REC_LEN(1) &&
+	    offset == EXT2_DIR_REC_LEN(1) &&
+	    dirent->name[0] == '.' && dirent->name[1] == '.') {
+		curr_rec_len -= csum_size;
+		ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
+		if (ls->err)
+			return DIRENT_ABORT;
+		t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize);
+		ext2fs_initialize_dirent_tail(ls->fs, t);
+		ret = DIRENT_CHANGED;
+	}
+
+	/*
 	 * If the directory entry is used, see if we can split the
 	 * directory entry to make room for the new name.  If so,
 	 * truncate it and return.
@@ -152,6 +187,11 @@  errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
 	if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
 		return retval;
 
+	/*
+	 * If this function changes to preserve the htree, remove the two
+	 * hunks in link_proc that shove checksum tails into the former
+	 * dx_root/dx_node blocks.
+	 */
 	if (inode.i_flags & EXT2_INDEX_FL) {
 		inode.i_flags &= ~EXT2_INDEX_FL;
 		if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0)