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