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/mount.h>
46 #include <fs/ext2fs/fs.h>
47 #include <fs/ext2fs/ext2fs.h>
48 #include <fs/ext2fs/ext2_dinode.h>
49 #include <fs/ext2fs/inode.h>
50 #include <fs/ext2fs/ext2_dir.h>
51 #include <fs/ext2fs/htree.h>
52 #include <fs/ext2fs/ext2_extattr.h>
53 #include <fs/ext2fs/ext2_extern.h>
55 SDT_PROVIDER_DECLARE(ext2fs);
58 * arg0: verbosity. Higher numbers give more verbose messages
59 * arg1: Textual message
61 SDT_PROBE_DEFINE2(ext2fs, , trace, csum, "int", "char*");
63 #define EXT2_BG_INODE_BITMAP_CSUM_HI_END \
64 (offsetof(struct ext2_gd, ext4bgd_i_bmap_csum_hi) + \
67 #define EXT2_INODE_CSUM_HI_EXTRA_END \
68 (offsetof(struct ext2fs_dinode, e2di_chksum_hi) + sizeof(uint16_t) - \
71 #define EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION \
72 (offsetof(struct ext2_gd, ext4bgd_b_bmap_csum_hi) + \
76 ext2_sb_csum_set_seed(struct m_ext2fs *fs)
79 if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_CSUM_SEED))
80 fs->e2fs_csum_seed = fs->e2fs->e4fs_chksum_seed;
81 else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
82 fs->e2fs_csum_seed = calculate_crc32c(~0, fs->e2fs->e2fs_uuid,
83 sizeof(fs->e2fs->e2fs_uuid));
86 fs->e2fs_csum_seed = 0;
90 ext2_sb_csum_verify(struct m_ext2fs *fs)
93 if (fs->e2fs->e4fs_chksum_type != EXT4_CRC32C_CHKSUM) {
95 "WARNING: mount of %s denied due bad sb csum type\n", fs->e2fs_fsmnt);
98 if (fs->e2fs->e4fs_sbchksum !=
99 calculate_crc32c(~0, (const char *)fs->e2fs,
100 offsetof(struct ext2fs, e4fs_sbchksum))) {
102 "WARNING: mount of %s denied due bad sb csum=0x%x, expected=0x%x - run fsck\n",
103 fs->e2fs_fsmnt, fs->e2fs->e4fs_sbchksum, calculate_crc32c(~0,
104 (const char *)fs->e2fs, offsetof(struct ext2fs, e4fs_sbchksum)));
112 ext2_sb_csum_set(struct m_ext2fs *fs)
115 fs->e2fs->e4fs_sbchksum = calculate_crc32c(~0, (const char *)fs->e2fs,
116 offsetof(struct ext2fs, e4fs_sbchksum));
120 ext2_extattr_blk_csum(struct inode *ip, uint64_t facl,
121 struct ext2fs_extattr_header *header)
124 uint32_t crc, old_crc;
128 old_crc = header->h_checksum;
130 header->h_checksum = 0;
131 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&facl, sizeof(facl));
132 crc = calculate_crc32c(crc, (uint8_t *)header, fs->e2fs_bsize);
133 header->h_checksum = old_crc;
139 ext2_extattr_blk_csum_verify(struct inode *ip, struct buf *bp)
141 struct ext2fs_extattr_header *header;
143 header = (struct ext2fs_extattr_header *)bp->b_data;
145 if (EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM) &&
146 (header->h_checksum != ext2_extattr_blk_csum(ip, ip->i_facl, header))) {
147 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad extattr csum detected");
155 ext2_extattr_blk_csum_set(struct inode *ip, struct buf *bp)
157 struct ext2fs_extattr_header *header;
159 if (!EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
162 header = (struct ext2fs_extattr_header *)bp->b_data;
163 header->h_checksum = ext2_extattr_blk_csum(ip, ip->i_facl, header);
167 ext2_init_dirent_tail(struct ext2fs_direct_tail *tp)
169 memset(tp, 0, sizeof(struct ext2fs_direct_tail));
170 tp->e2dt_rec_len = sizeof(struct ext2fs_direct_tail);
171 tp->e2dt_reserved_ft = EXT2_FT_DIR_CSUM;
175 ext2_is_dirent_tail(struct inode *ip, struct ext2fs_direct_2 *ep)
178 struct ext2fs_direct_tail *tp;
182 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
185 tp = (struct ext2fs_direct_tail *)ep;
186 if (tp->e2dt_reserved_zero1 == 0 &&
187 tp->e2dt_rec_len == sizeof(struct ext2fs_direct_tail) &&
188 tp->e2dt_reserved_zero2 == 0 &&
189 tp->e2dt_reserved_ft == EXT2_FT_DIR_CSUM)
195 struct ext2fs_direct_tail *
196 ext2_dirent_get_tail(struct inode *ip, struct ext2fs_direct_2 *ep)
198 struct ext2fs_direct_2 *dep;
200 unsigned int rec_len;
203 top = EXT2_DIRENT_TAIL(ep, ip->i_e2fs->e2fs_bsize);
204 rec_len = dep->e2d_reclen;
206 while (rec_len && !(rec_len & 0x3)) {
207 dep = (struct ext2fs_direct_2 *)(((char *)dep) + rec_len);
208 if ((void *)dep >= top)
210 rec_len = dep->e2d_reclen;
216 if (ext2_is_dirent_tail(ip, dep))
217 return ((struct ext2fs_direct_tail *)dep);
223 ext2_dirent_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int size)
227 uint32_t inum, gen, crc;
235 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
236 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
237 crc = calculate_crc32c(crc, (uint8_t *)buf, size);
243 ext2_dirent_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
246 struct ext2fs_direct_tail *tp;
248 tp = ext2_dirent_get_tail(ip, ep);
252 calculated = ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
253 if (calculated != tp->e2dt_checksum)
259 static struct ext2fs_htree_count *
260 ext2_get_dx_count(struct inode *ip, struct ext2fs_direct_2 *ep, int *offset)
262 struct ext2fs_direct_2 *dp;
263 struct ext2fs_htree_root_info *root;
266 if (ep->e2d_reclen == EXT2_BLOCK_SIZE(ip->i_e2fs))
268 else if (ep->e2d_reclen == 12) {
269 dp = (struct ext2fs_direct_2 *)(((char *)ep) + 12);
270 if (dp->e2d_reclen != EXT2_BLOCK_SIZE(ip->i_e2fs) - 12)
273 root = (struct ext2fs_htree_root_info *)(((char *)dp + 12));
274 if (root->h_reserved1 ||
275 root->h_info_len != sizeof(struct ext2fs_htree_root_info))
283 *offset = count_offset;
285 return ((struct ext2fs_htree_count *)(((char *)ep) + count_offset));
289 ext2_dx_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int count_offset,
290 int count, struct ext2fs_htree_tail *tp)
295 uint32_t inum, old_csum, gen, crc;
301 size = count_offset + (count * sizeof(struct ext2fs_htree_entry));
302 old_csum = tp->ht_checksum;
307 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
308 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
309 crc = calculate_crc32c(crc, (uint8_t *)buf, size);
310 crc = calculate_crc32c(crc, (uint8_t *)tp, sizeof(struct ext2fs_htree_tail));
311 tp->ht_checksum = old_csum;
317 ext2_dx_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
320 struct ext2fs_htree_count *cp;
321 struct ext2fs_htree_tail *tp;
322 int count_offset, limit, count;
324 cp = ext2_get_dx_count(ip, ep, &count_offset);
328 limit = cp->h_entries_max;
329 count = cp->h_entries_num;
330 if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
331 ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
334 tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
335 calculated = ext2_dx_csum(ip, ep, count_offset, count, tp);
337 if (tp->ht_checksum != calculated)
344 ext2_dir_blk_csum_verify(struct inode *ip, struct buf *bp)
347 struct ext2fs_direct_2 *ep;
352 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
355 ep = (struct ext2fs_direct_2 *)bp->b_data;
357 if (ext2_dirent_get_tail(ip, ep) != NULL)
358 error = ext2_dirent_csum_verify(ip, ep);
359 else if (ext2_get_dx_count(ip, ep, NULL) != NULL)
360 error = ext2_dx_csum_verify(ip, ep);
363 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad directory csum detected");
369 ext2_dirent_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
372 struct ext2fs_direct_tail *tp;
376 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
379 tp = ext2_dirent_get_tail(ip, ep);
384 ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
388 ext2_dx_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
391 struct ext2fs_htree_count *cp;
392 struct ext2fs_htree_tail *tp;
393 int count_offset, limit, count;
397 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
400 cp = ext2_get_dx_count(ip, ep, &count_offset);
404 limit = cp->h_entries_max;
405 count = cp->h_entries_num;
406 if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
407 ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
410 tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
411 tp->ht_checksum = ext2_dx_csum(ip, ep, count_offset, count, tp);
415 ext2_extent_blk_csum(struct inode *ip, struct ext4_extent_header *ehp)
419 uint32_t inum, gen, crc;
423 size = EXT4_EXTENT_TAIL_OFFSET(ehp) +
424 offsetof(struct ext4_extent_tail, et_checksum);
428 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
429 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
430 crc = calculate_crc32c(crc, (uint8_t *)ehp, size);
436 ext2_extent_blk_csum_verify(struct inode *ip, void *data)
439 struct ext4_extent_header *ehp;
440 struct ext4_extent_tail *etp;
441 uint32_t provided, calculated;
445 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
448 ehp = (struct ext4_extent_header *)data;
449 etp = (struct ext4_extent_tail *)(((char *)ehp) +
450 EXT4_EXTENT_TAIL_OFFSET(ehp));
452 provided = etp->et_checksum;
453 calculated = ext2_extent_blk_csum(ip, ehp);
455 if (provided != calculated) {
456 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad extent csum detected");
464 ext2_extent_blk_csum_set(struct inode *ip, void *data)
467 struct ext4_extent_header *ehp;
468 struct ext4_extent_tail *etp;
472 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
475 ehp = (struct ext4_extent_header *)data;
476 etp = (struct ext4_extent_tail *)(((char *)data) +
477 EXT4_EXTENT_TAIL_OFFSET(ehp));
479 etp->et_checksum = ext2_extent_blk_csum(ip,
480 (struct ext4_extent_header *)data);
484 ext2_gd_i_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
486 uint32_t hi, provided, calculated;
488 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
491 provided = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum;
492 calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
493 fs->e2fs->e2fs_ipg / 8);
494 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) {
495 hi = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi;
496 provided |= (hi << 16);
498 calculated &= 0xFFFF;
500 if (provided != calculated) {
501 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad inode bitmap csum detected");
509 ext2_gd_i_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
513 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
516 csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
517 fs->e2fs->e2fs_ipg / 8);
518 fs->e2fs_gd[cg].ext4bgd_i_bmap_csum = csum & 0xFFFF;
519 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END)
520 fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi = csum >> 16;
524 ext2_gd_b_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
526 uint32_t hi, provided, calculated, size;
528 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
531 size = fs->e2fs_fpg / 8;
532 provided = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum;
533 calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
534 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) {
535 hi = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi;
536 provided |= (hi << 16);
538 calculated &= 0xFFFF;
540 if (provided != calculated) {
541 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad block bitmap csum detected");
549 ext2_gd_b_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
553 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
556 size = fs->e2fs_fpg / 8;
557 csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
558 fs->e2fs_gd[cg].ext4bgd_b_bmap_csum = csum & 0xFFFF;
559 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
560 fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi = csum >> 16;
564 ext2_ei_csum(struct inode *ip, struct ext2fs_dinode *ei)
567 uint32_t inode_csum_seed, inum, gen, crc;
568 uint16_t dummy_csum = 0;
569 unsigned int offset, csum_size;
572 offset = offsetof(struct ext2fs_dinode, e2di_chksum_lo);
573 csum_size = sizeof(dummy_csum);
575 crc = calculate_crc32c(fs->e2fs_csum_seed,
576 (uint8_t *)&inum, sizeof(inum));
578 inode_csum_seed = calculate_crc32c(crc,
579 (uint8_t *)&gen, sizeof(gen));
581 crc = calculate_crc32c(inode_csum_seed, (uint8_t *)ei, offset);
582 crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum, csum_size);
584 crc = calculate_crc32c(crc, (uint8_t *)ei + offset,
585 E2FS_REV0_INODE_SIZE - offset);
587 if (EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE) {
588 offset = offsetof(struct ext2fs_dinode, e2di_chksum_hi);
589 crc = calculate_crc32c(crc, (uint8_t *)ei +
590 E2FS_REV0_INODE_SIZE, offset - E2FS_REV0_INODE_SIZE);
592 if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE &&
593 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
594 crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum,
599 crc = calculate_crc32c(crc, (uint8_t *)ei + offset,
600 EXT2_INODE_SIZE(fs) - offset);
607 ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei)
610 const static struct ext2fs_dinode ei_zero;
611 uint32_t hi, provided, calculated;
615 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
618 provided = ei->e2di_chksum_lo;
619 calculated = ext2_ei_csum(ip, ei);
621 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
622 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
623 hi = ei->e2di_chksum_hi;
624 provided |= hi << 16;
626 calculated &= 0xFFFF;
628 if (provided != calculated) {
630 * If it is first time used dinode,
631 * it is expected that it will be zeroed
632 * and we will not return checksum error in this case.
634 if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode)))
637 SDT_PROBE2(ext2fs, , trace, csum, 1, "bad inode csum");
646 ext2_ei_csum_set(struct inode *ip, struct ext2fs_dinode *ei)
653 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
656 crc = ext2_ei_csum(ip, ei);
658 ei->e2di_chksum_lo = crc & 0xFFFF;
659 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
660 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END))
661 ei->e2di_chksum_hi = crc >> 16;
665 ext2_crc16(uint16_t crc, const void *buffer, unsigned int len)
667 const unsigned char *cp = buffer;
668 /* CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1). */
669 static uint16_t const crc16_table[256] = {
670 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
671 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
672 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
673 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
674 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
675 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
676 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
677 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
678 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
679 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
680 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
681 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
682 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
683 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
684 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
685 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
686 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
687 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
688 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
689 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
690 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
691 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
692 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
693 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
694 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
695 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
696 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
697 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
698 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
699 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
700 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
701 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
705 crc = (((crc >> 8) & 0xffU) ^
706 crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU;
711 ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd)
715 uint16_t crc, dummy_csum;
717 offset = offsetof(struct ext2_gd, ext4bgd_csum);
719 if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
720 csum32 = calculate_crc32c(fs->e2fs_csum_seed,
721 (uint8_t *)&block_group, sizeof(block_group));
722 csum32 = calculate_crc32c(csum32, (uint8_t *)gd, offset);
724 csum32 = calculate_crc32c(csum32, (uint8_t *)&dummy_csum,
726 offset += sizeof(dummy_csum);
727 if (offset < fs->e2fs->e3fs_desc_size)
728 csum32 = calculate_crc32c(csum32, (uint8_t *)gd + offset,
729 fs->e2fs->e3fs_desc_size - offset);
731 crc = csum32 & 0xFFFF;
733 } else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
734 crc = ext2_crc16(~0, fs->e2fs->e2fs_uuid,
735 sizeof(fs->e2fs->e2fs_uuid));
736 crc = ext2_crc16(crc, (uint8_t *)&block_group,
737 sizeof(block_group));
738 crc = ext2_crc16(crc, (uint8_t *)gd, offset);
739 offset += sizeof(gd->ext4bgd_csum); /* skip checksum */
740 if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) &&
741 offset < fs->e2fs->e3fs_desc_size)
742 crc = ext2_crc16(crc, (uint8_t *)gd + offset,
743 fs->e2fs->e3fs_desc_size - offset);
751 ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev)
756 for (i = 0; i < fs->e2fs_gcount; i++) {
757 if (fs->e2fs_gd[i].ext4bgd_csum !=
758 ext2_gd_csum(fs, i, &fs->e2fs_gd[i])) {
760 "WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n",
761 devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum,
762 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]));
772 ext2_gd_csum_set(struct m_ext2fs *fs)
776 for (i = 0; i < fs->e2fs_gcount; i++)
777 fs->e2fs_gd[i].ext4bgd_csum =
778 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]);