From: Vyacheslav Dubeyko <slava@xxxxxxxxxxx> Subject: [PATCH v4 13/15] hfsplus: implement replay transaction's block functionality A group of related changes is called a transaction. When all of the changes of a transaction have been written to their normal locations on disk, that transaction has been committed, and is removed from the journal. The journal may contain several transactions. Copying changes from all transactions to their normal locations on disk is called replaying the journal. A single transaction consists of several blocks, including both the data to be written, and the location where that data is to be written. This is represented on disk by a block list header, which describes the number and sizes of the blocks, immediately followed by the contents of those blocks. This patch implements replaying of transaction's block in location is described by binfo in block list. Signed-off-by: Vyacheslav Dubeyko <slava@xxxxxxxxxxx> CC: Al Viro <viro@xxxxxxxxxxxxxxxxxx> CC: Christoph Hellwig <hch@xxxxxxxxxxxxx> Tested-by: Hin-Tak Leung <htl10@xxxxxxxxxxxxxxxxxxxxx> --- fs/hfsplus/journal.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/fs/hfsplus/journal.c b/fs/hfsplus/journal.c index bdc6fc6..292c32c 100644 --- a/fs/hfsplus/journal.c +++ b/fs/hfsplus/journal.c @@ -668,6 +668,97 @@ end_check: return err; } +static int hfsplus_replay_transaction_block(struct super_block *sb, int i, + struct hfsplus_blist_desc *desc) +{ + struct hfsplus_journal *jnl = HFSPLUS_SB(sb)->jnl; + struct hfsplus_block_info *binfo; + u64 bnum; + u32 bsize; + sector_t src_sec, dst_sec; + int err = 0; + + hfs_dbg(JREPLAY, "replay binfo[%u]\n", i); + + binfo = hfsplus_get_binfo(sb, i, desc); + if (!binfo) { + pr_err("unable to get binfo[%u]\n", i); + return -EIO; + } + + bnum = BNUM(jnl, binfo); + bsize = BSIZE(jnl, binfo); + + hfs_dbg(JREPLAY, "bnum: %llu, bsize: %u\n", bnum, bsize); + + if (bnum == ~(u64)0) { + hfs_dbg(JREPLAY, "don't add *killed* block %llu\n", bnum); + err = 0; /* don't add "killed" blocks */ + goto end_replay; + } + + src_sec = JOURNAL_OFF_TO_SEC(sb); + dst_sec = HFSPLUS_SB(sb)->blockoffset + bnum; + + hfs_dbg(JREPLAY, "dst_sec: %llu, bsize: %u\n", + (unsigned long long)dst_sec, bsize); + + while (bsize > 0) { + size_t buf_size = hfsplus_min_io_size(sb); + size_t dst_off = 0; + size_t rest_bytes; + + if (dst_sec >= HFSPLUS_SB(sb)->sect_count) { + pr_err("replay out of volume %llu\n", + (unsigned long long)dst_sec); + err = -EIO; + goto end_replay; + } + + while (dst_off < buf_size) { + void *src_ptr; + u64 start = TR_START(jnl); + size_t copy_size = HFSPLUS_SECTOR_SIZE; + + if (need_to_wrap_journal(jnl, start, copy_size)) { + hfsplus_wrap_journal(sb, start, copy_size); + src_sec = JOURNAL_OFF_TO_SEC(sb); + } + + err = hfsplus_submit_bio(sb, src_sec, desc->src_buf, + &src_ptr, READ, &rest_bytes); + if (err) { + pr_err("unable to read sector %llu of blist\n", + (unsigned long long)src_sec); + goto end_replay; + } + + BUG_ON(rest_bytes < HFSPLUS_SECTOR_SIZE); + + memcpy((void *)((u8 *)desc->dst_buf + dst_off), + desc->src_buf, copy_size); + + dst_off += copy_size; + bsize -= copy_size; + JH_START_ADD(jnl, copy_size); + src_sec = JOURNAL_OFF_TO_SEC(sb); + } + + err = hfsplus_submit_bio(sb, dst_sec, desc->dst_buf, NULL, + WRITE_SYNC, NULL); + if (err) { + pr_err("unable to replay sector %llu\n", + (unsigned long long)dst_sec); + goto end_replay; + } + + dst_sec += buf_size >> HFSPLUS_SECTOR_SHIFT; + } + +end_replay: + return err; +} + static inline bool hfsplus_journal_empty(struct hfsplus_journal *jnl) { @@ -802,6 +893,20 @@ static int hfsplus_replay_journal(struct super_block *sb) really_used += BSIZE(jnl, binfo); } + + /* Replay transaction */ + for (i = 1; i < TR_BLOCKS(jnl, blhdr); i++) { + binfo = hfsplus_get_binfo(sb, i, &desc); + if (!binfo) { + pr_err("unable to get binfo[%u]\n", i); + err = -EIO; + goto failed_journal_replay; + } + + err = hfsplus_replay_transaction_block(sb, i, &desc); + if (err) + goto failed_journal_replay; + } } /* TODO: implement */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html