* [PATCH 04/14] hfsplus: implement functionality for HFSPLUS_JOURNAL_NEED_INIT flag
@ 2013-12-26 9:45 Vyacheslav Dubeyko
0 siblings, 0 replies; only message in thread
From: Vyacheslav Dubeyko @ 2013-12-26 9:45 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 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
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2013-12-26 9:52 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-26 9:45 [PATCH 04/14] hfsplus: implement functionality for HFSPLUS_JOURNAL_NEED_INIT flag Vyacheslav Dubeyko
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).