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);
157 static struct ext2fs_direct_tail *
158 ext2_get_dirent_tail(struct inode *ip, struct ext2fs_direct_2 *ep)
160 struct ext2fs_direct_tail *tp;
162 tp = EXT2_DIRENT_TAIL(ep, ip->i_e2fs->e2fs_bsize);
163 if (tp->e2dt_reserved_zero1 ||
164 tp->e2dt_rec_len != sizeof(struct ext2fs_direct_tail) ||
165 tp->e2dt_reserved_zero2 ||
166 tp->e2dt_reserved_ft != EXT2_FT_DIR_CSUM)
173 ext2_dirent_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int size)
177 uint32_t inum, gen, crc;
185 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
186 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
187 crc = calculate_crc32c(crc, (uint8_t *)buf, size);
193 ext2_dirent_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
196 struct ext2fs_direct_tail *tp;
198 tp = ext2_get_dirent_tail(ip, ep);
202 calculated = ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
203 if (calculated != tp->e2dt_checksum)
209 static struct ext2fs_htree_count *
210 ext2_get_dx_count(struct inode *ip, struct ext2fs_direct_2 *ep, int *offset)
212 struct ext2fs_direct_2 *dp;
213 struct ext2fs_htree_root_info *root;
216 if (ep->e2d_reclen == EXT2_BLOCK_SIZE(ip->i_e2fs))
218 else if (ep->e2d_reclen == 12) {
219 dp = (struct ext2fs_direct_2 *)(((char *)ep) + 12);
220 if (dp->e2d_reclen != EXT2_BLOCK_SIZE(ip->i_e2fs) - 12)
223 root = (struct ext2fs_htree_root_info *)(((char *)dp + 12));
224 if (root->h_reserved1 ||
225 root->h_info_len != sizeof(struct ext2fs_htree_root_info))
233 *offset = count_offset;
235 return ((struct ext2fs_htree_count *)(((char *)ep) + count_offset));
239 ext2_dx_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int count_offset,
240 int count, struct ext2fs_htree_tail *tp)
245 uint32_t inum, old_csum, gen, crc;
251 size = count_offset + (count * sizeof(struct ext2fs_htree_entry));
252 old_csum = tp->ht_checksum;
257 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
258 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
259 crc = calculate_crc32c(crc, (uint8_t *)buf, size);
260 crc = calculate_crc32c(crc, (uint8_t *)tp, sizeof(struct ext2fs_htree_tail));
261 tp->ht_checksum = old_csum;
267 ext2_dx_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
270 struct ext2fs_htree_count *cp;
271 struct ext2fs_htree_tail *tp;
272 int count_offset, limit, count;
274 cp = ext2_get_dx_count(ip, ep, &count_offset);
278 limit = cp->h_entries_max;
279 count = cp->h_entries_num;
280 if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
281 ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
284 tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
285 calculated = ext2_dx_csum(ip, ep, count_offset, count, tp);
287 if (tp->ht_checksum != calculated)
294 ext2_dir_blk_csum_verify(struct inode *ip, struct buf *bp)
297 struct ext2fs_direct_2 *ep;
302 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
305 ep = (struct ext2fs_direct_2 *)bp->b_data;
307 if (ext2_get_dirent_tail(ip, ep) != NULL)
308 error = ext2_dirent_csum_verify(ip, ep);
309 else if (ext2_get_dx_count(ip, ep, NULL) != NULL)
310 error = ext2_dx_csum_verify(ip, ep);
313 printf("WARNING: bad directory csum detected, ip=%lu"
314 " - run fsck\n", (unsigned long)ip->i_number);
320 ext2_dirent_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
322 struct ext2fs_direct_tail *tp;
324 tp = ext2_get_dirent_tail(ip, ep);
329 ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
333 ext2_dx_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
335 struct ext2fs_htree_count *cp;
336 struct ext2fs_htree_tail *tp;
337 int count_offset, limit, count;
339 cp = ext2_get_dx_count(ip, ep, &count_offset);
343 limit = cp->h_entries_max;
344 count = cp->h_entries_num;
345 if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
346 ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
349 tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
350 tp->ht_checksum = ext2_dx_csum(ip, ep, count_offset, count, tp);
354 ext2_dir_blk_csum_set_mem(struct inode *ip, char *buf, int size)
357 struct ext2fs_direct_2 *ep;
361 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
364 ep = (struct ext2fs_direct_2 *)buf;
366 if (ext2_htree_has_idx(ip)) {
367 if (ext2_get_dx_count(ip, ep, NULL) != NULL)
368 ext2_dx_csum_set(ip, ep);
370 if (ext2_get_dirent_tail(ip, ep) != NULL)
371 ext2_dirent_csum_set(ip, ep);
376 ext2_dir_blk_csum_set(struct inode *ip, struct buf *bp)
379 ext2_dir_blk_csum_set_mem(ip, bp->b_data, bp->b_bufsize);
383 ext2_extent_blk_csum(struct inode *ip, struct ext4_extent_header *ehp)
387 uint32_t inum, gen, crc;
391 size = EXT4_EXTENT_TAIL_OFFSET(ehp) +
392 offsetof(struct ext4_extent_tail, et_checksum);
396 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
397 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
398 crc = calculate_crc32c(crc, (uint8_t *)ehp, size);
404 ext2_extent_blk_csum_verify(struct inode *ip, void *data)
407 struct ext4_extent_header *ehp;
408 struct ext4_extent_tail *etp;
409 uint32_t provided, calculated;
413 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
416 ehp = (struct ext4_extent_header *)data;
417 etp = (struct ext4_extent_tail *)(((char *)ehp) +
418 EXT4_EXTENT_TAIL_OFFSET(ehp));
420 provided = etp->et_checksum;
421 calculated = ext2_extent_blk_csum(ip, ehp);
423 if (provided != calculated) {
424 printf("WARNING: bad extent csum detected, ip=%lu - run fsck\n",
425 (unsigned long)ip->i_number);
433 ext2_extent_blk_csum_set(struct inode *ip, void *data)
436 struct ext4_extent_header *ehp;
437 struct ext4_extent_tail *etp;
441 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
444 ehp = (struct ext4_extent_header *)data;
445 etp = (struct ext4_extent_tail *)(((char *)data) +
446 EXT4_EXTENT_TAIL_OFFSET(ehp));
448 etp->et_checksum = ext2_extent_blk_csum(ip,
449 (struct ext4_extent_header *)data);
453 ext2_gd_i_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
455 uint32_t hi, provided, calculated;
457 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
460 provided = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum;
461 calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
462 fs->e2fs->e2fs_ipg / 8);
463 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) {
464 hi = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi;
465 provided |= (hi << 16);
467 calculated &= 0xFFFF;
469 if (provided != calculated) {
470 printf("WARNING: bad inode bitmap csum detected, "
471 "cg=%d - run fsck\n", cg);
479 ext2_gd_i_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
483 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
486 csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
487 fs->e2fs->e2fs_ipg / 8);
488 fs->e2fs_gd[cg].ext4bgd_i_bmap_csum = csum & 0xFFFF;
489 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END)
490 fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi = csum >> 16;
494 ext2_gd_b_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
496 uint32_t hi, provided, calculated, size;
498 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
501 size = fs->e2fs_fpg / 8;
502 provided = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum;
503 calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
504 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) {
505 hi = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi;
506 provided |= (hi << 16);
508 calculated &= 0xFFFF;
510 if (provided != calculated) {
511 printf("WARNING: bad block bitmap csum detected, "
512 "cg=%d - run fsck\n", cg);
520 ext2_gd_b_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
524 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
527 size = fs->e2fs_fpg / 8;
528 csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
529 fs->e2fs_gd[cg].ext4bgd_b_bmap_csum = csum & 0xFFFF;
530 if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
531 fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi = csum >> 16;
535 ext2_ei_csum(struct inode *ip, struct ext2fs_dinode *ei)
538 uint16_t old_lo, old_hi;
539 uint32_t inum, gen, crc;
543 old_lo = ei->e2di_chksum_lo;
544 ei->e2di_chksum_lo = 0;
545 if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE &&
546 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
547 old_hi = ei->e2di_chksum_hi;
548 ei->e2di_chksum_hi = 0;
554 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
555 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
556 crc = calculate_crc32c(crc, (uint8_t *)ei, fs->e2fs->e2fs_inode_size);
558 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
559 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END))
560 ei->e2di_chksum_hi = old_hi;
566 ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei)
569 const static struct ext2fs_dinode ei_zero;
570 uint32_t hi, provided, calculated;
574 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
577 /* Check case, when dinode was not initialized */
578 if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode)))
581 provided = ei->e2di_chksum_lo;
582 calculated = ext2_ei_csum(ip, ei);
584 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
585 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
586 hi = ei->e2di_chksum_hi;
587 provided |= hi << 16;
589 calculated &= 0xFFFF;
591 if (provided != calculated)
598 ext2_ei_csum_set(struct inode *ip, struct ext2fs_dinode *ei)
605 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
608 crc = ext2_ei_csum(ip, ei);
610 ei->e2di_chksum_lo = crc & 0xFFFF;
611 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
612 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END))
613 ei->e2di_chksum_hi = crc >> 16;
617 ext2_crc16(uint16_t crc, const void *buffer, unsigned int len)
619 const unsigned char *cp = buffer;
620 /* CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1). */
621 static uint16_t const crc16_table[256] = {
622 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
623 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
624 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
625 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
626 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
627 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
628 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
629 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
630 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
631 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
632 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
633 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
634 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
635 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
636 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
637 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
638 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
639 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
640 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
641 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
642 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
643 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
644 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
645 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
646 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
647 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
648 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
649 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
650 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
651 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
652 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
653 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
657 crc = (((crc >> 8) & 0xffU) ^
658 crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU;
663 ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd)
667 uint16_t crc, dummy_csum;
669 offset = offsetof(struct ext2_gd, ext4bgd_csum);
671 if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
672 csum32 = calculate_crc32c(fs->e2fs_csum_seed,
673 (uint8_t *)&block_group, sizeof(block_group));
674 csum32 = calculate_crc32c(csum32, (uint8_t *)gd, offset);
676 csum32 = calculate_crc32c(csum32, (uint8_t *)&dummy_csum,
678 offset += sizeof(dummy_csum);
679 if (offset < fs->e2fs->e3fs_desc_size)
680 csum32 = calculate_crc32c(csum32, (uint8_t *)gd + offset,
681 fs->e2fs->e3fs_desc_size - offset);
683 crc = csum32 & 0xFFFF;
685 } else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
686 crc = ext2_crc16(~0, fs->e2fs->e2fs_uuid,
687 sizeof(fs->e2fs->e2fs_uuid));
688 crc = ext2_crc16(crc, (uint8_t *)&block_group,
689 sizeof(block_group));
690 crc = ext2_crc16(crc, (uint8_t *)gd, offset);
691 offset += sizeof(gd->ext4bgd_csum); /* skip checksum */
692 if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) &&
693 offset < fs->e2fs->e3fs_desc_size)
694 crc = ext2_crc16(crc, (uint8_t *)gd + offset,
695 fs->e2fs->e3fs_desc_size - offset);
703 ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev)
708 for (i = 0; i < fs->e2fs_gcount; i++) {
709 if (fs->e2fs_gd[i].ext4bgd_csum !=
710 ext2_gd_csum(fs, i, &fs->e2fs_gd[i])) {
712 "WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n",
713 devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum,
714 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]));
724 ext2_gd_csum_set(struct m_ext2fs *fs)
728 for (i = 0; i < fs->e2fs_gcount; i++)
729 fs->e2fs_gd[i].ext4bgd_csum =
730 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]);