static errcode_t walk_journal(ocfs2_filesys *fs, int slot, struct journal_info *ji, char *buf, int recover) { errcode_t err, ret = 0; uint32_t next_seq; uint64_t next_block, nr; journal_superblock_t *jsb = ji->ji_jsb; journal_header_t jh; next_seq = jsb->s_sequence; next_block = jsb->s_start; /* s_start == 0 when we have nothing to do */ if (next_block == 0) return 0; /* ret is set when bad tags are seen in the first scan and when there * are io errors in the recovery scan. Only stop walking the journal * when bad tags are seen in the first scan. */ while(recover || !ret) { verbosef("next_seq %"PRIu32" final_seq %"PRIu32" next_block " "%"PRIu64"\n", next_seq, ji->ji_final_seq, next_block); if (recover && seq_geq(next_seq, ji->ji_final_seq)) break; /* only mark the blocks used on the first pass */ err = read_journal_block(fs, ji, next_block, buf, !recover); if (err) { ret = err; break; } next_block = jwrap(jsb, next_block + 1); memcpy(&jh, buf, sizeof(jh)); jh.h_magic = be32_to_cpu(jh.h_magic); jh.h_blocktype = be32_to_cpu(jh.h_blocktype); jh.h_sequence = be32_to_cpu(jh.h_sequence); verbosef("jh magic %x\n", jh.h_magic); if (jh.h_magic != JBD2_MAGIC_NUMBER) break; verbosef("jh block %x\n", jh.h_blocktype); verbosef("jh seq %"PRIu32"\n", jh.h_sequence); if (jh.h_sequence != next_seq) break; switch(jh.h_blocktype) { case JBD2_DESCRIPTOR_BLOCK: verbosef("found a desc type %x\n", jh.h_blocktype); /* replay the blocks described in the desc block */ if (recover) { err = replay_blocks(fs, ji, buf, next_seq, &next_block); if (err) ret = err; continue; } /* just record the blocks as used and carry on */ err = count_tags(fs, jsb, buf, &nr); if (err) ret = err; else next_block = jwrap(jsb, next_block + nr); break; case JBD2_COMMIT_BLOCK: verbosef("found a commit type %x\n", jh.h_blocktype); next_seq++; break; case JBD2_REVOKE_BLOCK: verbosef("found a revoke type %x\n", jh.h_blocktype); add_revoke_records(ji, buf, jsb->s_blocksize, next_seq); break; default: verbosef("unknown type %x\n", jh.h_blocktype); break; } } verbosef("done scanning with seq %"PRIu32"\n", next_seq); if (!recover) { ji->ji_set_final_seq = 1; ji->ji_final_seq = next_seq; } else if (ji->ji_final_seq != next_seq) { printf("Replaying slot %d's journal stopped at seq %"PRIu32" " "but an initial scan indicated that it should have " "stopped at seq %"PRIu32"\n", ji->ji_slot, next_seq, ji->ji_final_seq); if (ret == 0) err = OCFS2_ET_IO; } return ret; }
static void dump_journal(char *cmdname, FILE *out_file, struct journal_source *source) { struct ext2_super_block *sb; char jsb_buffer[1024]; char buf[8192]; journal_superblock_t *jsb; unsigned int blocksize = 1024; unsigned int got; int retval; __u32 magic, sequence, blocktype; journal_header_t *header; tid_t transaction; unsigned int blocknr = 0; /* First, check to see if there's an ext2 superblock header */ retval = read_journal_block(cmdname, source, 0, buf, 2048, &got); if (retval) return; jsb = (journal_superblock_t *) buf; sb = (struct ext2_super_block *) (buf+1024); #ifdef ENABLE_SWAPFS if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ext2fs_swap_super(sb); #endif if ((be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) && (sb->s_magic == EXT2_SUPER_MAGIC) && (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { blocksize = EXT2_BLOCK_SIZE(sb); blocknr = (blocksize == 1024) ? 2 : 1; uuid_unparse(sb->s_uuid, jsb_buffer); fprintf(out_file, "Ext2 superblock header found.\n"); if (dump_all) { fprintf(out_file, "\tuuid=%s\n", jsb_buffer); fprintf(out_file, "\tblocksize=%d\n", blocksize); fprintf(out_file, "\tjournal data size %ld\n", (long) sb->s_blocks_count); } } /* Next, read the journal superblock */ retval = read_journal_block(cmdname, source, blocknr*blocksize, jsb_buffer, 1024, &got); if (retval) return; jsb = (journal_superblock_t *) jsb_buffer; if (be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) { fprintf(out_file, "Journal superblock magic number invalid!\n"); return; } blocksize = be32_to_cpu(jsb->s_blocksize); transaction = be32_to_cpu(jsb->s_sequence); blocknr = be32_to_cpu(jsb->s_start); fprintf(out_file, "Journal starts at block %u, transaction %u\n", blocknr, transaction); if (!blocknr) /* Empty journal, nothing to do. */ return; while (1) { retval = read_journal_block(cmdname, source, blocknr*blocksize, buf, blocksize, &got); if (retval || got != blocksize) return; header = (journal_header_t *) buf; magic = be32_to_cpu(header->h_magic); sequence = be32_to_cpu(header->h_sequence); blocktype = be32_to_cpu(header->h_blocktype); if (magic != JFS_MAGIC_NUMBER) { fprintf (out_file, "No magic number at block %u: " "end of journal.\n", blocknr); return; } if (sequence != transaction) { fprintf (out_file, "Found sequence %u (not %u) at " "block %u: end of journal.\n", sequence, transaction, blocknr); return; } if (dump_descriptors) { fprintf (out_file, "Found expected sequence %u, " "type %u (%s) at block %u\n", sequence, blocktype, type_to_name(blocktype), blocknr); } switch (blocktype) { case JFS_DESCRIPTOR_BLOCK: dump_descriptor_block(out_file, source, buf, jsb, &blocknr, blocksize, transaction); continue; case JFS_COMMIT_BLOCK: transaction++; blocknr++; WRAP(jsb, blocknr); continue; case JFS_REVOKE_BLOCK: dump_revoke_block(out_file, buf, jsb, blocknr, blocksize, transaction); blocknr++; WRAP(jsb, blocknr); continue; default: fprintf (out_file, "Unexpected block type %u at " "block %u.\n", blocktype, blocknr); return; } } }
static errcode_t replay_blocks(ocfs2_filesys *fs, struct journal_info *ji, char *buf, uint64_t seq, uint64_t *next_block) { char *tagp; journal_block_tag_t *tag; size_t i, num; char *io_buf = NULL; errcode_t err, ret = 0; int tag_bytes = ocfs2_journal_tag_bytes(ji->ji_jsb); uint32_t t_flags; uint64_t block64; tagp = buf + sizeof(journal_header_t); num = (ji->ji_jsb->s_blocksize - sizeof(journal_header_t)) / tag_bytes; ret = ocfs2_malloc_blocks(fs->fs_io, 1, &io_buf); if (ret) { com_err(whoami, ret, "while allocating a block buffer"); goto out; } for(i = 0; i < num; i++, tagp += tag_bytes, (*next_block)++) { tag = (journal_block_tag_t *)tagp; t_flags = be32_to_cpu(tag->t_flags); block64 = ocfs2_journal_tag_block(tag, tag_bytes); *next_block = jwrap(ji->ji_jsb, *next_block); verbosef("recovering journal block %"PRIu64" to disk block " "%"PRIu64"\n", *next_block, block64); if (revoke_this_block(&ji->ji_revoke, block64, seq)) goto skip_io; err = read_journal_block(fs, ji, *next_block, io_buf, 1); if (err) { ret = err; goto skip_io; } if (t_flags & JBD2_FLAG_ESCAPE) { uint32_t magic = cpu_to_be32(JBD2_MAGIC_NUMBER); memcpy(io_buf, &magic, sizeof(magic)); } err = io_write_block(fs->fs_io, block64, 1, io_buf); if (err) ret = err; skip_io: if (t_flags & JBD2_FLAG_LAST_TAG) i = num; /* be sure to increment next_block */ if (!(t_flags & JBD2_FLAG_SAME_UUID)) tagp += 16; } out: if (io_buf) ocfs2_free(&io_buf); return ret; }