All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 07/15] hfsplus: implement check consistency of journal log file
@ 2014-02-23 15:33 Vyacheslav Dubeyko
  0 siblings, 0 replies; only message in thread
From: Vyacheslav Dubeyko @ 2014-02-23 15:33 UTC (permalink / raw)
  To: Linux FS devel list
  Cc: Al Viro, ChristophHellwig, Hin-Tak Leung, Andrew Morton

From: Vyacheslav Dubeyko <slava@dubeyko.com>
Subject: [PATCH v4 07/15] hfsplus: implement check consistency of journal log file

This patch implements functionality of checking main HFS+ journal
structures (journal info block and journal header) before replaying
of journal buffer's transactions.

Signed-off-by: Vyacheslav Dubeyko <slava@dubeyko.com>
CC: Al Viro <viro@zeniv.linux.org.uk>
CC: Christoph Hellwig <hch@infradead.org>
Tested-by: Hin-Tak Leung <htl10@users.sourceforge.net>
---
 fs/hfsplus/journal.c |  161 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 161 insertions(+)

diff --git a/fs/hfsplus/journal.c b/fs/hfsplus/journal.c
index f0a0815..049cff5 100644
--- a/fs/hfsplus/journal.c
+++ b/fs/hfsplus/journal.c
@@ -62,6 +62,10 @@
 	((sector_t)(blk) << \
 	 (HFSPLUS_SB(sb)->alloc_blksz_shift - HFSPLUS_SECTOR_SHIFT))
 
+#define TR_START(jnl) \
+	(le64_to_cpu(JNL_SWAP64(jnl, HFSPLUS_JH(jnl)->start)))
+#define LAST_TR_END(jnl) \
+	(le64_to_cpu(JNL_SWAP64(jnl, HFSPLUS_JH(jnl)->end)))
 #define JHDR_SIZE(jnl) \
 	(le32_to_cpu(JNL_SWAP32(jnl, HFSPLUS_JH(jnl)->jhdr_size)))
 
@@ -161,6 +165,34 @@ static u32 calc_internal_checksum(u32 seed, unsigned char *ptr, int len)
 #define HFSPLUS_CALC_CHECKSUM(ptr, len) \
 	HFSPLUS_CHECKSUM(calc_internal_checksum(0, ptr, len))
 
+static int hfsplus_replay_journal_header(struct super_block *sb)
+{
+	struct hfsplus_journal *jnl = HFSPLUS_SB(sb)->jnl;
+	struct hfsplus_journal_header *jh = jnl->jh;
+	sector_t jh_blk = JH_BLOCK(sb, jnl);
+	__le32 calc_cksum;
+	int err;
+
+	hfs_dbg(JOURNAL, "replay journal header\n");
+
+	jh->start = JNL_SWAP64(jnl, cpu_to_le64((u64)JHDR_SIZE(jnl)));
+	jh->end = JNL_SWAP64(jnl, cpu_to_le64((u64)JHDR_SIZE(jnl)));
+
+	jh->checksum = 0;
+	calc_cksum = HFSPLUS_CALC_CHECKSUM((unsigned char *)jh, sizeof(*jh));
+	jh->checksum = JNL_SWAP32(jnl, calc_cksum);
+
+	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);
+		return err;
+	}
+
+	return 0;
+}
+
 /*
  * hfsplus_create_journal - create journal
  *
@@ -251,6 +283,127 @@ static int hfsplus_create_journal(struct super_block *sb,
 	return 0;
 }
 
+static inline
+bool hfsplus_journal_empty(struct hfsplus_journal *jnl)
+{
+	return TR_START(jnl) == LAST_TR_END(jnl);
+}
+
+static int hfsplus_replay_journal(struct super_block *sb)
+{
+	/* TODO: implement */
+	return -EINVAL;
+}
+
+static
+int hfsplus_check_journal_info_block(struct hfsplus_journal_info_block *jib)
+{
+	u32 jib_flags;
+
+	jib_flags = be32_to_cpu(jib->flags);
+	hfs_dbg(JOURNAL, "jib->flags: %#x\n", jib_flags);
+
+	/* Check that journal is on another volume */
+	if (jib_flags & HFSPLUS_JOURNAL_ON_OTHER_DEVICE &&
+	    !(jib_flags & HFSPLUS_JOURNAL_IN_FS)) {
+		pr_err("unable to access the HFS+ journal\n");
+		return -EOPNOTSUPP;
+	}
+
+	/* Check that journal is created yet */
+	if (jib_flags & HFSPLUS_JOURNAL_NEED_INIT) {
+		pr_err("HFS+ journal is not created\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int hfsplus_verify_journal_header(struct hfsplus_journal *jnl)
+{
+	struct hfsplus_journal_header *jh = jnl->jh;
+	__le32 magic = cpu_to_le32(HFSPLUS_JOURNAL_HEADER_MAGIC);
+	__le32 endian = cpu_to_le32(HFSPLUS_JOURNAL_HEADER_ENDIAN);
+	__le32 jh_checksum;
+	__le32 checksum;
+
+	if (JNL_SWAP32(jnl, jh->magic) != magic ||
+	    JNL_SWAP32(jnl, jh->endian) != endian) {
+		pr_err("invalid journal header\n");
+		return -EIO;
+	}
+
+	jh_checksum = JNL_SWAP32(jnl, jh->checksum);
+
+	jh->checksum = 0;
+	checksum = HFSPLUS_CALC_CHECKSUM((unsigned char *)jh, sizeof(*jh));
+
+	if (le32_to_cpu(checksum) != le32_to_cpu(jh_checksum)) {
+		jh->checksum = JNL_SWAP32(jnl, jh_checksum);
+		pr_err("invalid journal header\n");
+		hfs_dbg(JOURNAL, "calculated CRC %#x, jh_checksum %#x\n",
+			checksum, le32_to_cpu(jh_checksum));
+		return -EIO;
+	}
+
+	jh->checksum = JNL_SWAP32(jnl, jh_checksum);
+
+	return 0;
+}
+
+/*
+ * hfsplus_check_journal - check consistency of journal log file.
+ *
+ * @sb: superblock
+ */
+int hfsplus_check_journal(struct super_block *sb)
+{
+	struct hfsplus_journal *jnl = HFSPLUS_SB(sb)->jnl;
+	int err;
+
+	if (!jnl) {
+		hfs_dbg(JOURNAL, "HFS+ journal absent");
+		return 0;
+	}
+
+	hfs_dbg(JOURNAL, "check HFS+ journal\n");
+
+	err = hfsplus_check_journal_info_block(jnl->jib);
+	if (err)
+		return err;
+
+	err = hfsplus_verify_journal_header(jnl);
+	if (err)
+		return err;
+
+	if (test_and_clear_bit(HFSPLUS_SB_NORECOVERY, &HFSPLUS_SB(sb)->flags)) {
+		pr_info("journal replay is skiped, mounting read-only.\n");
+		sb->s_flags |= MS_RDONLY;
+		return -EROFS;
+	}
+
+	if (hfsplus_journal_empty(jnl)) {
+		err = hfsplus_replay_journal_header(sb);
+		if (unlikely(err)) {
+			pr_err("journal replay failed, please run fsck.hfsplus\n");
+			return err;
+		}
+		/* If they're the same, we can mount, it's clean */
+		hfs_dbg(JOURNAL, "journal is empty\n");
+		return 0;
+	} else {
+		/* Try to replay journal */
+		err = hfsplus_replay_journal(sb);
+		if (unlikely(err)) {
+			pr_err("journal replay failed, please run fsck.hfsplus\n");
+			return err;
+		}
+		hfs_dbg(JOURNAL, "journal replay is done\n");
+	}
+
+	return 0;
+}
+
 /*
  * hfsplus_init_journal - initialize journal object
  *
@@ -328,6 +481,13 @@ int hfsplus_init_journal(struct super_block *sb)
 	jnl->endianness = hfsplus_check_journal_endianness(jnl->jh);
 
 	if (JIB_FLAGS(jnl) & HFSPLUS_JOURNAL_NEED_INIT) {
+		if (test_and_clear_bit(HFSPLUS_SB_NORECOVERY,
+					&HFSPLUS_SB(sb)->flags)) {
+			sb->s_flags |= MS_RDONLY;
+			err = -EROFS;
+			goto finish_journal_init;
+		}
+
 		hfs_dbg(JOURNAL, "create HFS+ journal\n");
 
 		err = hfsplus_create_journal(sb, jnl);
@@ -359,6 +519,7 @@ int hfsplus_init_journal(struct super_block *sb)
 		goto free_jh_buf;
 	}
 
+finish_journal_init:
 	mutex_init(&jnl->jnl_lock);
 	jnl->sbp = sb;
 	HFSPLUS_SB(sb)->jnl = jnl;
-- 
1.7.9.5




^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2014-02-23 15:33 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-23 15:33 [PATCH v4 07/15] hfsplus: implement check consistency of journal log file Vyacheslav Dubeyko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.