From ff4f46b4fdb2db5a17440252a21c7db4dfce5986 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 7 Dec 2024 23:31:43 -0500 Subject: [PATCH] resize2fs: rewrite the checksums in the orphan file if necessary The calculation of the metadata checksum located in each block of the orphan file's inode includes the physical block number. So if any of those blocks have been moved, the checksum needs to be updated. Reported-by: Matthias Reichl Signed-off-by: Theodore Ts'o --- resize/resize2fs.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/resize/resize2fs.c b/resize/resize2fs.c index e590f93..28f33d8 100644 --- a/resize/resize2fs.c +++ b/resize/resize2fs.c @@ -49,6 +49,7 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs); static errcode_t inode_ref_fix(ext2_resize_t rfs); static errcode_t move_itables(ext2_resize_t rfs); static errcode_t fix_resize_inode(ext2_filsys fs); +static errcode_t fix_orphan_file_inode(ext2_filsys fs); static errcode_t resize2fs_calculate_summary_stats(ext2_filsys fs); static errcode_t fix_sb_journal_backup(ext2_filsys fs); static errcode_t mark_table_blocks(ext2_filsys fs, @@ -222,6 +223,12 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags, goto errout; print_resource_track(rfs, &rtrack, fs->io); + init_resource_track(&rtrack, "fix_orphan_file_inode", fs->io); + retval = fix_orphan_file_inode(rfs->new_fs); + if (retval) + goto errout; + print_resource_track(rfs, &rtrack, fs->io); + init_resource_track(&rtrack, "fix_sb_journal_backup", fs->io); retval = fix_sb_journal_backup(rfs->new_fs); if (retval) @@ -2837,6 +2844,74 @@ errout: return retval; } +struct process_orphan_block_data { + char *buf; + errcode_t errcode; + ext2_ino_t ino; + __u32 generation; +}; + +static int process_orphan_block(ext2_filsys fs, + blk64_t *block_nr, + e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), + blk64_t ref_blk EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct process_orphan_block_data *pd = priv_data; + struct ext4_orphan_block_tail *tail; + blk64_t blk = *block_nr; + __le32 new_crc; + + pd->errcode = io_channel_read_blk64(fs->io, blk, 1, pd->buf); + if (pd->errcode) + return BLOCK_ABORT; + tail = ext2fs_orphan_block_tail(fs, pd->buf); + new_crc = ext2fs_cpu_to_le32(ext2fs_do_orphan_file_block_csum(fs, + pd->ino, pd->generation, blk, pd->buf)); + if (new_crc == tail->ob_checksum) + return 0; + tail->ob_checksum = new_crc; + pd->errcode = io_channel_write_blk64(fs->io, blk, 1, pd->buf); + if (pd->errcode) + return BLOCK_ABORT; + return 0; +} + +/* + * Fix the checksums in orphan_file inode + */ +static errcode_t fix_orphan_file_inode(ext2_filsys fs) +{ + struct process_orphan_block_data pd; + struct ext2_inode inode; + errcode_t retval; + ext2_ino_t orphan_inum; + char *orphan_buf; + + if (!ext2fs_has_feature_orphan_file(fs->super) || + !ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + orphan_inum = fs->super->s_orphan_file_inum; + retval = ext2fs_read_inode(fs, orphan_inum, &inode); + if (retval) + return retval; + orphan_buf = malloc(fs->blocksize * 4); + if (!orphan_buf) + return ENOMEM; + + pd.errcode = 0; + pd.buf = orphan_buf + 3 * fs->blocksize; + pd.ino = orphan_inum; + pd.generation = inode.i_generation; + + retval = ext2fs_block_iterate3(fs, fs->super->s_orphan_file_inum, + BLOCK_FLAG_DATA_ONLY, + orphan_buf, process_orphan_block, &pd); + return (retval ? retval : pd.errcode); +} + /* * Finally, recalculate the summary information */ -- 1.8.3.1