static int count_tags(journal_t *journal, struct buffer_head *bh) { char * tagp; journal_block_tag_t * tag; int nr = 0, size = journal->j_blocksize; int tag_bytes = journal_tag_bytes(journal); if (journal_has_csum_v2or3(journal)) size -= sizeof(struct journal_block_tail); tagp = &bh->b_data[sizeof(journal_header_t)]; while ((tagp - bh->b_data + tag_bytes) <= size) { tag = (journal_block_tag_t *) tagp; nr++; tagp += tag_bytes; if (!(tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID))) tagp += 16; if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG)) break; } return nr; }
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 errcode_t journal_add_blocks_to_trans(journal_transaction_t *trans, blk64_t *block_list, size_t block_len, FILE *fp) { blk64_t curr_blk, jdb_blk; size_t i, j; int csum_size = 0; journal_header_t *jdb; journal_block_tag_t *jdbt; int tag_bytes; void *buf = NULL, *jdb_buf = NULL; struct buffer_head *bh = NULL, *data_bh; errcode_t err; JOURNAL_CHECK_TRANS_MAGIC(trans); if ((trans->flags & J_TRANS_COMMITTED) || !(trans->flags & J_TRANS_OPEN)) return EXT2_ET_INVALID_ARGUMENT; if (block_len == 0) return 0; /* Do we need to leave space at the end for a checksum? */ if (journal_has_csum_v2or3(trans->journal)) csum_size = sizeof(struct journal_block_tail); curr_blk = jdb_blk = trans->block; data_bh = getblk(trans->journal->j_dev, curr_blk, trans->journal->j_blocksize); if (data_bh == NULL) return ENOMEM; buf = data_bh->b_data; /* write the descriptor block header */ bh = getblk(trans->journal->j_dev, curr_blk, trans->journal->j_blocksize); if (bh == NULL) { err = ENOMEM; goto error; } jdb = jdb_buf = bh->b_data; jdb->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); jdb->h_blocktype = ext2fs_cpu_to_be32(JFS_DESCRIPTOR_BLOCK); jdb->h_sequence = ext2fs_cpu_to_be32(trans->tid); jdbt = (journal_block_tag_t *)(jdb + 1); curr_blk++; for (i = 0; i < block_len; i++) { j = fread(data_bh->b_data, trans->journal->j_blocksize, 1, fp); if (j != 1) { err = errno; goto error; } tag_bytes = journal_tag_bytes(trans->journal); /* No space left in descriptor block, write it out */ if ((char *)jdbt + tag_bytes > (char *)jdb_buf + trans->journal->j_blocksize - csum_size) { jbd2_descr_block_csum_set(trans->journal, bh); err = journal_bmap(trans->journal, jdb_blk, &bh->b_blocknr); if (err) goto error; dbg_printf("Writing descriptor block at %llu:%llu\n", jdb_blk, bh->b_blocknr); mark_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh); err = bh->b_err; if (err) goto error; jdbt = (journal_block_tag_t *)(jdb + 1); jdb_blk = curr_blk; curr_blk++; } if (block_list[i] >= ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) { err = EXT2_ET_BAD_BLOCK_NUM; goto error; } /* Fill out the block tag */ jdbt->t_blocknr = ext2fs_cpu_to_be32(block_list[i] & 0xFFFFFFFF); jdbt->t_flags = 0; if (jdbt != (journal_block_tag_t *)(jdb + 1)) jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID); else { memcpy(jdbt + tag_bytes, trans->journal->j_superblock->s_uuid, sizeof(trans->journal->j_superblock->s_uuid)); tag_bytes += 16; } if (i == block_len - 1) jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG); if (*((__u32 *)buf) == ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) { *((__u32 *)buf) = 0; jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_ESCAPE); } if (JFS_HAS_INCOMPAT_FEATURE(trans->journal, JFS_FEATURE_INCOMPAT_64BIT)) jdbt->t_blocknr_high = ext2fs_cpu_to_be32(block_list[i] >> 32); jbd2_block_tag_csum_set(trans->journal, jdbt, data_bh, trans->tid); /* Write the data block */ err = journal_bmap(trans->journal, curr_blk, &data_bh->b_blocknr); if (err) goto error; dbg_printf("Writing data block %llu at %llu:%llu tag %d\n", block_list[i], curr_blk, data_bh->b_blocknr, tag_bytes); mark_buffer_dirty(data_bh); ll_rw_block(WRITE, 1, &data_bh); err = data_bh->b_err; if (err) goto error; curr_blk++; jdbt = (journal_block_tag_t *)(((char *)jdbt) + tag_bytes); } /* Write out the last descriptor block */ if (jdbt != (journal_block_tag_t *)(jdb + 1)) { jbd2_descr_block_csum_set(trans->journal, bh); err = journal_bmap(trans->journal, jdb_blk, &bh->b_blocknr); if (err) goto error; dbg_printf("Writing descriptor block at %llu:%llu\n", jdb_blk, bh->b_blocknr); mark_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh); err = bh->b_err; if (err) goto error; } error: trans->block = curr_blk; if (bh) brelse(bh); brelse(data_bh); return err; }