csum.c revision c4dcb1c10ae5e3d523823fe0a2c84d0841ca2ea1
1/*
2 * csum.c --- checksumming of ext3 structures
3 *
4 * Copyright (C) 2006 Cluster File Systems, Inc.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include "ext2_fs.h"
13#include "ext2fs.h"
14#include "crc16.h"
15#include <assert.h>
16
17#ifndef offsetof
18#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
19#endif
20
21#ifdef DEBUG
22#define STATIC
23#else
24#define STATIC static
25#endif
26
27STATIC __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
28{
29	__u16 crc = 0;
30	struct ext2_group_desc *desc;
31
32	desc = &fs->group_desc[group];
33
34	if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
35		int offset = offsetof(struct ext2_group_desc, bg_checksum);
36
37#ifdef WORDS_BIGENDIAN
38		struct ext2_group_desc swabdesc = *desc;
39
40		/* Have to swab back to little-endian to do the checksum */
41		ext2fs_swap_group_desc(&swabdesc);
42		desc = &swabdesc;
43
44		group = ext2fs_swab32(group);
45#endif
46		crc = ext2fs_crc16(~0, fs->super->s_uuid,
47				   sizeof(fs->super->s_uuid));
48		crc = ext2fs_crc16(crc, &group, sizeof(group));
49		crc = ext2fs_crc16(crc, desc, offset);
50		offset += sizeof(desc->bg_checksum); /* skip checksum */
51		assert(offset == sizeof(*desc));
52		/* for checksum of struct ext4_group_desc do the rest...*/
53		if (offset < fs->super->s_desc_size) {
54			crc = ext2fs_crc16(crc, (char *)desc + offset,
55				    fs->super->s_desc_size - offset);
56		}
57	}
58
59	return crc;
60}
61
62int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group)
63{
64	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
65				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
66	    (fs->group_desc[group].bg_checksum !=
67	     ext2fs_group_desc_csum(fs, group)))
68		return 0;
69
70	return 1;
71}
72
73void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group)
74{
75	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
76				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
77		fs->group_desc[group].bg_checksum =
78			ext2fs_group_desc_csum(fs, group);
79}
80
81static __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap,
82				   __u32 inodes_per_grp, dgrp_t grp_no)
83{
84	ext2_ino_t i, start_ino, end_ino;
85
86	start_ino = grp_no * inodes_per_grp + 1;
87	end_ino = start_ino + inodes_per_grp - 1;
88
89	for (i = end_ino; i >= start_ino; i--) {
90		if (ext2fs_fast_test_inode_bitmap(bitmap, i))
91			return i - start_ino + 1;
92	}
93	return inodes_per_grp;
94}
95
96/* update the bitmap flags, set the itable high watermark, and calculate
97 * checksums for the group descriptors */
98errcode_t ext2fs_set_gdt_csum(ext2_filsys fs)
99{
100	struct ext2_super_block *sb = fs->super;
101	struct ext2_group_desc *bg = fs->group_desc;
102	int dirty = 0;
103	dgrp_t i;
104
105	if (!fs->inode_map)
106		return EXT2_ET_NO_INODE_BITMAP;
107
108	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
109					EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
110		return 0;
111
112	for (i = 0; i < fs->group_desc_count; i++, bg++) {
113		int old_csum = bg->bg_checksum;
114		int old_unused = bg->bg_itable_unused;
115		int old_flags = bg->bg_flags;
116
117		if (bg->bg_free_inodes_count == sb->s_inodes_per_group) {
118			bg->bg_flags |= EXT2_BG_INODE_UNINIT;
119			bg->bg_itable_unused = sb->s_inodes_per_group;
120		} else {
121			bg->bg_flags &= ~EXT2_BG_INODE_UNINIT;
122			bg->bg_itable_unused = sb->s_inodes_per_group -
123				find_last_inode_ingrp(fs->inode_map,
124						      sb->s_inodes_per_group,i);
125		}
126
127		ext2fs_group_desc_csum_set(fs, i);
128		if (old_flags != bg->bg_flags)
129			dirty = 1;
130		if (old_unused != bg->bg_itable_unused)
131			dirty = 1;
132		if (old_csum != bg->bg_checksum)
133			dirty = 1;
134	}
135	if (dirty)
136		ext2fs_mark_super_dirty(fs);
137	return 0;
138}
139