csum.c revision c816ecb204a32e67788738e050ff2b14a721672b
1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* 2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * csum.c --- checksumming of ext3 structures 3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Copyright (C) 2006 Cluster File Systems, Inc. 5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Copyright (C) 2006, 2007 by Andreas Dilger <adilger@clusterfs.com> 6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * %Begin-Header% 8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * This file may be redistributed under the terms of the GNU Library 9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * General Public License, version 2. 10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * %End-Header% 11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if HAVE_SYS_TYPES_H 14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <sys/types.h> 15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif 16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ext2_fs.h" 18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ext2fs.h" 19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "crc16.h" 20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <assert.h> 21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifndef offsetof 23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif 25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifdef DEBUG 27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define STATIC 28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#else 29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define STATIC static 30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif 31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgSTATIC __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group) 33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __u16 crc = 0; 35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct ext2_group_desc *desc; 36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org desc = &fs->group_desc[group]; 38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) { 40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org int offset = offsetof(struct ext2_group_desc, bg_checksum); 41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifdef WORDS_BIGENDIAN 43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct ext2_group_desc swabdesc = *desc; 44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* Have to swab back to little-endian to do the checksum */ 46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org ext2fs_swap_group_desc(&swabdesc); 47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org desc = &swabdesc; 48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org group = ext2fs_swab32(group); 50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif 51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org crc = ext2fs_crc16(~0, fs->super->s_uuid, 52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org sizeof(fs->super->s_uuid)); 53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org crc = ext2fs_crc16(crc, &group, sizeof(group)); 54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org crc = ext2fs_crc16(crc, desc, offset); 55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org offset += sizeof(desc->bg_checksum); /* skip checksum */ 56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(offset == sizeof(*desc)); 57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* for checksum of struct ext4_group_desc do the rest...*/ 58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (offset < fs->super->s_desc_size) { 59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org crc = ext2fs_crc16(crc, (char *)desc + offset, 60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fs->super->s_desc_size - offset); 61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return crc; 65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group) 68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, 70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && 71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org (fs->group_desc[group].bg_checksum != 72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org ext2fs_group_desc_csum(fs, group))) 73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return 0; 74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return 1; 76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group) 79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, 81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) 82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fs->group_desc[group].bg_checksum = 83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org ext2fs_group_desc_csum(fs, group); 84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap, 87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __u32 inodes_per_grp, dgrp_t grp_no) 88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org ext2_ino_t i, start_ino, end_ino; 90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org start_ino = grp_no * inodes_per_grp + 1; 92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org end_ino = start_ino + inodes_per_grp - 1; 93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (i = end_ino; i >= start_ino; i--) { 95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (ext2fs_fast_test_inode_bitmap(bitmap, i)) 96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return i - start_ino + 1; 97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return inodes_per_grp; 99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* update the bitmap flags, set the itable high watermark, and calculate 102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * checksums for the group descriptors */ 103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgerrcode_t ext2fs_set_gdt_csum(ext2_filsys fs) 104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct ext2_super_block *sb = fs->super; 106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct ext2_group_desc *bg = fs->group_desc; 107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org int dirty = 0; 108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org dgrp_t i; 109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!fs->inode_map) 111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return EXT2_ET_NO_INODE_BITMAP; 112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, 114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) 115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return 0; 116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (i = 0; i < fs->group_desc_count; i++, bg++) { 118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org int old_csum = bg->bg_checksum; 119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org int old_unused = bg->bg_itable_unused; 120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org int old_flags = bg->bg_flags; 121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (bg->bg_free_inodes_count == sb->s_inodes_per_group) { 123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org bg->bg_flags |= EXT2_BG_INODE_UNINIT; 124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org bg->bg_itable_unused = sb->s_inodes_per_group; 125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else { 126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org bg->bg_flags &= ~EXT2_BG_INODE_UNINIT; 127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org bg->bg_itable_unused = sb->s_inodes_per_group - 128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org find_last_inode_ingrp(fs->inode_map, 129 sb->s_inodes_per_group,i); 130 } 131 132 ext2fs_group_desc_csum_set(fs, i); 133 if (old_flags != bg->bg_flags) 134 dirty = 1; 135 if (old_unused != bg->bg_itable_unused) 136 dirty = 1; 137 if (old_csum != bg->bg_checksum) 138 dirty = 1; 139 } 140 if (dirty) 141 ext2fs_mark_super_dirty(fs); 142 return 0; 143} 144 145#ifdef DEBUG 146#include "e2p/e2p.h" 147 148void print_csum(const char *msg, ext2_filsys fs, dgrp_t group) 149{ 150 __u16 crc1, crc2, crc3; 151 dgrp_t swabgroup; 152 struct ext2_group_desc *desc = &fs->group_desc[group]; 153 struct ext2_super_block *sb = fs->super; 154 155#ifdef WORDS_BIGENDIAN 156 struct ext2_group_desc swabdesc = fs->group_desc[group]; 157 158 /* Have to swab back to little-endian to do the checksum */ 159 ext2fs_swap_group_desc(&swabdesc); 160 desc = &swabdesc; 161 162 swabgroup = ext2fs_swab32(group); 163#else 164 swabgroup = group; 165#endif 166 167 crc1 = ext2fs_crc16(~0, sb->s_uuid, sizeof(fs->super->s_uuid)); 168 crc2 = ext2fs_crc16(crc1, &swabgroup, sizeof(swabgroup)); 169 crc3 = ext2fs_crc16(crc2, desc, 170 offsetof(struct ext2_group_desc, bg_checksum)); 171 printf("%s: UUID %s(%04x), grp %u(%04x): %04x=%04x\n", 172 msg, e2p_uuid2str(sb->s_uuid), crc1, group, crc2,crc3, 173 ext2fs_group_desc_csum(fs, group)); 174} 175 176unsigned char sb_uuid[16] = { 0x4f, 0x25, 0xe8, 0xcf, 0xe7, 0x97, 0x48, 0x23, 177 0xbe, 0xfa, 0xa7, 0x88, 0x4b, 0xae, 0xec, 0xdb }; 178 179int main(int argc, char **argv) 180{ 181 struct ext2_super_block param; 182 errcode_t retval; 183 ext2_filsys fs; 184 int i; 185 __u16 csum1, csum2, csum_known = 0xd3a4; 186 187 memset(¶m, 0, sizeof(param)); 188 param.s_blocks_count = 32768; 189 190 retval = ext2fs_initialize("test fs", 0, ¶m, 191 test_io_manager, &fs); 192 if (retval) { 193 com_err("setup", retval, 194 "While initializing filesystem"); 195 exit(1); 196 } 197 memcpy(fs->super->s_uuid, sb_uuid, 16); 198 fs->super->s_feature_ro_compat = EXT4_FEATURE_RO_COMPAT_GDT_CSUM; 199 200 for (i=0; i < fs->group_desc_count; i++) { 201 fs->group_desc[i].bg_block_bitmap = 124; 202 fs->group_desc[i].bg_inode_bitmap = 125; 203 fs->group_desc[i].bg_inode_table = 126; 204 fs->group_desc[i].bg_free_blocks_count = 31119; 205 fs->group_desc[i].bg_free_inodes_count = 15701; 206 fs->group_desc[i].bg_used_dirs_count = 2; 207 fs->group_desc[i].bg_flags = 0; 208 }; 209 210 csum1 = ext2fs_group_desc_csum(fs, 0); 211 print_csum("csum0000", fs, 0); 212 213 if (csum1 != csum_known) { 214 printf("checksum for group 0 should be %04x\n", csum_known); 215 exit(1); 216 } 217 csum2 = ext2fs_group_desc_csum(fs, 1); 218 print_csum("csum0001", fs, 1); 219 if (csum1 == csum2) { 220 printf("checksums for different groups shouldn't match\n"); 221 exit(1); 222 } 223 csum2 = ext2fs_group_desc_csum(fs, 2); 224 print_csum("csumffff", fs, 2); 225 if (csum1 == csum2) { 226 printf("checksums for different groups shouldn't match\n"); 227 exit(1); 228 } 229 fs->group_desc[0].bg_checksum = csum1; 230 csum2 = ext2fs_group_desc_csum(fs, 0); 231 print_csum("csum_set", fs, 0); 232 if (csum1 != csum2) { 233 printf("checksums should not depend on checksum field\n"); 234 exit(1); 235 } 236 if (!ext2fs_group_desc_csum_verify(fs, 0)) { 237 printf("checksums should verify against gd_checksum\n"); 238 exit(1); 239 } 240 memset(fs->super->s_uuid, 0x30, sizeof(fs->super->s_uuid)); 241 print_csum("new_uuid", fs, 0); 242 if (ext2fs_group_desc_csum_verify(fs, 0) != 0) { 243 printf("checksums for different filesystems shouldn't match\n"); 244 exit(1); 245 } 246 csum1 = fs->group_desc[0].bg_checksum = ext2fs_group_desc_csum(fs, 0); 247 print_csum("csum_new", fs, 0); 248 fs->group_desc[0].bg_free_blocks_count = 1; 249 csum2 = ext2fs_group_desc_csum(fs, 0); 250 print_csum("csum_blk", fs, 0); 251 if (csum1 == csum2) { 252 printf("checksums for different data shouldn't match\n"); 253 exit(1); 254 } 255 256 return 0; 257} 258#endif 259