On Sun, Sep 04, 2011 at 11:59:44AM -0600, Andreas Dilger wrote: > On 2011-08-31, at 6:35 PM, "Darrick J. Wong" <djwong@xxxxxxxxxx> wrote: > > > This patch adds the ability for the libext2fs functions to read and write the > > inode checksum. It also fixes a few fields that were omitted from the byte > > swapping routines. > > > > Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> > > --- > > lib/ext2fs/csum.c | 59 +++++++++++++++++++++++++++++++++++++++++++++ > > lib/ext2fs/ext2_err.et.in | 9 +++++++ > > lib/ext2fs/ext2_fs.h | 4 ++- > > lib/ext2fs/ext2fs.h | 6 +++++ > > lib/ext2fs/inode.c | 20 +++++++++++++++ > > lib/ext2fs/swapfs.c | 10 ++++++-- > > 6 files changed, 104 insertions(+), 4 deletions(-) > > > > > > diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c > > index 2fece68..57adc4c 100644 > > --- a/lib/ext2fs/csum.c > > +++ b/lib/ext2fs/csum.c > > @@ -29,6 +29,65 @@ > > #define STATIC static > > #endif > > > > +__u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum, > > + struct ext2_inode_large *inode) > > +{ > > + struct ext2_inode_large *desc = inode; > > + int offset = offsetof(struct ext2_inode_large, i_checksum); > > + int extra_size = inode->i_extra_isize; > > + size_t size = fs->super->s_inode_size; > > + __u32 crc = 0; > > + > > + if (size < EXT2_GOOD_OLD_INODE_SIZE + extra_size) > > + printf("ERROR: inode %d size %d != extra_size %d!\n", inum, > > + size, extra_size + EXT2_GOOD_OLD_INODE_SIZE); > > This shouldn't have to be checked for every inode checksum. If the checksum > is covering the whole inode size then this is a constant size, and e2fsck is > already checking the value of i_extra_isize. This actually comes out later in the patchset when I change the checksum to cover the entire inode size. I'll remove this hunk since it goes away. --D > > > + if (fs->super->s_creator_os != EXT2_OS_LINUX) > > + return 0; > > + > > + if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, > > + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) > > + > > + return 0; > > + > > +#ifdef WORDS_BIGENDIAN > > + char buf[EXT2_INODE_CORE_SIZE(fs->super)]; > > + struct ext2_inode_large *swabinode = (struct ext2_inode_large *)buf; > > + > > + /* Have to swab back to little-endian to do the checksum */ > > + memcpy(swabinode, inode, size); > > + ext2fs_swap_inode_full(fs, swabinode, swabinode, 1, size); > > + desc = swabinode; > > +#endif > > + inum = ext2fs_cpu_to_le32(inum); > > + crc = crc32c_le(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid)); > > + crc = crc32c_le(crc, (char *)&inum, sizeof(inum)); > > + crc = crc32c_le(crc, (char *)desc, offset); > > + offset += sizeof(inode->i_checksum); /* skip checksum */ > > + crc = crc32c_le(crc, (char *)desc + offset, > > + EXT2_GOOD_OLD_INODE_SIZE + extra_size - offset); > > + return crc; > > +} > > + > > +int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum, > > + struct ext2_inode_large *inode) > > +{ > > + if (fs->super->s_creator_os == EXT2_OS_LINUX && > > + EXT2_HAS_RO_COMPAT_FEATURE(fs->super, > > + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && > > + (inode->i_checksum != ext2fs_inode_csum(fs, inum, inode))) > > + return 0; > > + return 1; > > +} > > + > > +void ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum, > > + struct ext2_inode_large *inode) > > +{ > > + if (fs->super->s_creator_os != EXT2_OS_LINUX) > > + return; > > + inode->i_checksum = ext2fs_inode_csum(fs, inum, inode); > > +} > > + > > STATIC __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group) > > { > > __u16 crc = 0; > > diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in > > index 995ddc3..31c8fe1 100644 > > --- a/lib/ext2fs/ext2_err.et.in > > +++ b/lib/ext2fs/ext2_err.et.in > > @@ -422,4 +422,13 @@ ec EXT2_NO_MTAB_FILE, > > ec EXT2_ET_CANT_USE_LEGACY_BITMAPS, > > "Filesystem too large to use legacy bitmaps" > > > > +ec EXT2_ET_INODE_CSUM_INVALID, > > + "Inode checksum is incorrect" > > + > > +ec EXT2_ET_INODE_CORRUPT, > > + "Inode checksum indicates corruption" > > + > > +ec EXT2_ET_INODE_CSUM_NONZERO, > > + "Inode checksum should not be set" > > + > > end > > diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h > > index ae7662e..1f08673 100644 > > --- a/lib/ext2fs/ext2_fs.h > > +++ b/lib/ext2fs/ext2_fs.h > > @@ -362,7 +362,7 @@ struct ext2_inode_large { > > __u16 l_i_file_acl_high; > > __u16 l_i_uid_high; /* these 2 fields */ > > __u16 l_i_gid_high; /* were reserved2[0] */ > > - __u32 l_i_reserved2; > > + __u32 l_i_checksum; /* crc32c(uuid+inum+inode) */ > > } linux2; > > struct { > > __u8 h_i_frag; /* Fragment number */ > > @@ -393,7 +393,7 @@ struct ext2_inode_large { > > #define i_gid_low i_gid > > #define i_uid_high osd2.linux2.l_i_uid_high > > #define i_gid_high osd2.linux2.l_i_gid_high > > -#define i_reserved2 osd2.linux2.l_i_reserved2 > > +#define i_checksum osd2.linux2.l_i_checksum > > #else > > #if defined(__GNU__) > > > > diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h > > index e571508..db8b28b 100644 > > --- a/lib/ext2fs/ext2fs.h > > +++ b/lib/ext2fs/ext2fs.h > > @@ -892,6 +892,12 @@ extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len); > > extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len); > > > > /* csum.c */ > > +extern __u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum, > > + struct ext2_inode_large *inode); > > +extern void ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum, > > + struct ext2_inode_large *inode); > > +extern int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum, > > + struct ext2_inode_large *inode); > > extern void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group); > > extern int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group); > > extern errcode_t ext2fs_set_gdt_csum(ext2_filsys fs); > > diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c > > index 76893fd..0789505 100644 > > --- a/lib/ext2fs/inode.c > > +++ b/lib/ext2fs/inode.c > > @@ -509,6 +509,12 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino, > > if (EXT2_INODE_SIZE(scan->fs->super) == EXT2_GOOD_OLD_INODE_SIZE) > > inode->i_extra_isize = 0; > > > > + /* Verify the inode checksum. */ > > + if (!(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && > > + !ext2fs_inode_csum_verify(scan->fs, scan->current_inode, inode)) > > + return EXT2_ET_INODE_CSUM_INVALID; > > + > > + > > scan->inodes_left--; > > scan->current_inode++; > > *ino = scan->current_inode; > > @@ -617,6 +623,10 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, > > (struct ext2_inode_large *) inode, > > 0, bufsize); > > #endif > > + /* Verify the inode checksum. */ > > + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && > > + !ext2fs_inode_csum_verify(fs, ino, inode)) > > + return EXT2_ET_INODE_CSUM_INVALID; > > > > /* Update the inode cache */ > > fs->icache->cache_last = (fs->icache->cache_last + 1) % > > @@ -685,6 +695,16 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, > > w_inode = &temp_inode; > > memset(w_inode, 0, length); > > > > + /* > > + * If inode checksum enabled, ensure that we actually have the whole > > + * inode in memory. > > + */ > > + if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE && > > + bufsize <= EXT2_GOOD_OLD_INODE_SIZE) { > > + fprintf(stderr, "inode %d has a too-short buffer!\n", ino); > > + abort(); > > + } > > + ext2fs_inode_csum_set(fs, ino, inode); > > #ifdef WORDS_BIGENDIAN > > ext2fs_swap_inode_full(fs, w_inode, inode, 1, bufsize); > > #else > > diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c > > index 517f1d7..df604ba 100644 > > --- a/lib/ext2fs/swapfs.c > > +++ b/lib/ext2fs/swapfs.c > > @@ -244,8 +244,7 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t, > > ext2fs_swab16 (f->osd2.linux2.l_i_uid_high); > > t->osd2.linux2.l_i_gid_high = > > ext2fs_swab16 (f->osd2.linux2.l_i_gid_high); > > - t->osd2.linux2.l_i_reserved2 = > > - ext2fs_swab32(f->osd2.linux2.l_i_reserved2); > > + t->i_checksum = ext2fs_swab32(f->i_checksum); > > break; > > case EXT2_OS_HURD: > > t->osd1.hurd1.h_i_translator = > > @@ -279,6 +278,13 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t, > > return; > > } > > > > + t->i_ctime_extra = ext2fs_swab32(f->i_ctime_extra); > > + t->i_mtime_extra = ext2fs_swab32(f->i_mtime_extra); > > + t->i_atime_extra = ext2fs_swab32(f->i_atime_extra); > > + t->i_crtime = ext2fs_swab32(f->i_crtime); > > + t->i_crtime_extra = ext2fs_swab32(f->i_crtime_extra); > > + t->i_version_hi = ext2fs_swab32(f->i_version_hi); > > + > > i = EXT2_GOOD_OLD_INODE_SIZE + extra_isize + sizeof(__u32); > > if (bufsize < (int) i) > > return; /* no space for EA magic */ > > > > -- > > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in > > the body of a message to majordomo@xxxxxxxxxxxxxxx > > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html