static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag, void *buf, __u32 sequence) { __u32 provided, calculated; if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) return 1; sequence = cpu_to_be32(sequence); calculated = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence, sizeof(sequence)); calculated = jbd2_chksum(j, calculated, buf, j->j_blocksize); provided = be32_to_cpu(tag->t_checksum); return provided == cpu_to_be32(calculated); }
static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag, void *buf, __u32 sequence) { journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag; __u32 csum32; __u32 seq; if (!journal_has_csum_v2or3(j)) return 1; seq = ext2fs_cpu_to_be32(sequence); csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq)); csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize); if (jfs_has_feature_csum3(j)) return tag3->t_checksum == ext2fs_cpu_to_be32(csum32); return tag->t_checksum == ext2fs_cpu_to_be16(csum32); }
void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag, struct buffer_head *bh, __u32 sequence) { journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag; __u32 csum32; __be32 seq; if (!journal_has_csum_v2or3(j)) return; seq = ext2fs_cpu_to_be32(sequence); csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq)); csum32 = jbd2_chksum(j, csum32, bh->b_data, bh->b_size); if (jfs_has_feature_csum3(j)) tag3->t_checksum = ext2fs_cpu_to_be32(csum32); else tag->t_checksum = ext2fs_cpu_to_be16(csum32); }
static void update_journal_csum(journal_t *journal, int ver) { journal_superblock_t *jsb; if (journal->j_format_version < 2) return; if (journal->j_tail != 0 || EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super, EXT3_FEATURE_INCOMPAT_RECOVER)) { printf("Journal needs recovery, will not add csums.\n"); return; } /* metadata_csum implies journal csum v3 */ jsb = journal->j_superblock; if (EXT2_HAS_RO_COMPAT_FEATURE(journal->j_fs_dev->k_fs->super, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { printf("Setting csum v%d\n", ver); switch (ver) { case 2: journal->j_superblock->s_feature_incompat &= ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V3); journal->j_superblock->s_feature_incompat |= ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2); journal->j_superblock->s_feature_compat &= ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM); break; case 3: journal->j_superblock->s_feature_incompat &= ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V2); journal->j_superblock->s_feature_incompat |= ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V3); journal->j_superblock->s_feature_compat &= ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM); break; default: printf("Unknown checksum v%d\n", ver); break; } journal->j_superblock->s_checksum_type = JBD2_CRC32C_CHKSUM; journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid, sizeof(jsb->s_uuid)); } else { journal->j_superblock->s_feature_compat |= ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM); journal->j_superblock->s_feature_incompat &= ext2fs_cpu_to_be32(~(JFS_FEATURE_INCOMPAT_CSUM_V2 | JFS_FEATURE_INCOMPAT_CSUM_V3)); } }
void jbd2_descr_block_csum_set(journal_t *j, struct buffer_head *bh) { struct journal_block_tail *tail; __u32 csum; if (!journal_has_csum_v2or3(j)) return; tail = (struct journal_block_tail *)(bh->b_data + j->j_blocksize - sizeof(struct journal_block_tail)); tail->t_checksum = 0; csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); tail->t_checksum = ext2fs_cpu_to_be32(csum); }
void jbd2_commit_block_csum_set(journal_t *j, struct buffer_head *bh) { struct commit_header *h; __u32 csum; if (!journal_has_csum_v2or3(j)) return; h = (struct commit_header *)(bh->b_data); h->h_chksum_type = 0; h->h_chksum_size = 0; h->h_chksum[0] = 0; csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); h->h_chksum[0] = ext2fs_cpu_to_be32(csum); }
static int jbd2_commit_block_csum_verify(journal_t *j, void *buf) { struct commit_header *h; __u32 provided; __u32 calculated; if (!journal_has_csum_v2or3(j)) return 1; h = buf; provided = h->h_chksum[0]; h->h_chksum[0] = 0; calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); h->h_chksum[0] = provided; return provided == ext2fs_cpu_to_be32(calculated); }
static int jbd2_commit_block_csum_verify(journal_t *j, void *buf) { struct commit_header *h; __u32 provided, calculated; if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) return 1; h = buf; provided = h->h_chksum[0]; h->h_chksum[0] = 0; calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); h->h_chksum[0] = provided; provided = be32_to_cpu(provided); return provided == calculated; }
static int jbd2_descriptor_block_csum_verify(journal_t *j, void *buf) { struct jbd2_journal_block_tail *tail; __be32 provided; __u32 calculated; if (!jbd2_journal_has_csum_v2or3(j)) return 1; tail = (struct jbd2_journal_block_tail *)(buf + j->j_blocksize - sizeof(struct jbd2_journal_block_tail)); provided = tail->t_checksum; tail->t_checksum = 0; calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); tail->t_checksum = provided; return provided == cpu_to_be32(calculated); }
static int jbd2_revoke_block_csum_verify(journal_t *j, void *buf) { struct jbd2_journal_revoke_tail *tail; __u32 provided, calculated; if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) return 1; tail = (struct jbd2_journal_revoke_tail *)(buf + j->j_blocksize - sizeof(struct jbd2_journal_revoke_tail)); provided = tail->r_checksum; tail->r_checksum = 0; calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); tail->r_checksum = provided; provided = be32_to_cpu(provided); return provided == calculated; }
static errcode_t e2fsck_journal_load(journal_t *journal) { e2fsck_t ctx = journal->j_dev->k_ctx; journal_superblock_t *jsb; struct buffer_head *jbh = journal->j_sb_buffer; struct problem_context pctx; clear_problem_context(&pctx); ll_rw_block(READ, 1, &jbh); if (jbh->b_err) { com_err(ctx->device_name, jbh->b_err, "%s", _("reading journal superblock\n")); return jbh->b_err; } jsb = journal->j_superblock; /* If we don't even have JFS_MAGIC, we probably have a wrong inode */ if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER)) return e2fsck_journal_fix_bad_inode(ctx, &pctx); switch (ntohl(jsb->s_header.h_blocktype)) { case JFS_SUPERBLOCK_V1: journal->j_format_version = 1; if (jsb->s_feature_compat || jsb->s_feature_incompat || jsb->s_feature_ro_compat || jsb->s_nr_users) clear_v2_journal_fields(journal); break; case JFS_SUPERBLOCK_V2: journal->j_format_version = 2; if (ntohl(jsb->s_nr_users) > 1 && uuid_is_null(ctx->fs->super->s_journal_uuid)) clear_v2_journal_fields(journal); if (ntohl(jsb->s_nr_users) > 1) { fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx); return EXT2_ET_JOURNAL_UNSUPP_VERSION; } break; /* * These should never appear in a journal super block, so if * they do, the journal is badly corrupted. */ case JFS_DESCRIPTOR_BLOCK: case JFS_COMMIT_BLOCK: case JFS_REVOKE_BLOCK: return EXT2_ET_CORRUPT_SUPERBLOCK; /* If we don't understand the superblock major type, but there * is a magic number, then it is likely to be a new format we * just don't understand, so leave it alone. */ default: return EXT2_ET_JOURNAL_UNSUPP_VERSION; } if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES)) return EXT2_ET_UNSUPP_FEATURE; if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES)) return EXT2_ET_RO_UNSUPP_FEATURE; /* Checksum v1-3 are mutually exclusive features. */ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) && JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3)) return EXT2_ET_CORRUPT_SUPERBLOCK; if (journal_has_csum_v2or3(journal) && JFS_HAS_COMPAT_FEATURE(journal, JFS_FEATURE_COMPAT_CHECKSUM)) return EXT2_ET_CORRUPT_SUPERBLOCK; if (!e2fsck_journal_verify_csum_type(journal, jsb) || !e2fsck_journal_sb_csum_verify(journal, jsb)) return EXT2_ET_CORRUPT_SUPERBLOCK; if (journal_has_csum_v2or3(journal)) journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid, sizeof(jsb->s_uuid)); /* We have now checked whether we know enough about the journal * format to be able to proceed safely, so any other checks that * fail we should attempt to recover from. */ if (jsb->s_blocksize != htonl(journal->j_blocksize)) { com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK, _("%s: no valid journal superblock found\n"), ctx->device_name); return EXT2_ET_CORRUPT_SUPERBLOCK; } if (ntohl(jsb->s_maxlen) < journal->j_maxlen) journal->j_maxlen = ntohl(jsb->s_maxlen); else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) { com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK, _("%s: journal too short\n"), ctx->device_name); return EXT2_ET_CORRUPT_SUPERBLOCK; } journal->j_tail_sequence = ntohl(jsb->s_sequence); journal->j_transaction_sequence = journal->j_tail_sequence; journal->j_tail = ntohl(jsb->s_start); journal->j_first = ntohl(jsb->s_first); journal->j_last = ntohl(jsb->s_maxlen); return 0; }