shithub: lwext4

Download patch

ref: 3e54b8a78e230f6c8703390e7667cd0ad80f9462
parent: daf0d53c33e9427c3eb66b6e572798017249011b
author: ngkaho1234 <[email protected]>
date: Mon Oct 26 08:31:35 EDT 2015

Assign correct checksum to directory entry blocks.

--- a/lwext4/ext4_dir.c
+++ b/lwext4/ext4_dir.c
@@ -400,14 +400,19 @@
 	/* Fill block with zeroes */
 	memset(new_block.data, 0, block_size);
 	struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;
-	ext4_dir_write_entry(&fs->sb, block_entry, block_size, child, name,
-			     name_len);
 
 	/* Save new block */
 	if (ext4_sb_has_feature_read_only(&fs->sb,
-					  EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+					  EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+		ext4_dir_write_entry(&fs->sb, block_entry,
+				block_size - sizeof(struct ext4_directory_entry_tail),
+				child,
+				name, name_len);
 		initialize_dir_tail(EXT4_DIRENT_TAIL(new_block.data,
 					ext4_sb_get_block_size(&fs->sb)));
+	} else
+		ext4_dir_write_entry(&fs->sb, block_entry, block_size, child, name,
+				     name_len);
 
 	ext4_dir_set_checksum(parent,
 			(struct ext4_directory_entry_ll *)new_block.data);
@@ -577,9 +582,12 @@
 	while (dentry < stop) {
 		uint32_t inode = ext4_dir_entry_ll_get_inode(dentry);
 		uint16_t rec_len = ext4_dir_entry_ll_get_entry_length(dentry);
+		uint8_t inode_type = ext4_dir_entry_ll_get_inode_type(sb, dentry);
 
 		/* If invalid and large enough entry, use it */
-		if ((inode == 0) && (rec_len >= required_len)) {
+		if ((inode == 0) &&
+		    (inode_type != EXT4_DIRENTRY_DIR_CSUM) &&
+		    (rec_len >= required_len)) {
 			ext4_dir_write_entry(sb, dentry, rec_len, child, name,
 					     name_len);
 			ext4_dir_set_checksum(inode_ref,
--- a/lwext4/ext4_dir_idx.c
+++ b/lwext4/ext4_dir_idx.c
@@ -408,12 +408,10 @@
 						  0);
 		ext4_dir_entry_ll_set_inode_type(sb,
 						 block_entry,
-						 EXT4_DIRENTRY_DIR_CSUM);
-		if (ext4_sb_has_feature_read_only(sb,
-						  EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
-			initialize_dir_tail(EXT4_DIRENT_TAIL(block_entry,
-						ext4_sb_get_block_size(sb)));
+						 EXT4_DIRENTRY_UNKNOWN);
 
+		initialize_dir_tail(EXT4_DIRENT_TAIL(block_entry,
+					ext4_sb_get_block_size(sb)));
 		ext4_dir_set_checksum(dir,
 				(struct ext4_directory_entry_ll *)new_block.data);
 	} else {
@@ -1008,6 +1006,10 @@
 	uint32_t offset = 0;
 	void *ptr;
 
+	if (ext4_sb_has_feature_read_only(&inode_ref->fs->sb,
+					  EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		block_size -= sizeof(struct ext4_directory_entry_tail);
+
 	/* First part - to the old block */
 	for (i = 0; i < mid; ++i) {
 		ptr = old_data_block->data + offset;
@@ -1041,14 +1043,18 @@
 		offset += sort_array[i].rec_len;
 	}
 
+	block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
+
 	/* Do some steps to finish operation */
-	ext4_dir_set_checksum(inode_ref,
-			(struct ext4_directory_entry_ll *)old_data_block->data);
 	if (ext4_sb_has_feature_read_only(&inode_ref->fs->sb,
-					  EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+					  EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+		initialize_dir_tail(EXT4_DIRENT_TAIL(old_data_block->data,
+					block_size));
 		initialize_dir_tail(EXT4_DIRENT_TAIL(new_data_block_tmp.data,
-					ext4_sb_get_block_size(&inode_ref->fs->sb)));
-
+					block_size));
+	}
+	ext4_dir_set_checksum(inode_ref,
+			(struct ext4_directory_entry_ll *)old_data_block->data);
 	ext4_dir_set_checksum(inode_ref,
 			(struct ext4_directory_entry_ll *)new_data_block_tmp.data);
 	old_data_block->dirty = true;