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/mount.h>
45 #include <fs/ext2fs/fs.h>
46 #include <fs/ext2fs/ext2fs.h>
47 #include <fs/ext2fs/ext2_dinode.h>
48 #include <fs/ext2fs/inode.h>
49 #include <fs/ext2fs/ext2_dir.h>
50 #include <fs/ext2fs/htree.h>
51 #include <fs/ext2fs/ext2_extattr.h>
52 #include <fs/ext2fs/ext2_extern.h>
54 SDT_PROVIDER_DECLARE(ext2fs);
57 * arg0: verbosity. Higher numbers give more verbose messages
58 * arg1: Textual message
60 SDT_PROBE_DEFINE2(ext2fs, , trace, csum, "int", "char*");
62 #define EXT2_BG_INODE_BITMAP_CSUM_HI_END \
63 (offsetof(struct ext2_gd, ext4bgd_i_bmap_csum_hi) + \
66 #define EXT2_INODE_CSUM_HI_EXTRA_END \
67 (offsetof(struct ext2fs_dinode, e2di_chksum_hi) + sizeof(uint16_t) - \
70 #define EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION \
71 (offsetof(struct ext2_gd, ext4bgd_b_bmap_csum_hi) + \
75 ext2_sb_csum_set_seed(struct m_ext2fs *fs)
78 if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_CSUM_SEED))
79 fs->e2fs_csum_seed = fs->e2fs->e4fs_chksum_seed;
80 else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
81 fs->e2fs_csum_seed = calculate_crc32c(~0, fs->e2fs->e2fs_uuid,
82 sizeof(fs->e2fs->e2fs_uuid));
85 fs->e2fs_csum_seed = 0;
89 ext2_sb_csum_verify(struct m_ext2fs *fs)
92 if (fs->e2fs->e4fs_chksum_type != EXT4_CRC32C_CHKSUM) {
94 "WARNING: mount of %s denied due bad sb csum type\n", fs->e2fs_fsmnt);
97 if (fs->e2fs->e4fs_sbchksum !=
98 calculate_crc32c(~0, (const char *)fs->e2fs,
99 offsetof(struct ext2fs, e4fs_sbchksum))) {
101 "WARNING: mount of %s denied due bad sb csum=0x%x, expected=0x%x - run fsck\n",
102 fs->e2fs_fsmnt, fs->e2fs->e4fs_sbchksum, calculate_crc32c(~0,
103 (const char *)fs->e2fs, offsetof(struct ext2fs, e4fs_sbchksum)));
111 ext2_sb_csum_set(struct m_ext2fs *fs)
114 fs->e2fs->e4fs_sbchksum = calculate_crc32c(~0, (const char *)fs->e2fs,
115 offsetof(struct ext2fs, e4fs_sbchksum));
119 ext2_extattr_blk_csum(struct inode *ip, uint64_t facl,
120 struct ext2fs_extattr_header *header)
123 uint32_t crc, old_crc;
127 old_crc = header->h_checksum;
129 header->h_checksum = 0;
130 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&facl, sizeof(facl));
131 crc = calculate_crc32c(crc, (uint8_t *)header, fs->e2fs_bsize);
132 header->h_checksum = old_crc;
138 ext2_extattr_blk_csum_verify(struct inode *ip, struct buf *bp)
140 struct ext2fs_extattr_header *header;
142 header = (struct ext2fs_extattr_header *)bp->b_data;
144 if (EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM) &&
145 (header->h_checksum != ext2_extattr_blk_csum(ip, ip->i_facl, header))) {
146 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad extattr csum detected");
154 ext2_extattr_blk_csum_set(struct inode *ip, struct buf *bp)
156 struct ext2fs_extattr_header *header;
158 if (!EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
161 header = (struct ext2fs_extattr_header *)bp->b_data;
162 header->h_checksum = ext2_extattr_blk_csum(ip, ip->i_facl, header);
166 ext2_init_dirent_tail(struct ext2fs_direct_tail *tp)
168 memset(tp, 0, sizeof(struct ext2fs_direct_tail));
169 tp->e2dt_rec_len = sizeof(struct ext2fs_direct_tail);
170 tp->e2dt_reserved_ft = EXT2_FT_DIR_CSUM;
174 ext2_is_dirent_tail(struct inode *ip, struct ext2fs_direct_2 *ep)
177 struct ext2fs_direct_tail *tp;
181 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
184 tp = (struct ext2fs_direct_tail *)ep;
185 if (tp->e2dt_reserved_zero1 == 0 &&
186 tp->e2dt_rec_len == sizeof(struct ext2fs_direct_tail) &&
187 tp->e2dt_reserved_zero2 == 0 &&
188 tp->e2dt_reserved_ft == EXT2_FT_DIR_CSUM)
194 struct ext2fs_direct_tail *
195 ext2_dirent_get_tail(struct inode *ip, struct ext2fs_direct_2 *ep)
197 struct ext2fs_direct_2 *dep;
199 unsigned int rec_len;
202 top = EXT2_DIRENT_TAIL(ep, ip->i_e2fs->e2fs_bsize);
203 rec_len = dep->e2d_reclen;
205 while (rec_len && !(rec_len & 0x3)) {
206 dep = (struct ext2fs_direct_2 *)(((char *)dep) + rec_len);
207 if ((void *)dep >= top)
209 rec_len = dep->e2d_reclen;
215 if (ext2_is_dirent_tail(ip, dep))
216 return ((struct ext2fs_direct_tail *)dep);
222 ext2_dirent_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int size)
226 uint32_t inum, gen, crc;
234 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
235 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
236 crc = calculate_crc32c(crc, (uint8_t *)buf, size);
242 ext2_dirent_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
245 struct ext2fs_direct_tail *tp;
247 tp = ext2_dirent_get_tail(ip, ep);
251 calculated = ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
252 if (calculated != tp->e2dt_checksum)
258 static struct ext2fs_htree_count *
259 ext2_get_dx_count(struct inode *ip, struct ext2fs_direct_2 *ep, int *offset)
261 struct ext2fs_direct_2 *dp;
262 struct ext2fs_htree_root_info *root;
265 if (ep->e2d_reclen == EXT2_BLOCK_SIZE(ip->i_e2fs))
267 else if (ep->e2d_reclen == 12) {
268 dp = (struct ext2fs_direct_2 *)(((char *)ep) + 12);
269 if (dp->e2d_reclen != EXT2_BLOCK_SIZE(ip->i_e2fs) - 12)
272 root = (struct ext2fs_htree_root_info *)(((char *)dp + 12));
273 if (root->h_reserved1 ||
274 root->h_info_len != sizeof(struct ext2fs_htree_root_info))
282 *offset = count_offset;
284 return ((struct ext2fs_htree_count *)(((char *)ep) + count_offset));
288 ext2_dx_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int count_offset,
289 int count, struct ext2fs_htree_tail *tp)
294 uint32_t inum, old_csum, gen, crc;
300 size = count_offset + (count * sizeof(struct ext2fs_htree_entry));
301 old_csum = tp->ht_checksum;
306 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
307 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
308 crc = calculate_crc32c(crc, (uint8_t *)buf, size);
309 crc = calculate_crc32c(crc, (uint8_t *)tp, sizeof(struct ext2fs_htree_tail));
310 tp->ht_checksum = old_csum;
316 ext2_dx_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
319 struct ext2fs_htree_count *cp;
320 struct ext2fs_htree_tail *tp;
321 int count_offset, limit, count;
323 cp = ext2_get_dx_count(ip, ep, &count_offset);
327 limit = cp->h_entries_max;
328 count = cp->h_entries_num;
329 if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
330 ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
333 tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
334 calculated = ext2_dx_csum(ip, ep, count_offset, count, tp);
336 if (tp->ht_checksum != calculated)
343 ext2_dir_blk_csum_verify(struct inode *ip, struct buf *bp)
346 struct ext2fs_direct_2 *ep;
351 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
354 ep = (struct ext2fs_direct_2 *)bp->b_data;
356 if (ext2_dirent_get_tail(ip, ep) != NULL)
357 error = ext2_dirent_csum_verify(ip, ep);
358 else if (ext2_get_dx_count(ip, ep, NULL) != NULL)
359 error = ext2_dx_csum_verify(ip, ep);
362 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad directory csum detected");
368 ext2_dirent_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
371 struct ext2fs_direct_tail *tp;
375 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
378 tp = ext2_dirent_get_tail(ip, ep);
383 ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
387 ext2_dx_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
390 struct ext2fs_htree_count *cp;
391 struct ext2fs_htree_tail *tp;
392 int count_offset, limit, count;
396 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
399 cp = ext2_get_dx_count(ip, ep, &count_offset);
403 limit = cp->h_entries_max;
404 count = cp->h_entries_num;
405 if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
406 ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
409 tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
410 tp->ht_checksum = ext2_dx_csum(ip, ep, count_offset, count, tp);
414 ext2_extent_blk_csum(struct inode *ip, struct ext4_extent_header *ehp)
418 uint32_t inum, gen, crc;
422 size = EXT4_EXTENT_TAIL_OFFSET(ehp) +
423 offsetof(struct ext4_extent_tail, et_checksum);
427 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
428 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
429 crc = calculate_crc32c(crc, (uint8_t *)ehp, size);
435 ext2_extent_blk_csum_verify(struct inode *ip, void *data)
438 struct ext4_extent_header *ehp;
439 struct ext4_extent_tail *etp;
440 uint32_t provided, calculated;
444 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
447 ehp = (struct ext4_extent_header *)data;
448 etp = (struct ext4_extent_tail *)(((char *)ehp) +
449 EXT4_EXTENT_TAIL_OFFSET(ehp));
451 provided = etp->et_checksum;
452 calculated = ext2_extent_blk_csum(ip, ehp);
454 if (provided != calculated) {
455 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad extent csum detected");
463 ext2_extent_blk_csum_set(struct inode *ip, void *data)
466 struct ext4_extent_header *ehp;
467 struct ext4_extent_tail *etp;
471 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
474 ehp = (struct ext4_extent_header *)data;
475 etp = (struct ext4_extent_tail *)(((char *)data) +
476 EXT4_EXTENT_TAIL_OFFSET(ehp));
478 etp->et_checksum = ext2_extent_blk_csum(ip,
479 (struct ext4_extent_header *)data);
483 ext2_gd_i_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
485 uint32_t hi, provided, calculated;
487 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
490 provided = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum;
491 calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
492 fs->e2fs->e2fs_ipg / 8);
493 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) {
494 hi = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi;
495 provided |= (hi << 16);
497 calculated &= 0xFFFF;
499 if (provided != calculated) {
500 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad inode bitmap csum detected");
508 ext2_gd_i_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
512 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
515 csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
516 fs->e2fs->e2fs_ipg / 8);
517 fs->e2fs_gd[cg].ext4bgd_i_bmap_csum = csum & 0xFFFF;
518 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END)
519 fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi = csum >> 16;
523 ext2_gd_b_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
525 uint32_t hi, provided, calculated, size;
527 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
530 size = fs->e2fs_fpg / 8;
531 provided = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum;
532 calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
533 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) {
534 hi = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi;
535 provided |= (hi << 16);
537 calculated &= 0xFFFF;
539 if (provided != calculated) {
540 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad block bitmap csum detected");
548 ext2_gd_b_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
552 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
555 size = fs->e2fs_fpg / 8;
556 csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
557 fs->e2fs_gd[cg].ext4bgd_b_bmap_csum = csum & 0xFFFF;
558 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
559 fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi = csum >> 16;
563 ext2_ei_csum(struct inode *ip, struct ext2fs_dinode *ei)
566 uint32_t inode_csum_seed, inum, gen, crc;
567 uint16_t dummy_csum = 0;
568 unsigned int offset, csum_size;
571 offset = offsetof(struct ext2fs_dinode, e2di_chksum_lo);
572 csum_size = sizeof(dummy_csum);
574 crc = calculate_crc32c(fs->e2fs_csum_seed,
575 (uint8_t *)&inum, sizeof(inum));
577 inode_csum_seed = calculate_crc32c(crc,
578 (uint8_t *)&gen, sizeof(gen));
580 crc = calculate_crc32c(inode_csum_seed, (uint8_t *)ei, offset);
581 crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum, csum_size);
583 crc = calculate_crc32c(crc, (uint8_t *)ei + offset,
584 E2FS_REV0_INODE_SIZE - offset);
586 if (EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE) {
587 offset = offsetof(struct ext2fs_dinode, e2di_chksum_hi);
588 crc = calculate_crc32c(crc, (uint8_t *)ei +
589 E2FS_REV0_INODE_SIZE, offset - E2FS_REV0_INODE_SIZE);
591 if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE &&
592 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
593 crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum,
598 crc = calculate_crc32c(crc, (uint8_t *)ei + offset,
599 EXT2_INODE_SIZE(fs) - offset);
606 ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei)
609 const static struct ext2fs_dinode ei_zero;
610 uint32_t hi, provided, calculated;
614 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
617 provided = ei->e2di_chksum_lo;
618 calculated = ext2_ei_csum(ip, ei);
620 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
621 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
622 hi = ei->e2di_chksum_hi;
623 provided |= hi << 16;
625 calculated &= 0xFFFF;
627 if (provided != calculated) {
629 * If it is first time used dinode,
630 * it is expected that it will be zeroed
631 * and we will not return checksum error in this case.
633 if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode)))
636 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad inode csum");
645 ext2_ei_csum_set(struct inode *ip, struct ext2fs_dinode *ei)
652 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
655 crc = ext2_ei_csum(ip, ei);
657 ei->e2di_chksum_lo = crc & 0xFFFF;
658 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
659 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END))
660 ei->e2di_chksum_hi = crc >> 16;
664 ext2_crc16(uint16_t crc, const void *buffer, unsigned int len)
666 const unsigned char *cp = buffer;
667 /* CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1). */
668 static uint16_t const crc16_table[256] = {
669 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
670 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
671 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
672 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
673 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
674 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
675 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
676 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
677 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
678 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
679 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
680 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
681 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
682 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
683 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
684 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
685 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
686 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
687 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
688 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
689 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
690 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
691 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
692 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
693 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
694 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
695 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
696 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
697 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
698 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
699 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
700 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
704 crc = (((crc >> 8) & 0xffU) ^
705 crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU;
710 ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd)
714 uint16_t crc, dummy_csum;
716 offset = offsetof(struct ext2_gd, ext4bgd_csum);
718 if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
719 csum32 = calculate_crc32c(fs->e2fs_csum_seed,
720 (uint8_t *)&block_group, sizeof(block_group));
721 csum32 = calculate_crc32c(csum32, (uint8_t *)gd, offset);
723 csum32 = calculate_crc32c(csum32, (uint8_t *)&dummy_csum,
725 offset += sizeof(dummy_csum);
726 if (offset < fs->e2fs->e3fs_desc_size)
727 csum32 = calculate_crc32c(csum32, (uint8_t *)gd + offset,
728 fs->e2fs->e3fs_desc_size - offset);
730 crc = csum32 & 0xFFFF;
732 } else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
733 crc = ext2_crc16(~0, fs->e2fs->e2fs_uuid,
734 sizeof(fs->e2fs->e2fs_uuid));
735 crc = ext2_crc16(crc, (uint8_t *)&block_group,
736 sizeof(block_group));
737 crc = ext2_crc16(crc, (uint8_t *)gd, offset);
738 offset += sizeof(gd->ext4bgd_csum); /* skip checksum */
739 if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) &&
740 offset < fs->e2fs->e3fs_desc_size)
741 crc = ext2_crc16(crc, (uint8_t *)gd + offset,
742 fs->e2fs->e3fs_desc_size - offset);
750 ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev)
755 for (i = 0; i < fs->e2fs_gcount; i++) {
756 if (fs->e2fs_gd[i].ext4bgd_csum !=
757 ext2_gd_csum(fs, i, &fs->e2fs_gd[i])) {
759 "WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n",
760 devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum,
761 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]));
771 ext2_gd_csum_set(struct m_ext2fs *fs)
775 for (i = 0; i < fs->e2fs_gcount; i++)
776 fs->e2fs_gd[i].ext4bgd_csum =
777 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]);