linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Vyacheslav Dubeyko <slava@dubeyko.com>
To: Linux FS devel list <linux-fsdevel@vger.kernel.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>,
	ChristophHellwig <hch@infradead.org>,
	Hin-Tak Leung <htl10@users.sourceforge.net>,
	Andrew Morton <akpm@linux-foundation.org>
Subject: [PATCH 04/14] hfsplus: implement functionality for HFSPLUS_JOURNAL_NEED_INIT flag
Date: Thu, 26 Dec 2013 13:45:06 +0400	[thread overview]
Message-ID: <1388051106.4168.64.camel@slavad-ubuntu> (raw)

From: Vyacheslav Dubeyko <slava@dubeyko.com>
Subject: [PATCH 04/14] hfsplus: implement functionality for HFSPLUS_JOURNAL_NEED_INIT flag

This patch implements functionality of creation of journal header,
journal buffer and initialization of them.

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

diff --git a/fs/hfsplus/journal.c b/fs/hfsplus/journal.c
index c6d76de..6f61e77 100644
--- a/fs/hfsplus/journal.c
+++ b/fs/hfsplus/journal.c
@@ -8,6 +8,23 @@
 
 #include "hfsplus_fs.h"
 
+#define HFSPLUS_1KB_SHIFT		10
+#define HFSPLUS_1MB_SHIFT		20
+#define HFSPLUS_1GB_SHIFT		30
+#define HFSPLUS_1TB_SHIFT		40
+
+#define HFSPLUS_JOURNAL_MIN_SIZE	(512 * 1024)
+#define HFSPLUS_JOURNAL_DEFAULT_SIZE	(8 * (1 << HFSPLUS_1MB_SHIFT))
+#define HFSPLUS_JOURNAL_MAX_SIZE	(512 * (1 << HFSPLUS_1MB_SHIFT))
+
+#define HFSPLUS_VOLUME_GRAIN		100 /* 100 GB*/
+#define HFSPLUS_JSCALE_MAX		64
+
+#define HFSPLUS_VOLUME_MIN_THRESHOLD	(128 * (1 << HFSPLUS_1MB_SHIFT))
+#define HFSPLUS_DEFAULT_JHDR_SIZE	(4 * 1024)
+#define HFSPLUS_BLHDR_SIZE_MIN		(4 * 1024)
+#define HFSPLUS_BLHDR_SIZE_MAX		(16 * 1024)
+
 #define HFSPLUS_HAS_JOURNAL(sb) \
 	(HFSPLUS_SB(sb)->s_vhdr->attributes & \
 	 cpu_to_be32(HFSPLUS_VOL_JOURNALED))
@@ -25,8 +42,157 @@
 	((sector_t)(blk) << \
 	 (HFSPLUS_SB(sb)->alloc_blksz_shift - HFSPLUS_SECTOR_SHIFT))
 
+/*
+ * We want at least 8 megs of journal for each 100 gigs of
+ * disk space.  We cap the size at 512 megs (64x default), unless
+ * the allocation block size is larger, in which case we use one
+ * allocation block.
+ *
+ * Volumes that are 128 megs or less in size have such
+ * a small bitmap (one 4k-block) and inherhently such
+ * a small btree that we can get by with a much smaller
+ * journal. Even in a worst case scenario of a catalog
+ * filled with very long korean file names we should
+ * never touch more than 256k of meta-data for a single
+ * transaction.  therefore we'll make the journal 512k
+ * which is safe and doesn't waste much space.
+ */
+static u64 calc_journal_size(struct super_block *sb)
+{
+	u64 journal_size;
+	u64 jscale;
+	u64 volume_size = (u64)HFSPLUS_SB(sb)->sect_count *
+				HFSPLUS_SECTOR_SIZE;
+	u64 volume_grain = (u64)HFSPLUS_VOLUME_GRAIN *
+				((u64)1 << HFSPLUS_1GB_SHIFT);
+
+	jscale = volume_size / volume_grain;
+
+	if (jscale > HFSPLUS_JSCALE_MAX)
+		jscale = HFSPLUS_JSCALE_MAX;
+
+	journal_size = HFSPLUS_JOURNAL_DEFAULT_SIZE * (jscale + 1);
+
+	if (journal_size > HFSPLUS_JOURNAL_MAX_SIZE)
+		journal_size = HFSPLUS_JOURNAL_MAX_SIZE;
+
+	if (volume_size < HFSPLUS_VOLUME_MIN_THRESHOLD)
+		journal_size = HFSPLUS_JOURNAL_MIN_SIZE;
+
+	return journal_size;
+}
+
+/*
+ * Technical Note TN1150
+ *
+ * Checksums can be verified as part of a basic consistency check.
+ * To verify the checksum, temporarily set the checksum field to zero
+ * and then call the calc_checksum routine with the address and size of
+ * the header being checksummed. The function result should equal the
+ * original value of the checksum field.
+ *
+ * static int
+ * calc_checksum(unsigned char *ptr, int len)
+ * {
+ *    int i, cksum=0;
+ *
+ *    for(i=0; i < len; i++, ptr++) {
+ *        cksum = (cksum << 8) ^ (cksum + *ptr);
+ *    }
+ *
+ *    return (~cksum);
+ * }
+*/
+static u32 calc_internal_checksum(u32 seed, unsigned char *ptr, int len)
+{
+	int i;
+	u32 chksum = seed;
+
+	for (i = 0; i < len; i++, ptr++)
+		chksum = (chksum << 8) ^ (chksum + *ptr);
+
+	return chksum;
+}
+
+#define HFSPLUS_CHECKSUM(internal_checksum) \
+	(cpu_to_le32(~(u32)(internal_checksum)))
+
+#define HFSPLUS_CALC_CHECKSUM(ptr, len) \
+	HFSPLUS_CHECKSUM(calc_internal_checksum(0, ptr, len))
+
+/*
+ * hfsplus_create_journal - create journal
+ *
+ * @sb: superblock
+ *
+ * Create journal header, journal buffer and initialize them.
+ * It is assumed that presence of journal is already verified.
+ */
 static int hfsplus_create_journal(struct super_block *sb,
-				  struct hfsplus_journal *jnl);
+				  struct hfsplus_journal *jnl)
+{
+	u64 offset = be64_to_cpu(jnl->jib->offset);
+	int blksz_bits = HFSPLUS_SB(sb)->alloc_blksz_shift;
+	u32 blksz = HFSPLUS_SB(sb)->alloc_blksz;
+	u64 journal_size = be64_to_cpu(jnl->jib->size);
+	u64 calculated_journal_size;
+
+	hfs_dbg(JOURNAL, "create HFS+ journal: blocksize %u, jib_hdr->offset %llu\n",
+		blksz, offset);
+
+	if (((offset >> blksz_bits) << blksz_bits) != offset) {
+		pr_err("journal size is not aligned\n");
+		return -EIO;
+	}
+
+	if (journal_size < HFSPLUS_JOURNAL_MIN_SIZE ||
+	    journal_size > HFSPLUS_JOURNAL_MAX_SIZE) {
+		pr_err("journal size %llu looks bogus\n", journal_size);
+		return -EIO;
+	}
+
+	if ((journal_size % blksz) != 0) {
+		pr_err("journal size %llu is not an even multiple of block size %u\n",
+			journal_size, blksz);
+		return -EIO;
+	}
+
+	calculated_journal_size = calc_journal_size(sb);
+	if (journal_size != calculated_journal_size) {
+		pr_warn("journal size %llu is different from calculated journal size %llu\n",
+			journal_size, calculated_journal_size);
+	}
+
+	jnl->jh->magic = cpu_to_le32(HFSPLUS_JOURNAL_HEADER_MAGIC);
+	jnl->jh->endian = cpu_to_le32(HFSPLUS_JOURNAL_HEADER_ENDIAN);
+
+	/*
+	 * The jhdr_size is a 512 byte for volumes are less than 1TB.
+	 * Otherwise, jhdr_size is 4096 bytes for 1+TB volumes.
+	 */
+	if (HFSPLUS_SB(sb)->sect_count >
+	    (((u64)1 << HFSPLUS_1TB_SHIFT) >> HFSPLUS_SECTOR_SHIFT))
+		jnl->jh->jhdr_size = cpu_to_le32(HFSPLUS_DEFAULT_JHDR_SIZE);
+	else
+		jnl->jh->jhdr_size = cpu_to_le32(HFSPLUS_SECTOR_SIZE);
+
+	if (blksz < HFSPLUS_BLHDR_SIZE_MIN)
+		jnl->jh->blhdr_size = cpu_to_le32(HFSPLUS_BLHDR_SIZE_MIN);
+	else if (blksz > HFSPLUS_BLHDR_SIZE_MAX)
+		jnl->jh->blhdr_size = cpu_to_le32(HFSPLUS_BLHDR_SIZE_MAX);
+	else
+		jnl->jh->blhdr_size = cpu_to_le32(sb->s_blocksize);
+
+	jnl->jh->start = cpu_to_le64(JHDR_SIZE(jnl->jh));
+	jnl->jh->end = cpu_to_le64(JHDR_SIZE(jnl->jh));
+	jnl->jh->size = cpu_to_le64(journal_size);
+
+	jnl->jh->checksum = 0;
+	jnl->jh->checksum = HFSPLUS_CALC_CHECKSUM((unsigned char *)(jnl->jh),
+						  sizeof(*(jnl->jh)));
+
+	return 0;
+}
 
 /*
  * hfsplus_init_journal - initialize journal object
-- 
1.7.9.5




                 reply	other threads:[~2013-12-26  9:52 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1388051106.4168.64.camel@slavad-ubuntu \
    --to=slava@dubeyko.com \
    --cc=akpm@linux-foundation.org \
    --cc=hch@infradead.org \
    --cc=htl10@users.sourceforge.net \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).