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>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/vnode.h>
40 #include <sys/endian.h>
42 #include <sys/mount.h>
44 #include <fs/ext2fs/fs.h>
45 #include <fs/ext2fs/ext2fs.h>
46 #include <fs/ext2fs/ext2_dinode.h>
47 #include <fs/ext2fs/inode.h>
48 #include <fs/ext2fs/ext2_dir.h>
49 #include <fs/ext2fs/htree.h>
50 #include <fs/ext2fs/ext2_extattr.h>
51 #include <fs/ext2fs/ext2_extern.h>
53 #define EXT2_BG_INODE_BITMAP_CSUM_HI_END \
54 (offsetof(struct ext2_gd, ext4bgd_i_bmap_csum_hi) + \
57 #define EXT2_INODE_CSUM_HI_EXTRA_END \
58 (offsetof(struct ext2fs_dinode, e2di_chksum_hi) + sizeof(uint16_t) - \
61 #define EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION \
62 (offsetof(struct ext2_gd, ext4bgd_b_bmap_csum_hi) + \
66 ext2_sb_csum_set_seed(struct m_ext2fs *fs)
69 if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_CSUM_SEED))
70 fs->e2fs_csum_seed = fs->e2fs->e4fs_chksum_seed;
71 else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
72 fs->e2fs_csum_seed = calculate_crc32c(~0, fs->e2fs->e2fs_uuid,
73 sizeof(fs->e2fs->e2fs_uuid));
76 fs->e2fs_csum_seed = 0;
80 ext2_sb_csum_verify(struct m_ext2fs *fs)
83 if (fs->e2fs->e4fs_chksum_type != EXT4_CRC32C_CHKSUM) {
85 "WARNING: mount of %s denied due bad sb csum type\n", fs->e2fs_fsmnt);
88 if (fs->e2fs->e4fs_sbchksum !=
89 calculate_crc32c(~0, (const char *)fs->e2fs,
90 offsetof(struct ext2fs, e4fs_sbchksum))) {
92 "WARNING: mount of %s denied due bad sb csum=0x%x, expected=0x%x - run fsck\n",
93 fs->e2fs_fsmnt, fs->e2fs->e4fs_sbchksum, calculate_crc32c(~0,
94 (const char *)fs->e2fs, offsetof(struct ext2fs, e4fs_sbchksum)));
102 ext2_sb_csum_set(struct m_ext2fs *fs)
105 fs->e2fs->e4fs_sbchksum = calculate_crc32c(~0, (const char *)fs->e2fs,
106 offsetof(struct ext2fs, e4fs_sbchksum));
110 ext2_extattr_blk_csum(struct inode *ip, uint64_t facl,
111 struct ext2fs_extattr_header *header)
114 uint32_t crc, old_crc;
118 old_crc = header->h_checksum;
120 header->h_checksum = 0;
121 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&facl, sizeof(facl));
122 crc = calculate_crc32c(crc, (uint8_t *)header, fs->e2fs_bsize);
123 header->h_checksum = old_crc;
129 ext2_extattr_blk_csum_verify(struct inode *ip, struct buf *bp)
131 struct ext2fs_extattr_header *header;
133 header = (struct ext2fs_extattr_header *)bp->b_data;
135 if (EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM) &&
136 (header->h_checksum != ext2_extattr_blk_csum(ip, ip->i_facl, header))) {
137 printf("WARNING: bad extattr csum detected, ip=%lu - run fsck\n",
138 (unsigned long)ip->i_number);
146 ext2_extattr_blk_csum_set(struct inode *ip, struct buf *bp)
148 struct ext2fs_extattr_header *header;
150 if (!EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
153 header = (struct ext2fs_extattr_header *)bp->b_data;
154 header->h_checksum = ext2_extattr_blk_csum(ip, ip->i_facl, header);
158 ext2_init_dirent_tail(struct ext2fs_direct_tail *tp)
160 memset(tp, 0, sizeof(struct ext2fs_direct_tail));
161 tp->e2dt_rec_len = sizeof(struct ext2fs_direct_tail);
162 tp->e2dt_reserved_ft = EXT2_FT_DIR_CSUM;
166 ext2_is_dirent_tail(struct inode *ip, struct ext2fs_direct_2 *ep)
169 struct ext2fs_direct_tail *tp;
173 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
176 tp = (struct ext2fs_direct_tail *)ep;
177 if (tp->e2dt_reserved_zero1 == 0 &&
178 tp->e2dt_rec_len == sizeof(struct ext2fs_direct_tail) &&
179 tp->e2dt_reserved_zero2 == 0 &&
180 tp->e2dt_reserved_ft == EXT2_FT_DIR_CSUM)
186 struct ext2fs_direct_tail *
187 ext2_dirent_get_tail(struct inode *ip, struct ext2fs_direct_2 *ep)
189 struct ext2fs_direct_2 *dep;
191 unsigned int rec_len;
194 top = EXT2_DIRENT_TAIL(ep, ip->i_e2fs->e2fs_bsize);
195 rec_len = dep->e2d_reclen;
197 while (rec_len && !(rec_len & 0x3)) {
198 dep = (struct ext2fs_direct_2 *)(((char *)dep) + rec_len);
199 if ((void *)dep >= top)
201 rec_len = dep->e2d_reclen;
207 if (ext2_is_dirent_tail(ip, dep))
208 return ((struct ext2fs_direct_tail *)dep);
214 ext2_dirent_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int size)
218 uint32_t inum, gen, crc;
226 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
227 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
228 crc = calculate_crc32c(crc, (uint8_t *)buf, size);
234 ext2_dirent_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
237 struct ext2fs_direct_tail *tp;
239 tp = ext2_dirent_get_tail(ip, ep);
243 calculated = ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
244 if (calculated != tp->e2dt_checksum)
250 static struct ext2fs_htree_count *
251 ext2_get_dx_count(struct inode *ip, struct ext2fs_direct_2 *ep, int *offset)
253 struct ext2fs_direct_2 *dp;
254 struct ext2fs_htree_root_info *root;
257 if (ep->e2d_reclen == EXT2_BLOCK_SIZE(ip->i_e2fs))
259 else if (ep->e2d_reclen == 12) {
260 dp = (struct ext2fs_direct_2 *)(((char *)ep) + 12);
261 if (dp->e2d_reclen != EXT2_BLOCK_SIZE(ip->i_e2fs) - 12)
264 root = (struct ext2fs_htree_root_info *)(((char *)dp + 12));
265 if (root->h_reserved1 ||
266 root->h_info_len != sizeof(struct ext2fs_htree_root_info))
274 *offset = count_offset;
276 return ((struct ext2fs_htree_count *)(((char *)ep) + count_offset));
280 ext2_dx_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int count_offset,
281 int count, struct ext2fs_htree_tail *tp)
286 uint32_t inum, old_csum, gen, crc;
292 size = count_offset + (count * sizeof(struct ext2fs_htree_entry));
293 old_csum = tp->ht_checksum;
298 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
299 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
300 crc = calculate_crc32c(crc, (uint8_t *)buf, size);
301 crc = calculate_crc32c(crc, (uint8_t *)tp, sizeof(struct ext2fs_htree_tail));
302 tp->ht_checksum = old_csum;
308 ext2_dx_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
311 struct ext2fs_htree_count *cp;
312 struct ext2fs_htree_tail *tp;
313 int count_offset, limit, count;
315 cp = ext2_get_dx_count(ip, ep, &count_offset);
319 limit = cp->h_entries_max;
320 count = cp->h_entries_num;
321 if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
322 ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
325 tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
326 calculated = ext2_dx_csum(ip, ep, count_offset, count, tp);
328 if (tp->ht_checksum != calculated)
335 ext2_dir_blk_csum_verify(struct inode *ip, struct buf *bp)
338 struct ext2fs_direct_2 *ep;
343 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
346 ep = (struct ext2fs_direct_2 *)bp->b_data;
348 if (ext2_dirent_get_tail(ip, ep) != NULL)
349 error = ext2_dirent_csum_verify(ip, ep);
350 else if (ext2_get_dx_count(ip, ep, NULL) != NULL)
351 error = ext2_dx_csum_verify(ip, ep);
354 printf("WARNING: bad directory csum detected, ip=%lu"
355 " - run fsck\n", (unsigned long)ip->i_number);
361 ext2_dirent_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
364 struct ext2fs_direct_tail *tp;
368 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
371 tp = ext2_dirent_get_tail(ip, ep);
376 ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
380 ext2_dx_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
383 struct ext2fs_htree_count *cp;
384 struct ext2fs_htree_tail *tp;
385 int count_offset, limit, count;
389 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
392 cp = ext2_get_dx_count(ip, ep, &count_offset);
396 limit = cp->h_entries_max;
397 count = cp->h_entries_num;
398 if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
399 ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
402 tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
403 tp->ht_checksum = ext2_dx_csum(ip, ep, count_offset, count, tp);
407 ext2_extent_blk_csum(struct inode *ip, struct ext4_extent_header *ehp)
411 uint32_t inum, gen, crc;
415 size = EXT4_EXTENT_TAIL_OFFSET(ehp) +
416 offsetof(struct ext4_extent_tail, et_checksum);
420 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
421 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
422 crc = calculate_crc32c(crc, (uint8_t *)ehp, size);
428 ext2_extent_blk_csum_verify(struct inode *ip, void *data)
431 struct ext4_extent_header *ehp;
432 struct ext4_extent_tail *etp;
433 uint32_t provided, calculated;
437 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
440 ehp = (struct ext4_extent_header *)data;
441 etp = (struct ext4_extent_tail *)(((char *)ehp) +
442 EXT4_EXTENT_TAIL_OFFSET(ehp));
444 provided = etp->et_checksum;
445 calculated = ext2_extent_blk_csum(ip, ehp);
447 if (provided != calculated) {
448 printf("WARNING: bad extent csum detected, ip=%lu - run fsck\n",
449 (unsigned long)ip->i_number);
457 ext2_extent_blk_csum_set(struct inode *ip, void *data)
460 struct ext4_extent_header *ehp;
461 struct ext4_extent_tail *etp;
465 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
468 ehp = (struct ext4_extent_header *)data;
469 etp = (struct ext4_extent_tail *)(((char *)data) +
470 EXT4_EXTENT_TAIL_OFFSET(ehp));
472 etp->et_checksum = ext2_extent_blk_csum(ip,
473 (struct ext4_extent_header *)data);
477 ext2_gd_i_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
479 uint32_t hi, provided, calculated;
481 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
484 provided = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum;
485 calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
486 fs->e2fs->e2fs_ipg / 8);
487 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) {
488 hi = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi;
489 provided |= (hi << 16);
491 calculated &= 0xFFFF;
493 if (provided != calculated) {
494 printf("WARNING: bad inode bitmap csum detected, "
495 "cg=%d - run fsck\n", cg);
503 ext2_gd_i_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
507 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
510 csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
511 fs->e2fs->e2fs_ipg / 8);
512 fs->e2fs_gd[cg].ext4bgd_i_bmap_csum = csum & 0xFFFF;
513 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END)
514 fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi = csum >> 16;
518 ext2_gd_b_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
520 uint32_t hi, provided, calculated, size;
522 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
525 size = fs->e2fs_fpg / 8;
526 provided = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum;
527 calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
528 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) {
529 hi = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi;
530 provided |= (hi << 16);
532 calculated &= 0xFFFF;
534 if (provided != calculated) {
535 printf("WARNING: bad block bitmap csum detected, "
536 "cg=%d - run fsck\n", cg);
544 ext2_gd_b_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
548 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
551 size = fs->e2fs_fpg / 8;
552 csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
553 fs->e2fs_gd[cg].ext4bgd_b_bmap_csum = csum & 0xFFFF;
554 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
555 fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi = csum >> 16;
559 ext2_ei_csum(struct inode *ip, struct ext2fs_dinode *ei)
562 uint32_t inode_csum_seed, inum, gen, crc;
563 uint16_t dummy_csum = 0;
564 unsigned int offset, csum_size;
567 offset = offsetof(struct ext2fs_dinode, e2di_chksum_lo);
568 csum_size = sizeof(dummy_csum);
570 crc = calculate_crc32c(fs->e2fs_csum_seed,
571 (uint8_t *)&inum, sizeof(inum));
573 inode_csum_seed = calculate_crc32c(crc,
574 (uint8_t *)&gen, sizeof(gen));
576 crc = calculate_crc32c(inode_csum_seed, (uint8_t *)ei, offset);
577 crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum, csum_size);
579 crc = calculate_crc32c(crc, (uint8_t *)ei + offset,
580 E2FS_REV0_INODE_SIZE - offset);
582 if (EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE) {
583 offset = offsetof(struct ext2fs_dinode, e2di_chksum_hi);
584 crc = calculate_crc32c(crc, (uint8_t *)ei +
585 E2FS_REV0_INODE_SIZE, offset - E2FS_REV0_INODE_SIZE);
587 if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE &&
588 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
589 crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum,
594 crc = calculate_crc32c(crc, (uint8_t *)ei + offset,
595 EXT2_INODE_SIZE(fs) - offset);
602 ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei)
605 const static struct ext2fs_dinode ei_zero;
606 uint32_t hi, provided, calculated;
610 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
613 provided = ei->e2di_chksum_lo;
614 calculated = ext2_ei_csum(ip, ei);
616 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
617 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
618 hi = ei->e2di_chksum_hi;
619 provided |= hi << 16;
621 calculated &= 0xFFFF;
623 if (provided != calculated) {
625 * If it is first time used dinode,
626 * it is expected that it will be zeroed
627 * and we will not return checksum error in this case.
629 if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode)))
639 ext2_ei_csum_set(struct inode *ip, struct ext2fs_dinode *ei)
646 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
649 crc = ext2_ei_csum(ip, ei);
651 ei->e2di_chksum_lo = crc & 0xFFFF;
652 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
653 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END))
654 ei->e2di_chksum_hi = crc >> 16;
658 ext2_crc16(uint16_t crc, const void *buffer, unsigned int len)
660 const unsigned char *cp = buffer;
661 /* CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1). */
662 static uint16_t const crc16_table[256] = {
663 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
664 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
665 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
666 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
667 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
668 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
669 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
670 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
671 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
672 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
673 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
674 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
675 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
676 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
677 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
678 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
679 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
680 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
681 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
682 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
683 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
684 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
685 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
686 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
687 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
688 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
689 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
690 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
691 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
692 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
693 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
694 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
698 crc = (((crc >> 8) & 0xffU) ^
699 crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU;
704 ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd)
708 uint16_t crc, dummy_csum;
710 offset = offsetof(struct ext2_gd, ext4bgd_csum);
712 if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
713 csum32 = calculate_crc32c(fs->e2fs_csum_seed,
714 (uint8_t *)&block_group, sizeof(block_group));
715 csum32 = calculate_crc32c(csum32, (uint8_t *)gd, offset);
717 csum32 = calculate_crc32c(csum32, (uint8_t *)&dummy_csum,
719 offset += sizeof(dummy_csum);
720 if (offset < fs->e2fs->e3fs_desc_size)
721 csum32 = calculate_crc32c(csum32, (uint8_t *)gd + offset,
722 fs->e2fs->e3fs_desc_size - offset);
724 crc = csum32 & 0xFFFF;
726 } else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
727 crc = ext2_crc16(~0, fs->e2fs->e2fs_uuid,
728 sizeof(fs->e2fs->e2fs_uuid));
729 crc = ext2_crc16(crc, (uint8_t *)&block_group,
730 sizeof(block_group));
731 crc = ext2_crc16(crc, (uint8_t *)gd, offset);
732 offset += sizeof(gd->ext4bgd_csum); /* skip checksum */
733 if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) &&
734 offset < fs->e2fs->e3fs_desc_size)
735 crc = ext2_crc16(crc, (uint8_t *)gd + offset,
736 fs->e2fs->e3fs_desc_size - offset);
744 ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev)
749 for (i = 0; i < fs->e2fs_gcount; i++) {
750 if (fs->e2fs_gd[i].ext4bgd_csum !=
751 ext2_gd_csum(fs, i, &fs->e2fs_gd[i])) {
753 "WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n",
754 devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum,
755 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]));
765 ext2_gd_csum_set(struct m_ext2fs *fs)
769 for (i = 0; i < fs->e2fs_gcount; i++)
770 fs->e2fs_gd[i].ext4bgd_csum =
771 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]);