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)
539 uint32_t inum, gen, crc;
543 ei->e2di_chksum_lo = 0;
544 if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE &&
545 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
546 old_hi = ei->e2di_chksum_hi;
547 ei->e2di_chksum_hi = 0;
553 crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
554 crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
555 crc = calculate_crc32c(crc, (uint8_t *)ei, fs->e2fs->e2fs_inode_size);
557 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
558 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END))
559 ei->e2di_chksum_hi = old_hi;
565 ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei)
568 const static struct ext2fs_dinode ei_zero;
569 uint32_t hi, provided, calculated;
573 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
576 /* Check case, when dinode was not initialized */
577 if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode)))
580 provided = ei->e2di_chksum_lo;
581 calculated = ext2_ei_csum(ip, ei);
583 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
584 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
585 hi = ei->e2di_chksum_hi;
586 provided |= hi << 16;
588 calculated &= 0xFFFF;
590 if (provided != calculated)
597 ext2_ei_csum_set(struct inode *ip, struct ext2fs_dinode *ei)
604 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
607 crc = ext2_ei_csum(ip, ei);
609 ei->e2di_chksum_lo = crc & 0xFFFF;
610 if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
611 ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END))
612 ei->e2di_chksum_hi = crc >> 16;
616 ext2_crc16(uint16_t crc, const void *buffer, unsigned int len)
618 const unsigned char *cp = buffer;
619 /* CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1). */
620 static uint16_t const crc16_table[256] = {
621 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
622 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
623 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
624 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
625 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
626 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
627 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
628 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
629 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
630 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
631 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
632 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
633 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
634 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
635 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
636 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
637 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
638 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
639 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
640 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
641 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
642 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
643 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
644 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
645 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
646 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
647 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
648 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
649 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
650 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
651 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
652 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
656 crc = (((crc >> 8) & 0xffU) ^
657 crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU;
662 ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd)
666 uint16_t crc, dummy_csum;
668 offset = offsetof(struct ext2_gd, ext4bgd_csum);
670 if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
671 csum32 = calculate_crc32c(fs->e2fs_csum_seed,
672 (uint8_t *)&block_group, sizeof(block_group));
673 csum32 = calculate_crc32c(csum32, (uint8_t *)gd, offset);
675 csum32 = calculate_crc32c(csum32, (uint8_t *)&dummy_csum,
677 offset += sizeof(dummy_csum);
678 if (offset < fs->e2fs->e3fs_desc_size)
679 csum32 = calculate_crc32c(csum32, (uint8_t *)gd + offset,
680 fs->e2fs->e3fs_desc_size - offset);
682 crc = csum32 & 0xFFFF;
684 } else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
685 crc = ext2_crc16(~0, fs->e2fs->e2fs_uuid,
686 sizeof(fs->e2fs->e2fs_uuid));
687 crc = ext2_crc16(crc, (uint8_t *)&block_group,
688 sizeof(block_group));
689 crc = ext2_crc16(crc, (uint8_t *)gd, offset);
690 offset += sizeof(gd->ext4bgd_csum); /* skip checksum */
691 if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) &&
692 offset < fs->e2fs->e3fs_desc_size)
693 crc = ext2_crc16(crc, (uint8_t *)gd + offset,
694 fs->e2fs->e3fs_desc_size - offset);
702 ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev)
707 for (i = 0; i < fs->e2fs_gcount; i++) {
708 if (fs->e2fs_gd[i].ext4bgd_csum !=
709 ext2_gd_csum(fs, i, &fs->e2fs_gd[i])) {
711 "WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n",
712 devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum,
713 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]));
723 ext2_gd_csum_set(struct m_ext2fs *fs)
727 for (i = 0; i < fs->e2fs_gcount; i++)
728 fs->e2fs_gd[i].ext4bgd_csum =
729 ext2_gd_csum(fs, i, &fs->e2fs_gd[i]);