From: Vyacheslav Dubeyko <slava@xxxxxxxxxxx> Subject: [PATCH v3 03/15] hfsplus: implement init/destroy journal object functionality The patch implements functionality of initialization (hfsplus_init_journal() method) and destruction (hfsplus_destroy_journal() method) of HFS+ journal object in memory. The hfsplus_init_journal(): (1) checks that HFS+ has journal; (2) allocate memory for main incapsulated objects; (3) check that journal is located inside file system's volume; (4) initialize journal's on-disk structures (in the case of necessity). The hfsplus_destroy_journal() method frees allocated memory. 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 | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 fs/hfsplus/journal.c diff --git a/fs/hfsplus/journal.c b/fs/hfsplus/journal.c new file mode 100644 index 0000000..89dea39 --- /dev/null +++ b/fs/hfsplus/journal.c @@ -0,0 +1,175 @@ +/* + * linux/fs/hfsplus/journal.c + * + * Vyacheslav Dubeyko <slava@xxxxxxxxxxx> + * + * Logic of HFS+ journaling + */ + +#include "hfsplus_fs.h" + +#define HFSPLUS_HAS_JOURNAL(sb) \ + (HFSPLUS_SB(sb)->s_vhdr->attributes & \ + cpu_to_be32(HFSPLUS_VOL_JOURNALED)) + +#define JIB_BLOCK(sb) \ + (be32_to_cpu(HFSPLUS_SB(sb)->s_vhdr->journal_info_block)) +#define JIB_FLAGS(jnl) \ + (be32_to_cpu(((struct hfsplus_journal *)(jnl))->jib->flags)) + +#define JH_BLOCK(sb, jnl) \ + (be64_to_cpu(((struct hfsplus_journal *)(jnl))->jib->offset) >> \ + HFSPLUS_SB(sb)->alloc_blksz_shift) + +#define BLOCK_TO_SEC(sb, blk) \ + ((sector_t)(blk) << \ + (HFSPLUS_SB(sb)->alloc_blksz_shift - HFSPLUS_SECTOR_SHIFT)) + +static int hfsplus_create_journal(struct super_block *sb, + struct hfsplus_journal *jnl) +{ + /* TODO: implement */ + return -EINVAL; +} + +/* + * hfsplus_init_journal - initialize journal object + * + * @sb: superblock + * + * Check presence of journal on volume and initialize journal object. + * It is assumed that superblock and volume header are initialized yet. + */ +int hfsplus_init_journal(struct super_block *sb) +{ + struct hfsplus_journal *jnl; + sector_t jib_blk; + sector_t jh_blk; + int err = 0; + + HFSPLUS_SB(sb)->jnl = NULL; + + if (!HFSPLUS_HAS_JOURNAL(sb)) + return 0; /* journal absent */ + + hfs_dbg(JOURNAL, "try to init journal subsystem\n"); + + jnl = kzalloc(sizeof(*jnl), GFP_KERNEL); + if (unlikely(!jnl)) + return -ENOMEM; + + hfs_dbg(JOURNAL, "HFS+ filesystem has journal\n"); + + jnl->jib_buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL); + if (unlikely(!jnl->jib_buf)) { + pr_err("unable to allocate jib_buf\n"); + err = -ENOMEM; + goto init_failed; + } + + jnl->jh_buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL); + if (unlikely(!jnl->jh_buf)) { + pr_err("unable to allocate jh_buf\n"); + err = -ENOMEM; + goto free_jib_buf; + } + + jib_blk = HFSPLUS_SB(sb)->blockoffset + JIB_BLOCK(sb); + + err = hfsplus_submit_bio(sb, BLOCK_TO_SEC(sb, jib_blk), + jnl->jib_buf, (void **)&jnl->jib, READ, NULL); + if (err) { + pr_err("unable to read journal info block %llu\n", + (unsigned long long)jib_blk); + goto free_jh_buf; + } + + hfs_dbg(JOURNAL, "jib_flags %#x\n", JIB_FLAGS(jnl)); + hfs_dbg(JOURNAL, "journal size %u\n", be32_to_cpu(jnl->jib->size)); + + if ((JIB_FLAGS(jnl) & HFSPLUS_JOURNAL_ON_OTHER_DEVICE) && + !(JIB_FLAGS(jnl) & HFSPLUS_JOURNAL_IN_FS)) { + err = -EOPNOTSUPP; + goto free_jh_buf; + } + + jh_blk = JH_BLOCK(sb, jnl); + + hfs_dbg(JOURNAL, "read journal header: jh_bkl %llu\n", + (unsigned long long)jh_blk); + + err = hfsplus_submit_bio(sb, BLOCK_TO_SEC(sb, jh_blk), + jnl->jh_buf, (void **)&jnl->jh, READ, NULL); + if (err) { + pr_err("unable to read journal header block %llu\n", + (unsigned long long)jh_blk); + goto free_jh_buf; + } + + if (JIB_FLAGS(jnl) & HFSPLUS_JOURNAL_NEED_INIT) { + hfs_dbg(JOURNAL, "create HFS+ journal\n"); + + err = hfsplus_create_journal(sb, jnl); + if (unlikely(err)) { + pr_err("fail to create HFS+ journal\n"); + goto free_jh_buf; + } + + jnl->jib->flags &= be32_to_cpu(~HFSPLUS_JOURNAL_NEED_INIT); + + err = hfsplus_submit_bio(sb, BLOCK_TO_SEC(sb, jh_blk), + jnl->jh_buf, NULL, WRITE_SYNC, NULL); + if (err) { + pr_err("unable to write journal header block %llu\n", + (unsigned long long)jh_blk); + goto free_jh_buf; + } + + err = hfsplus_submit_bio(sb, BLOCK_TO_SEC(sb, jib_blk), + jnl->jib_buf, NULL, WRITE_SYNC, NULL); + if (err) { + pr_err("unable to write journal info block %llu\n", + (unsigned long long)jib_blk); + goto free_jh_buf; + } + } + + mutex_init(&jnl->jnl_lock); + jnl->sbp = sb; + HFSPLUS_SB(sb)->jnl = jnl; + + return err; + +free_jh_buf: + kfree(jnl->jh_buf); + +free_jib_buf: + kfree(jnl->jib_buf); + +init_failed: + kfree(jnl); + + return err; +} + +/* + * hfsplus_destroy_journal - deinitialize journal (if it is present). + * + * @sb: superblock + */ +void hfsplus_destroy_journal(struct super_block *sb) +{ + struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); + struct hfsplus_journal *jnl = sbi->jnl; + + if (!jnl) + return; + + hfs_dbg(JOURNAL, "destroy journal subsystem\n"); + + /* TODO: stop journal thread */ + + kfree(jnl->jh_buf); + kfree(jnl->jib_buf); + kfree(jnl); +} -- 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