2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2017, Fedor Uporov
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/types.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/vnode.h>
41 #include <sys/endian.h>
43 #include <sys/gsb_crc32.h>
44 #include <sys/crc16.h>
45 #include <sys/mount.h>
47 #include <fs/ext2fs/fs.h>
48 #include <fs/ext2fs/ext2fs.h>
49 #include <fs/ext2fs/ext2_dinode.h>
50 #include <fs/ext2fs/inode.h>
51 #include <fs/ext2fs/ext2_dir.h>
52 #include <fs/ext2fs/htree.h>
53 #include <fs/ext2fs/ext2_extattr.h>
54 #include <fs/ext2fs/ext2_extern.h>
56 SDT_PROVIDER_DECLARE(ext2fs);
59 * arg0: verbosity. Higher numbers give more verbose messages
60 * arg1: Textual message
62 SDT_PROBE_DEFINE2(ext2fs, , trace, csum, "int", "char*");
64 #define EXT2_BG_INODE_BITMAP_CSUM_HI_END \
65 (offsetof(struct ext2_gd, ext4bgd_i_bmap_csum_hi) + \
68 #define EXT2_INODE_CSUM_HI_EXTRA_END \
69 (offsetof(struct ext2fs_dinode, e2di_chksum_hi) + sizeof(uint16_t) - \
72 #define EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION \
73 (offsetof(struct ext2_gd, ext4bgd_b_bmap_csum_hi) + \
77 ext2_sb_csum_set_seed(struct m_ext2fs *fs)
80 if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_CSUM_SEED))
81 fs->e2fs_csum_seed = le32toh(fs->e2fs->e4fs_chksum_seed);
82 else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
83 fs->e2fs_csum_seed = calculate_crc32c(~0, fs->e2fs->e2fs_uuid,
84 sizeof(fs->e2fs->e2fs_uuid));
87 fs->e2fs_csum_seed = 0;
91 ext2_sb_csum_verify(struct m_ext2fs *fs)
94 if (fs->e2fs->e4fs_chksum_type != EXT4_CRC32C_CHKSUM) {
96 "WARNING: mount of %s denied due bad sb csum type\n", fs->e2fs_fsmnt);
99 if (le32toh(fs->e2fs->e4fs_sbchksum) !=
100 calculate_crc32c(~0, (const char *)fs->e2fs,
101 offsetof(struct ext2fs, e4fs_sbchksum))) {
103 "WARNING: mount of %s denied due bad sb csum=0x%x, expected=0x%x - run fsck\n",
104 fs->e2fs_fsmnt, le32toh(fs->e2fs->e4fs_sbchksum),
105 calculate_crc32c(~0, (const char *)fs->e2fs,
106 offsetof(struct ext2fs, e4fs_sbchksum)));
114 ext2_sb_csum_set(struct m_ext2fs *fs)
117 fs->e2fs->e4fs_sbchksum =
118 htole32(calculate_crc32c(~0, (const char *)fs->e2fs,
119 offsetof(struct ext2fs, e4fs_sbchksum)));
123 ext2_extattr_blk_csum(struct inode *ip, uint64_t facl,
124 struct ext2fs_extattr_header *header)
127 uint32_t crc, dummy_crc = 0;
128 uint64_t facl_bn = htole64(facl);
129 int offset = offsetof(struct ext2fs_extattr_header, h_checksum);
133 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&facl_bn,
135 crc = calculate_crc32c(crc, (uint8_t *)header, offset);
136 crc = calculate_crc32c(crc, (uint8_t *)&dummy_crc,
138 offset += sizeof(dummy_crc);
139 crc = calculate_crc32c(crc, (uint8_t *)header + offset,
140 fs->e2fs_bsize - offset);
142 return (htole32(crc));
146 ext2_extattr_blk_csum_verify(struct inode *ip, struct buf *bp)
148 struct ext2fs_extattr_header *header;
150 header = (struct ext2fs_extattr_header *)bp->b_data;
152 if (EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM) &&
153 (header->h_checksum != ext2_extattr_blk_csum(ip, ip->i_facl, header))) {
154 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad extattr csum detected");
162 ext2_extattr_blk_csum_set(struct inode *ip, struct buf *bp)
164 struct ext2fs_extattr_header *header;
166 if (!EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
169 header = (struct ext2fs_extattr_header *)bp->b_data;
170 header->h_checksum = ext2_extattr_blk_csum(ip, ip->i_facl, header);
174 ext2_init_dirent_tail(struct ext2fs_direct_tail *tp)
176 memset(tp, 0, sizeof(struct ext2fs_direct_tail));
177 tp->e2dt_rec_len = le16toh(sizeof(struct ext2fs_direct_tail));
178 tp->e2dt_reserved_ft = EXT2_FT_DIR_CSUM;
182 ext2_is_dirent_tail(struct inode *ip, struct ext2fs_direct_2 *ep)
185 struct ext2fs_direct_tail *tp;
189 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
192 tp = (struct ext2fs_direct_tail *)ep;
193 if (tp->e2dt_reserved_zero1 == 0 &&
194 le16toh(tp->e2dt_rec_len) == sizeof(struct ext2fs_direct_tail) &&
195 tp->e2dt_reserved_zero2 == 0 &&
196 tp->e2dt_reserved_ft == EXT2_FT_DIR_CSUM)
202 struct ext2fs_direct_tail *
203 ext2_dirent_get_tail(struct inode *ip, struct ext2fs_direct_2 *ep)
205 struct ext2fs_direct_2 *dep;
207 unsigned int rec_len;
210 top = EXT2_DIRENT_TAIL(ep, ip->i_e2fs->e2fs_bsize);
211 rec_len = le16toh(dep->e2d_reclen);
213 while (rec_len && !(rec_len & 0x3)) {
214 dep = (struct ext2fs_direct_2 *)(((char *)dep) + rec_len);
215 if ((void *)dep >= top)
217 rec_len = le16toh(dep->e2d_reclen);
223 if (ext2_is_dirent_tail(ip, dep))
224 return ((struct ext2fs_direct_tail *)dep);
230 ext2_dirent_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int size)
234 uint32_t inum, gen, crc;
240 inum = htole32(ip->i_number);
241 gen = htole32(ip->i_gen);
242 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
243 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
244 crc = calculate_crc32c(crc, (uint8_t *)buf, size);
250 ext2_dirent_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
253 struct ext2fs_direct_tail *tp;
255 tp = ext2_dirent_get_tail(ip, ep);
259 calculated = ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
260 if (calculated != le32toh(tp->e2dt_checksum))
266 static struct ext2fs_htree_count *
267 ext2_get_dx_count(struct inode *ip, struct ext2fs_direct_2 *ep, int *offset)
269 struct ext2fs_direct_2 *dp;
270 struct ext2fs_htree_root_info *root;
273 if (le16toh(ep->e2d_reclen) == EXT2_BLOCK_SIZE(ip->i_e2fs))
275 else if (le16toh(ep->e2d_reclen) == 12) {
276 dp = (struct ext2fs_direct_2 *)(((char *)ep) + 12);
277 if (le16toh(dp->e2d_reclen) != EXT2_BLOCK_SIZE(ip->i_e2fs) - 12)
280 root = (struct ext2fs_htree_root_info *)(((char *)dp + 12));
281 if (root->h_reserved1 ||
282 root->h_info_len != sizeof(struct ext2fs_htree_root_info))
290 *offset = count_offset;
292 return ((struct ext2fs_htree_count *)(((char *)ep) + count_offset));
296 ext2_dx_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int count_offset,
297 int count, struct ext2fs_htree_tail *tp)
302 uint32_t inum, old_csum, gen, crc;
308 size = count_offset + (count * sizeof(struct ext2fs_htree_entry));
309 old_csum = tp->ht_checksum;
312 inum = htole32(ip->i_number);
313 gen = htole32(ip->i_gen);
314 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
315 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
316 crc = calculate_crc32c(crc, (uint8_t *)buf, size);
317 crc = calculate_crc32c(crc, (uint8_t *)tp, sizeof(struct ext2fs_htree_tail));
318 tp->ht_checksum = old_csum;
324 ext2_dx_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
327 struct ext2fs_htree_count *cp;
328 struct ext2fs_htree_tail *tp;
329 int count_offset, limit, count;
331 cp = ext2_get_dx_count(ip, ep, &count_offset);
335 limit = le16toh(cp->h_entries_max);
336 count = le16toh(cp->h_entries_num);
337 if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
338 ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
341 tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
342 calculated = ext2_dx_csum(ip, ep, count_offset, count, tp);
344 if (tp->ht_checksum != calculated)
351 ext2_dir_blk_csum_verify(struct inode *ip, struct buf *bp)
354 struct ext2fs_direct_2 *ep;
359 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
362 ep = (struct ext2fs_direct_2 *)bp->b_data;
364 if (ext2_dirent_get_tail(ip, ep) != NULL)
365 error = ext2_dirent_csum_verify(ip, ep);
366 else if (ext2_get_dx_count(ip, ep, NULL) != NULL)
367 error = ext2_dx_csum_verify(ip, ep);
370 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad directory csum detected");
376 ext2_dirent_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
379 struct ext2fs_direct_tail *tp;
383 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
386 tp = ext2_dirent_get_tail(ip, ep);
391 htole32(ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep));
395 ext2_dx_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
398 struct ext2fs_htree_count *cp;
399 struct ext2fs_htree_tail *tp;
400 int count_offset, limit, count;
404 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
407 cp = ext2_get_dx_count(ip, ep, &count_offset);
411 limit = le16toh(cp->h_entries_max);
412 count = le16toh(cp->h_entries_num);
413 if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
414 ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
417 tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
418 tp->ht_checksum = ext2_dx_csum(ip, ep, count_offset, count, tp);
422 ext2_extent_blk_csum(struct inode *ip, struct ext4_extent_header *ehp)
426 uint32_t inum, gen, crc;
430 size = EXT4_EXTENT_TAIL_OFFSET(ehp) +
431 offsetof(struct ext4_extent_tail, et_checksum);
433 inum = htole32(ip->i_number);
434 gen = htole32(ip->i_gen);
435 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
436 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
437 crc = calculate_crc32c(crc, (uint8_t *)ehp, size);
443 ext2_extent_blk_csum_verify(struct inode *ip, void *data)
446 struct ext4_extent_header *ehp;
447 struct ext4_extent_tail *etp;
448 uint32_t provided, calculated;
452 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
455 ehp = (struct ext4_extent_header *)data;
456 etp = (struct ext4_extent_tail *)(((char *)ehp) +
457 EXT4_EXTENT_TAIL_OFFSET(ehp));
459 provided = le32toh(etp->et_checksum);
460 calculated = ext2_extent_blk_csum(ip, ehp);
462 if (provided != calculated) {
463 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad extent csum detected");
471 ext2_extent_blk_csum_set(struct inode *ip, void *data)
474 struct ext4_extent_header *ehp;
475 struct ext4_extent_tail *etp;
479 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
482 ehp = (struct ext4_extent_header *)data;
483 etp = (struct ext4_extent_tail *)(((char *)data) +
484 EXT4_EXTENT_TAIL_OFFSET(ehp));
486 etp->et_checksum = htole32(ext2_extent_blk_csum(ip,
487 (struct ext4_extent_header *)data));
491 ext2_gd_i_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
493 uint32_t hi, provided, calculated;
495 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
498 provided = le16toh(fs->e2fs_gd[cg].ext4bgd_i_bmap_csum);
499 calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
501 if (le16toh(fs->e2fs->e3fs_desc_size) >=
502 EXT2_BG_INODE_BITMAP_CSUM_HI_END) {
503 hi = le16toh(fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi);
504 provided |= (hi << 16);
506 calculated &= 0xFFFF;
508 if (provided != calculated) {
509 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad inode bitmap csum detected");
517 ext2_gd_i_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
521 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
524 csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
526 fs->e2fs_gd[cg].ext4bgd_i_bmap_csum = htole16(csum & 0xFFFF);
527 if (le16toh(fs->e2fs->e3fs_desc_size) >= EXT2_BG_INODE_BITMAP_CSUM_HI_END)
528 fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi = htole16(csum >> 16);
532 ext2_gd_b_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
534 uint32_t hi, provided, calculated, size;
536 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
539 size = fs->e2fs_fpg / 8;
540 provided = le16toh(fs->e2fs_gd[cg].ext4bgd_b_bmap_csum);
541 calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
542 if (le16toh(fs->e2fs->e3fs_desc_size) >=
543 EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) {
544 hi = le16toh(fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi);
545 provided |= (hi << 16);
547 calculated &= 0xFFFF;
549 if (provided != calculated) {
550 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad block bitmap csum detected");
558 ext2_gd_b_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
562 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
565 size = fs->e2fs_fpg / 8;
566 csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
567 fs->e2fs_gd[cg].ext4bgd_b_bmap_csum = htole16(csum & 0xFFFF);
568 if (le16toh(fs->e2fs->e3fs_desc_size) >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
569 fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi = htole16(csum >> 16);
573 ext2_ei_csum(struct inode *ip, struct ext2fs_dinode *ei)
576 uint32_t inode_csum_seed, inum, gen, crc;
577 uint16_t dummy_csum = 0;
578 unsigned int offset, csum_size;
581 offset = offsetof(struct ext2fs_dinode, e2di_chksum_lo);
582 csum_size = sizeof(dummy_csum);
583 inum = htole32(ip->i_number);
584 crc = calculate_crc32c(fs->e2fs_csum_seed,
585 (uint8_t *)&inum, sizeof(inum));
586 gen = htole32(ip->i_gen);
587 inode_csum_seed = calculate_crc32c(crc,
588 (uint8_t *)&gen, sizeof(gen));
590 crc = calculate_crc32c(inode_csum_seed, (uint8_t *)ei, offset);
591 crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum, csum_size);
593 crc = calculate_crc32c(crc, (uint8_t *)ei + offset,
594 E2FS_REV0_INODE_SIZE - offset);
596 if (EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE) {
597 offset = offsetof(struct ext2fs_dinode, e2di_chksum_hi);
598 crc = calculate_crc32c(crc, (uint8_t *)ei +
599 E2FS_REV0_INODE_SIZE, offset - E2FS_REV0_INODE_SIZE);
601 if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE &&
602 le16toh(ei->e2di_extra_isize) >=
603 EXT2_INODE_CSUM_HI_EXTRA_END)) {
604 crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum,
609 crc = calculate_crc32c(crc, (uint8_t *)ei + offset,
610 EXT2_INODE_SIZE(fs) - offset);
617 ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei)
620 const static struct ext2fs_dinode ei_zero;
621 uint32_t hi, provided, calculated;
625 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
628 provided = le16toh(ei->e2di_chksum_lo);
629 calculated = ext2_ei_csum(ip, ei);
631 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
632 le16toh(ei->e2di_extra_isize) >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
633 hi = le16toh(ei->e2di_chksum_hi);
634 provided |= hi << 16;
636 calculated &= 0xFFFF;
638 if (provided != calculated) {
640 * If it is first time used dinode,
641 * it is expected that it will be zeroed
642 * and we will not return checksum error in this case.
644 if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode)))
647 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad inode csum");
656 ext2_ei_csum_set(struct inode *ip, struct ext2fs_dinode *ei)
663 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
666 crc = ext2_ei_csum(ip, ei);
668 ei->e2di_chksum_lo = htole16(crc & 0xFFFF);
669 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
670 le16toh(ei->e2di_extra_isize) >= EXT2_INODE_CSUM_HI_EXTRA_END))
671 ei->e2di_chksum_hi = htole16(crc >> 16);
675 ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd)
679 uint16_t crc, dummy_csum;
681 offset = offsetof(struct ext2_gd, ext4bgd_csum);
683 block_group = htole32(block_group);
685 if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
686 csum32 = calculate_crc32c(fs->e2fs_csum_seed,
687 (uint8_t *)&block_group, sizeof(block_group));
688 csum32 = calculate_crc32c(csum32, (uint8_t *)gd, offset);
690 csum32 = calculate_crc32c(csum32, (uint8_t *)&dummy_csum,
692 offset += sizeof(dummy_csum);
693 if (offset < le16toh(fs->e2fs->e3fs_desc_size))
694 csum32 = calculate_crc32c(csum32, (uint8_t *)gd + offset,
695 le16toh(fs->e2fs->e3fs_desc_size) - offset);
697 crc = csum32 & 0xFFFF;
698 return (htole16(crc));
699 } else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
700 crc = crc16(~0, fs->e2fs->e2fs_uuid,
701 sizeof(fs->e2fs->e2fs_uuid));
702 crc = crc16(crc, (uint8_t *)&block_group,
703 sizeof(block_group));
704 crc = crc16(crc, (uint8_t *)gd, offset);
705 offset += sizeof(gd->ext4bgd_csum); /* skip checksum */
706 if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) &&
707 offset < le16toh(fs->e2fs->e3fs_desc_size))
708 crc = crc16(crc, (uint8_t *)gd + offset,
709 le16toh(fs->e2fs->e3fs_desc_size) - offset);
710 return (htole16(crc));
717 ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev)
722 for (i = 0; i < fs->e2fs_gcount; i++) {
723 if (fs->e2fs_gd[i].ext4bgd_csum !=
724 ext2_gd_csum(fs, i, &fs->e2fs_gd[i])) {
726 "WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n",
727 devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum,
728 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]));
738 ext2_gd_csum_set(struct m_ext2fs *fs)
742 for (i = 0; i < fs->e2fs_gcount; i++)
743 fs->e2fs_gd[i].ext4bgd_csum = ext2_gd_csum(fs, i, &fs->e2fs_gd[i]);