All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 12/15] hfsplus: implement functionality of transaction's block check
@ 2014-02-23 15:34 Vyacheslav Dubeyko
  0 siblings, 0 replies; only message in thread
From: Vyacheslav Dubeyko @ 2014-02-23 15:34 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 12/15] hfsplus: implement functionality of transaction's block check

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 method of checking description of
transaction's block before replaying of it.

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 |  114 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 113 insertions(+), 1 deletion(-)

diff --git a/fs/hfsplus/journal.c b/fs/hfsplus/journal.c
index 5b430b6..bdc6fc6 100644
--- a/fs/hfsplus/journal.c
+++ b/fs/hfsplus/journal.c
@@ -565,6 +565,109 @@ struct hfsplus_block_info *hfsplus_get_binfo(struct super_block *sb,
 	return &desc->binfo[diff];
 }
 
+static int hfsplus_check_transaction_block(struct super_block *sb, int i,
+					   struct hfsplus_blist_desc *desc)
+{
+	struct hfsplus_journal *jnl = HFSPLUS_SB(sb)->jnl;
+	struct hfsplus_blhdr *blhdr = &desc->blhdr;
+	struct hfsplus_block_info *binfo;
+	sector_t sec;
+	u32 size;
+	u32 checksum = 0;
+	int err = 0;
+
+	hfs_dbg(JREPLAY, "check binfo[%u]\n", i);
+
+	binfo = hfsplus_get_binfo(sb, i, desc);
+	if (!binfo) {
+		pr_err("unable to get binfo[%u]\n", i);
+		return -EIO;
+	}
+
+	hfs_dbg(JREPLAY, "bnum: %llu, bsize: %u\n",
+		BNUM(jnl, binfo), BSIZE(jnl, binfo));
+
+	if (BNUM(jnl, binfo) == ~(u64)0) {
+		hfs_dbg(JREPLAY, "don't add *killed* block %llu\n",
+			BNUM(jnl, binfo));
+		err = 0; /* don't add "killed" blocks */
+		goto end_check;
+	}
+
+	BUG_ON(BSIZE(jnl, binfo) % HFSPLUS_SECTOR_SIZE);
+
+	if ((BSIZE(jnl, binfo) / HFSPLUS_SECTOR_SIZE) == 0) {
+		pr_warn("transaction block size is not aligned\n");
+		err = -EINVAL;
+		goto end_check;
+	}
+
+	sec = JOURNAL_OFF_TO_SEC(sb);
+	size = BSIZE(jnl, binfo);
+	while (size > 0) {
+		void *block_ptr;
+		size_t check_size = HFSPLUS_SECTOR_SIZE;
+		size_t rest_bytes;
+
+		if (need_to_wrap_journal(jnl, TR_START(jnl), check_size)) {
+			hfsplus_wrap_journal(sb, TR_START(jnl), check_size);
+			sec = JOURNAL_OFF_TO_SEC(sb);
+		}
+
+		err = hfsplus_submit_bio(sb, sec, desc->src_buf,
+					 (void **)&block_ptr,
+					 READA, &rest_bytes);
+		if (err) {
+			pr_err("unable to read sector %llu of blist\n",
+				(unsigned long long)sec);
+			goto end_check;
+		}
+
+		BUG_ON(rest_bytes < HFSPLUS_SECTOR_SIZE);
+
+		if (TR_START(jnl) > LAST_TR_END(jnl)) {
+			if ((TR_START(jnl) + check_size) > JOURNAL_SIZE(jnl))
+				err = -EIO;
+		} else if (TR_START(jnl) < LAST_TR_END(jnl)) {
+			if ((TR_START(jnl) + check_size) > LAST_TR_END(jnl))
+				err = -EIO;
+		} else /* start == end */
+			err = -EIO;
+
+		if (err) {
+			pr_err("invalid transaction: start %llu, end %llu, journal size %llu, bsize %zu\n",
+				TR_START(jnl), LAST_TR_END(jnl),
+				JOURNAL_SIZE(jnl), check_size);
+			goto end_check;
+		}
+
+		if (NEED_CHECK_CSUM(jnl, blhdr)) {
+			checksum = calc_internal_checksum(checksum,
+							  block_ptr,
+							  check_size);
+		}
+
+		size -= check_size;
+		JH_START_ADD(jnl, check_size);
+		sec = JOURNAL_OFF_TO_SEC(sb);
+	}
+
+	if (NEED_CHECK_CSUM(jnl, blhdr)) {
+		if (HFSPLUS_CHECKSUM(checksum) !=
+		    JNL_SWAP32(jnl, binfo->block.checksum)) {
+			pr_err("invalid transaction's checksum\n");
+			hfs_dbg(JREPLAY, "calc checksum: %#x, checksum: %#x\n",
+				le32_to_cpu(HFSPLUS_CHECKSUM(checksum)),
+				le32_to_cpu(JNL_SWAP32(jnl,
+					    binfo->block.checksum)));
+			err = -EIO;
+		}
+	}
+
+end_check:
+	return err;
+}
+
 static inline
 bool hfsplus_journal_empty(struct hfsplus_journal *jnl)
 {
@@ -650,6 +753,7 @@ static int hfsplus_replay_journal(struct super_block *sb)
 	while (!hfsplus_journal_empty(jnl)) {
 		struct hfsplus_blhdr *blhdr;
 		struct hfsplus_block_info *binfo;
+		u32 really_used = 0;
 		u32 i;
 
 		if (TR_START(jnl) == JOURNAL_SIZE(jnl))
@@ -679,6 +783,8 @@ static int hfsplus_replay_journal(struct super_block *sb)
 		} else
 			JH_START_ADD(jnl, BLHDR_SIZE(jnl));
 
+		really_used += BLHDR_SIZE(jnl);
+
 		/* Check transaction */
 		for (i = 1; i < TR_BLOCKS(jnl, blhdr); i++) {
 			binfo = hfsplus_get_binfo(sb, i, &desc);
@@ -688,7 +794,13 @@ static int hfsplus_replay_journal(struct super_block *sb)
 				goto failed_journal_replay;
 			}
 
-			/* TODO: check transaction block */
+			err = hfsplus_check_transaction_block(sb, i, &desc);
+			if (err) {
+				pr_err("binfo[%u] is corrupted\n", i);
+				goto failed_journal_replay;
+			}
+
+			really_used += BSIZE(jnl, binfo);
 		}
 	}
 
-- 
1.7.9.5




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

only message in thread, other threads:[~2014-02-23 15:34 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:34 [PATCH v4 12/15] hfsplus: implement functionality of transaction's block check 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.