[Ocfs2-tools-commits] jlbec commits r1205 - in branches/ecc: . extras libocfs2 libocfs2/include

svn-commits@oss.oracle.com svn-commits at oss.oracle.com
Mon Jun 19 11:37:07 CDT 2006


Author: jlbec
Date: 2006-06-19 11:36:59 -0500 (Mon, 19 Jun 2006)
New Revision: 1205

Added:
   branches/ecc/extras/hamming.c
   branches/ecc/libocfs2/blockcheck.c
   branches/ecc/libocfs2/include/blockcheck.h
Modified:
   branches/ecc/Config.make.in
   branches/ecc/configure.in
   branches/ecc/extras/
   branches/ecc/extras/Makefile
   branches/ecc/libocfs2/Makefile
   branches/ecc/libocfs2/chain.c
   branches/ecc/libocfs2/dirblock.c
   branches/ecc/libocfs2/extents.c
   branches/ecc/libocfs2/include/ocfs2.h
   branches/ecc/libocfs2/include/ocfs2_fs.h
   branches/ecc/libocfs2/inode.c
   branches/ecc/libocfs2/newdir.c
Log:

Add the blockcheck code for the library.




Modified: branches/ecc/Config.make.in
===================================================================
--- branches/ecc/Config.make.in	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/Config.make.in	2006-06-19 16:36:59 UTC (rev 1205)
@@ -51,6 +51,7 @@
 COM_ERR_CFLAGS = @COM_ERR_CFLAGS@
 COM_ERR_LIBS = @COM_ERR_LIBS@
 UUID_LIBS = @UUID_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
 
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_LIBS = @GLIB_LIBS@

Modified: branches/ecc/configure.in
===================================================================
--- branches/ecc/configure.in	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/configure.in	2006-06-19 16:36:59 UTC (rev 1205)
@@ -97,6 +97,13 @@
   AC_MSG_ERROR([Unable to find uuid headers]))
 AC_SUBST(UUID_LIBS)
 
+ZLIB_LIBS=
+AC_CHECK_LIB(z, adler32, ZLIB_LIBS=-lz)
+if test "x$ZLIB_LIBS" != "x"; then
+  AC_CHECK_HEADER(zlib.h, :, ZLIB_LIBS=)
+fi
+AC_SUBST(ZLIB_LIBS)
+
 AC_MSG_CHECKING(for debug executables)
 AC_ARG_ENABLE(debugexe, [  --enable-debugexe=[yes/no]     Enable debug executables for library source files [default=no]],,enable_debugexe=no)
 OCFS2_DEBUG_EXE=


Property changes on: branches/ecc/extras
___________________________________________________________________
Name: svn:ignore
   - .*.sw?
find_hardlinks
find_dup_extents
find_inode_paths
set_random_bits
decode_lockres
mark_journal_dirty
encode_lockres
*.d

   + .*.sw?
find_hardlinks
find_dup_extents
find_inode_paths
set_random_bits
decode_lockres
mark_journal_dirty
encode_lockres
hamming
*.d


Modified: branches/ecc/extras/Makefile
===================================================================
--- branches/ecc/extras/Makefile	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/extras/Makefile	2006-06-19 16:36:59 UTC (rev 1205)
@@ -11,7 +11,7 @@
 
 CFLAGS = $(OPTS) $(WARNINGS) 
 
-UNINST_PROGRAMS = find_hardlinks find_dup_extents find_inode_paths set_random_bits decode_lockres encode_lockres mark_journal_dirty
+UNINST_PROGRAMS = find_hardlinks find_dup_extents find_inode_paths set_random_bits decode_lockres encode_lockres mark_journal_dirty hamming
 
 INCLUDES = -I../libocfs2/include -I$(TOPDIR)/libo2dlm/include -I$(TOPDIR)/libo2cb/include
 
@@ -28,9 +28,14 @@
 DECODE_LOCKRES_CFILES = decode_lockres.c
 ENCODE_LOCKRES_CFILES = encode_lockres.c
 MARK_JOURNAL_DIRTY_CFILES = mark_journal_dirty.c
+HAMMING_CFILES = hamming.c
 
-DIST_FILES = $(FIND_HARDLINKS_CFILES) $(FIND_DUP_EXTENTS_CFILES) $(FIND_INODE_PATHS_CFILES) $(SET_RANDOM_BITS_CFILES) $(DECODE_LOCKRES_CFILES) $(ENCODE_LOCKRES_CFILES) $(MARK_JOURNAL_DIRTY_CFILES)
+ifneq ($(ZLIB_LIBS),)
+  hamming_CFLAGS = -DHAVE_ZLIB
+endif
 
+DIST_FILES = $(FIND_HARDLINKS_CFILES) $(FIND_DUP_EXTENTS_CFILES) $(FIND_INODE_PATHS_CFILES) $(SET_RANDOM_BITS_CFILES) $(DECODE_LOCKRES_CFILES) $(ENCODE_LOCKRES_CFILES) $(MARK_JOURNAL_DIRTY_CFILES) $(HAMMING_CFILES)
+
 FIND_HARDLINKS_OBJS = $(subst .c,.o,$(FIND_HARDLINKS_CFILES))
 FIND_DUP_EXTENTS_OBJS = $(subst .c,.o,$(FIND_DUP_EXTENTS_CFILES))
 FIND_INODE_PATHS_OBJS = $(subst .c,.o,$(FIND_INODE_PATHS_CFILES))
@@ -38,6 +43,7 @@
 DECODE_LOCKRES_OBJS  = $(subst .c,.o,$(DECODE_LOCKRES_CFILES))
 ENCODE_LOCKRES_OBJS  = $(subst .c,.o,$(ENCODE_LOCKRES_CFILES))
 MARK_JOURNAL_DIRTY_OBJS = $(subst .c,.o,$(MARK_JOURNAL_DIRTY_CFILES))
+HAMMING_OBJS = $(subst .c,.o,$(HAMMING_CFILES))
 LIBOCFS2 = ../libocfs2/libocfs2.a
 EXTRAS_LIBS = $(LIBOCFS2) $(COM_ERR_LIBS)
 
@@ -62,4 +68,7 @@
 mark_journal_dirty: $(MARK_JOURNAL_DIRTY_OBJS) $(LIBOCFS2)
 	$(LINK) $(EXTRAS_LIBS)
 
+hamming: $(HAMMING_OBJS) $(LIBOCFS2)
+	$(LINK) $(EXTRAS_LIBS) $(ZLIB_LIBS)
+
 include $(TOPDIR)/Postamble.make

Added: branches/ecc/extras/hamming.c
===================================================================
--- branches/ecc/extras/hamming.c	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/extras/hamming.c	2006-06-19 16:36:59 UTC (rev 1205)
@@ -0,0 +1,214 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <inttypes.h>
+
+/* Adler32 test */
+#include <zlib.h>
+
+#include "ocfs2.h"
+
+#include "bitops.h"
+#include "blockcheck.h"
+
+
+static int fill_buf(unsigned char *data, int blocksize)
+{
+    int fd;
+    ssize_t ret;
+
+    fd = open("/dev/urandom", O_RDONLY);
+    if (fd < 0)
+    {
+        fprintf(stderr, "Unable to open\n");
+        return 1;
+    }
+
+    ret = read(fd, data, blocksize);
+    close(fd);
+    if (ret != blocksize)
+    {
+        fprintf(stderr, "short read\n");
+        return 1;
+    }
+
+    memset(data + 0xC0, 0, blocksize - 0xC0);
+
+    return 0;
+}
+
+/* So time(1) can tell us we're slow! */
+static int time_encode(unsigned char *data, int blocksize, int count)
+{
+    int i;
+    unsigned int d = blocksize * 8;
+    uint32_t parity;
+
+    for (i = 0; i < count; i++)
+        ocfs2_hamming_encode(data, d, &parity);
+
+    return 0;
+}
+
+static int time_cpy(unsigned char *data, int blocksize, int count)
+{
+    int i, j;
+    char *dest;
+
+    dest = malloc(blocksize);
+    if (!dest)
+        return 1;
+
+    for (i = 0; i < count; i++)
+        /*
+         * This is purposely inefficient - memcpy(3) is way fast
+         * ... later ... and still, way fast ...
+         */
+        for (j = 0; j < blocksize; j++)
+            dest[j] = data[j];
+
+    free(dest);
+
+    return 0;
+}
+
+static int time_crc32(unsigned char *data, int blocksize, int count)
+{
+    int i;
+    unsigned long crc_val;
+
+    for (i = 0; i < count; i++)
+    {
+#if 0  /* zlib crc32 */
+        crc_val = crc32(0L, Z_NULL, 0);
+        crc_val = crc32(crc_val, (unsigned char *)data, blocksize);
+#endif
+        crc_val = crc32_le(~0, data, blocksize);
+    }
+
+    return 0;
+}
+
+#ifdef HAVE_ZLIB
+static int time_adler32(unsigned char *data, int blocksize, int count)
+{
+    int i;
+    unsigned long adler_val;
+
+    for (i = 0; i < count; i++)
+    {
+        adler_val = adler32(0L, Z_NULL, 0);
+        adler_val = adler32(adler_val, data, blocksize);
+    }
+
+    return 0;
+}
+#endif
+
+
+static int test_buf(unsigned char *data, int blocksize)
+{
+    int i, rc = 1;
+    unsigned int d = blocksize * 8;
+    unsigned char *broken;
+    uint32_t parity, parity_broken;
+
+    ocfs2_hamming_encode(data, d, &parity);
+
+    broken = malloc(blocksize);
+    if (!broken)
+        goto out;
+
+    for (i = 0; i < d; i++) {
+        fprintf(stdout, "Testing bit %d... ", i);
+
+        memcpy(broken, data, blocksize);
+        if (ocfs2_test_bit(i, broken))
+            ocfs2_clear_bit(i, broken);
+        else
+            ocfs2_set_bit(i, broken);
+
+        /* The twiddled bit should break things */
+        if (!memcmp(data, broken, blocksize))
+        {
+            fprintf(stdout, "Failed\n");
+            fprintf(stderr, "Breaking didn't!\n");
+            goto out_free;
+        }
+
+        ocfs2_hamming_encode(broken, d, &parity_broken);
+        ocfs2_hamming_fix(broken, d, parity ^ parity_broken);
+
+        /* Now it should work */
+        if (memcmp(data, broken, blocksize))
+        {
+            fprintf(stdout, "Failed\n");
+            fprintf(stderr, "Fix didn't!\n");
+            goto out_free;
+        }
+
+        fprintf(stdout, "Pass\n");
+    }
+
+    rc = 0;
+
+out_free:
+    free(broken);
+
+out:
+    return rc;
+}
+
+
+int main(int argc, char *argv[])
+{
+    int rc = 1;
+    int blocksize = 0;
+    unsigned char *data;
+
+    if (argc < 2)
+        goto out;
+
+    blocksize = atoi(argv[1]);
+
+    data = malloc(blocksize);
+    if (!data)
+        goto out;
+
+    if (fill_buf(data, blocksize))
+        goto out_free;
+
+    if (argc < 3 || !strcmp(argv[2], "test"))
+        if (test_buf(data, blocksize))
+            goto out_free;
+
+    if (argc < 4)
+        goto out_free;
+
+    if (!strcmp(argv[2], "encode"))
+        time_encode(data, blocksize, atoi(argv[3]));
+    else if (!strcmp(argv[2], "cpy"))
+        time_cpy(data, blocksize, atoi(argv[3]));
+#ifdef HAVE_ZLIB
+    else if (!strcmp(argv[2], "adler32"))
+        time_adler32(data, blocksize, atoi(argv[3]));
+#endif
+    else if (!strcmp(argv[2], "crc32"))
+        time_crc32(data, blocksize, atoi(argv[3]));
+    else
+        goto out_free;
+
+
+    rc = 0;
+
+out_free:
+    free(data);
+
+out:
+    return rc;
+}

Modified: branches/ecc/libocfs2/Makefile
===================================================================
--- branches/ecc/libocfs2/Makefile	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/libocfs2/Makefile	2006-06-19 16:36:59 UTC (rev 1205)
@@ -46,6 +46,7 @@
 	alloc.c		\
 	bitmap.c	\
 	bitops.c	\
+	blockcheck.c	\
 	cached_inode.c	\
 	chain.c		\
 	chainalloc.c	\
@@ -85,6 +86,7 @@
 HFILES =				\
 	include/bitmap.h		\
 	include/bitops.h		\
+	include/blockcheck.h		\
 	include/byteorder.h		\
 	include/dir_iterate.h		\
 	include/dir_util.h		\

Added: branches/ecc/libocfs2/blockcheck.c
===================================================================
--- branches/ecc/libocfs2/blockcheck.c	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/libocfs2/blockcheck.c	2006-06-19 16:36:59 UTC (rev 1205)
@@ -0,0 +1,308 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * blockcheck.c
+ *
+ * Checksum and ECC codes for the OCFS2 userspace library.
+ *
+ * Copyright (C) 2006 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License, version 2,  as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ *   The 802.3 CRC32 algorithm is copied from the Linux kernel, lib/crc32.c.
+ *   Code was from the public domain, is now GPL, so no real copyright
+ *   attribution other than "The Linux Kernel".  XXX: better text, anyone?
+ */
+
+#define _XOPEN_SOURCE 600 /* Triggers magic in features.h */
+#define _LARGEFILE64_SOURCE
+
+#include <inttypes.h>
+
+#include "ocfs2.h"
+
+#include "bitops.h"
+#include "blockcheck.h"
+
+
+
+static inline unsigned int hc_hweight32(unsigned int w)
+{
+	unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+	res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+	res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+	return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+/*
+ * We use the following conventions:
+ *
+ * d = # data bits
+ * p = # parity bits
+ * c = # total code bits (d + p)
+ */
+static int calc_parity_bits(unsigned int d)
+{
+	unsigned int p;
+
+	/*
+	 * Bits required for Single Error Correction is as follows: 
+	 *
+	 * d + p + 1 <= 2^p
+	 *
+	 * We're restricting ourselves to 31 bits of parity, that should be
+	 * sufficient.
+	 */
+	for (p = 1; p < 32; p++)
+	{
+		if ((d + p + 1) <= (1 << p))
+			return p;
+	}
+
+	return 0;
+}
+
+/*
+ * Calculate the bit offset in the hamming code buffer based on the bit's
+ * offset in the data buffer.  Since the hamming code reserves all
+ * power-of-two bits for parity, the data bit number and the code bit
+ * number are offest by all the parity bits beforehand.
+ *
+ * Recall that bit numbers in hamming code are 1-based.  This function
+ * takes the 0-based data bit from the caller.
+ *
+ * An example.  Take bit 1 of the data buffer.  1 is a power of two (2^0),
+ * so it's a parity bit.  2 is a power of two (2^1), so it's a parity bit.
+ * 3 is not a power of two.  So bit 1 of the data buffer ends up as bit 3
+ * in the code buffer.
+ */
+static unsigned int calc_code_bit(unsigned int i)
+{
+	unsigned int b, p;
+
+	/*
+	 * Data bits are 0-based, but we're talking code bits, which
+	 * are 1-based.
+	 */
+	b = i + 1;
+
+	/*
+	 * For every power of two below our bit number, bump our bit.
+	 *
+	 * We compare with (b + 1) becuase we have to compare with what b
+	 * would be _if_ it were bumped up by the parity bit.  Capice?
+	 */
+	for (p = 0; (1 << p) < (b + 1); p++)
+		b++;
+
+	return b;
+}
+
+/* XXX: Not endian safe? */
+void ocfs2_hamming_encode(unsigned char *data, unsigned int d,
+			  uint32_t *parity)
+{
+	unsigned int p = calc_parity_bits(d);
+	unsigned int i, j, b;
+	unsigned int plist[p];  /* XXX: We use a simple array to avoid ugly
+	                           bitops on *parity.  Perhaps this makes us
+	                           slower? */
+
+	if (!p)
+		abort();
+
+	*parity = 0;
+	memset(plist, 0, sizeof(unsigned int) * p);
+
+	/*
+	 * b is the hamming code bit number.  Hamming code specifies a
+	 * 1-based array, but C uses 0-based.  So 'i' is for C, and 'b' is
+	 * for the algorithm.
+	 *
+	 * The i++ in the for loop is so that the start offset passed
+	 * to ocfs2_find_next_bit_set() is one greater than the previously
+	 * found bit.
+	 */
+	for (i = 0; (i = ocfs2_find_next_bit_set(data, d, i)) < d; i++)
+	{
+		
+		b = calc_code_bit(i);
+
+		for (j = 0; j < p; j++)
+		{
+			/*
+			 * Data bits in the resultant code are checked by
+			 * parity bits that are part of the bit number
+			 * representation.  Huh?
+			 *
+			 * <wikipedia href="http://en.wikipedia.org/wiki/Hamming_code">
+			 * In other words, the parity bit at position 2^k
+			 * checks bits in positions having bit k set in
+			 * their binary representation.  Conversely, for
+			 * instance, bit 13, i.e. 1101(2), is checked by
+			 * bits 1000(2) = 8, 0100(2)=4 and 0001(2) = 1.
+			 * </wikipedia>
+			 *
+			 * Note that 'k' is the _code_ bit number.  'b' in
+			 * our loop.
+			 */
+			if (b & (1 << j))
+				plist[j] ^= 1;
+		}
+	}
+
+	/* Now fill *parity */
+	for (j = 0; j < p; j++)
+		if (plist[j])
+			ocfs2_set_bit(j, parity);
+}
+
+void ocfs2_hamming_fix(unsigned char *data, unsigned int d,
+		       unsigned int fix)
+{
+	unsigned int p = calc_parity_bits(d);
+	unsigned int i, b;
+
+	if (!p)
+		abort();
+
+	/*
+	 * If the bit to fix has an hweight of 1, it's a parity bit.  One
+	 * busted parity bit is its own error.  Nothing to do here.
+	 */
+	if (hc_hweight32(fix) == 1)
+		return;
+
+	/* See hamming_encode() for a description of 'b' */
+	for (i = 0, b = 1; i < d; i++, b++)
+	{
+		/* Skip past parity bits */
+		while (hc_hweight32(b) == 1)
+			b++; 
+
+		if (b == fix)
+		{
+			if (ocfs2_test_bit(i, data))
+				ocfs2_clear_bit(i, data);
+			else
+				ocfs2_set_bit(i, data);
+			break;
+		}
+	}
+}
+
+/*
+ * table-less crc32_le() stolen from the kernel.  The kernel's slowest
+ * version :-)
+ *
+ * RFC 3385 shows that the 802.3 crc32 (this one) has the same properties
+ * and probabilities as crc32c (which iSCSI uses) for data blocks < 2^16
+ * bits.  We fit.
+ */
+
+/*
+ * There are multiple 16-bit CRC polynomials in common use, but this is
+ * *the* standard CRC-32 polynomial, first popularized by Ethernet.
+ * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
+ */
+#define CRCPOLY_LE 0xedb88320
+
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *        other uses, or the previous crc32 value if computing incrementally.
+ * @p   - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ * 
+ */
+uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len)
+{
+	int i;
+	while (len--) {
+		crc ^= *p++;
+		for (i = 0; i < 8; i++)
+			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+	}
+	return crc;
+}
+
+/*
+ * This function generates check information for a block.
+ * data is the block to be checked.  bc is a pointer to the
+ * ocfs2_block_check structure describing the crc32 and the ecc.
+ *
+ * bc should be a pointer inside data, as the function will
+ * take care of zeroing it before calculating the check information.  If
+ * bc does not point inside data, the caller must make sure any inline
+ * ocfs2_block_check structures are zeroed.
+ */
+void ocfs2_block_check_compute(ocfs2_filesys *fs, void *data,
+			       struct ocfs2_block_check *bc)
+{
+	uint32_t crc, ecc;
+
+	/* XXX: Caller has already swapped the inode, so this needs
+	 * endian fixup */
+	if (!OCFS2_HAS_INCOMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super),
+					OCFS2_FEATURE_INCOMPAT_BLOCK_CHECK))
+		return;
+
+	memset(bc, 0, sizeof(struct ocfs2_block_check));
+
+	/* XXX: I think crc32_le() might need bitreverse() */
+	crc = crc32_le(~0, data, fs->fs_blocksize);
+	ocfs2_hamming_encode(data, fs->fs_blocksize, &ecc);
+
+	bc->bc_crc32e = crc;
+	bc->bc_ecc = (uint16_t)ecc;  /* We know it's max 16 bits */
+}
+
+/*
+ * This function validates existing check information.  Like _compute,
+ * the function will take care of zeroing bc before calculating check codes.
+ * If bc is not a pointer inside data, the caller must have zeroed any
+ * inline ocfs2_block_check structures.
+ */
+errcode_t ocfs2_block_check_validate(ocfs2_filesys *fs, void *data,
+				     struct ocfs2_block_check *bc)
+{
+	struct ocfs2_block_check check = *bc;
+	uint32_t crc, ecc;
+
+	/* XXX: Caller has already swapped the inode, so this needs
+	 * endian fixup */
+	if (!OCFS2_HAS_INCOMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super),
+					OCFS2_FEATURE_INCOMPAT_BLOCK_CHECK))
+		return 0;
+
+	memset(bc, 0, sizeof(struct ocfs2_block_check));
+
+	/* Fast path - if the crc32 validates, we're good to go */
+	crc = crc32_le(~0, data, fs->fs_blocksize);
+	if (crc == check.bc_crc32e)
+		return 0;
+
+	/* Ok, try ECC fixups */
+	ocfs2_hamming_encode(data, fs->fs_blocksize, &ecc);
+	ocfs2_hamming_fix(data, fs->fs_blocksize, ecc ^ check.bc_ecc);
+
+	/* And check the crc32 again */
+	crc = crc32_le(~0, data, fs->fs_blocksize);
+	if (crc == check.bc_crc32e)
+		return 0;
+
+	return OCFS2_ET_IO;
+}

Modified: branches/ecc/libocfs2/chain.c
===================================================================
--- branches/ecc/libocfs2/chain.c	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/libocfs2/chain.c	2006-06-19 16:36:59 UTC (rev 1205)
@@ -28,6 +28,7 @@
 #include <string.h>
 
 #include "ocfs2.h"
+#include "blockcheck.h"
 
 void ocfs2_swap_group_desc(struct ocfs2_group_desc *gd)
 {
@@ -70,9 +71,14 @@
 		   strlen(OCFS2_GROUP_DESC_SIGNATURE)))
 		goto out;
 
+	ret = ocfs2_block_check_validate(fs, gd, &gd->bg_check);
+	if (ret)
+		goto out;
+
 	memcpy(gd_buf, blk, fs->fs_blocksize);
 
 	gd = (struct ocfs2_group_desc *)gd_buf;
+	
 	ocfs2_swap_group_desc(gd);
 
 	ret = 0;
@@ -105,6 +111,7 @@
 	gd = (struct ocfs2_group_desc *)blk;
 	ocfs2_swap_group_desc(gd);
 
+	ocfs2_block_check_compute(fs, gd, &gd->bg_check);
 	ret = io_write_block(fs->fs_io, blkno, 1, blk);
 	if (ret)
 		goto out;

Modified: branches/ecc/libocfs2/dirblock.c
===================================================================
--- branches/ecc/libocfs2/dirblock.c	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/libocfs2/dirblock.c	2006-06-19 16:36:59 UTC (rev 1205)
@@ -31,6 +31,7 @@
 #include <string.h>
 
 #include "ocfs2.h"
+#include "blockcheck.h"
 
 static void ocfs2_swap_dir_entry(struct ocfs2_dir_entry *dirent)
 {
@@ -87,11 +88,17 @@
                                void *buf)
 {
 	errcode_t	retval;
+	struct ocfs2_dir_check_entry *dc;
 
  	retval = io_read_block(fs->fs_io, block, 1, buf);
 	if (retval)
 		return retval;
 
+	dc = (struct ocfs2_dir_check_entry *)buf;
+	retval = ocfs2_block_check_validate(fs, buf, &dc->check);
+	if (retval)
+		return retval;
+
 	return ocfs2_swap_dir_entries_to_cpu(buf, fs->fs_blocksize);
 }
 
@@ -100,6 +107,7 @@
 {
 	errcode_t	retval;
 	char		*buf = NULL;
+	struct ocfs2_dir_check_entry *dc;
 
 	retval = ocfs2_malloc_block(fs->fs_io, &buf);
 	if (retval)
@@ -111,6 +119,8 @@
 	if (retval)
 		goto out;
 	
+	dc = (struct ocfs2_dir_check_entry *) buf;
+	ocfs2_block_check_compute(fs, buf, &dc->check);
  	retval = io_write_block(fs->fs_io, block, 1, buf);
 out:
 	ocfs2_free(&buf);

Modified: branches/ecc/libocfs2/extents.c
===================================================================
--- branches/ecc/libocfs2/extents.c	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/libocfs2/extents.c	2006-06-19 16:36:59 UTC (rev 1205)
@@ -33,6 +33,7 @@
 #include <inttypes.h>
 
 #include "ocfs2.h"
+#include "blockcheck.h"
 
 static void ocfs2_swap_extent_list_primary(struct ocfs2_extent_list *el)
 {
@@ -126,9 +127,16 @@
 		goto out;
 	}
 
+	/* XXX: fsck seems to expect all extent block corruption to be
+	 * ignored, so let's ask zach what to do here */
+	ret = ocfs2_block_check_validate(fs, eb, &eb->h_check);
+	if (ret)
+		goto out;
+
 	memcpy(eb_buf, blk, fs->fs_blocksize);
 
 	eb = (struct ocfs2_extent_block *) eb_buf;
+
 	ocfs2_swap_extent_block_to_cpu(eb);
 
 out:
@@ -175,6 +183,7 @@
 	eb = (struct ocfs2_extent_block *) blk;
 	ocfs2_swap_extent_block_from_cpu(eb);
 
+	ocfs2_block_check_compute(fs, eb, &eb->h_check);
 	ret = io_write_block(fs->fs_io, blkno, 1, blk);
 	if (ret)
 		goto out;

Added: branches/ecc/libocfs2/include/blockcheck.h
===================================================================
--- branches/ecc/libocfs2/include/blockcheck.h	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/libocfs2/include/blockcheck.h	2006-06-19 16:36:59 UTC (rev 1205)
@@ -0,0 +1,41 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * blockcheck.h
+ *
+ * Checksum and ECC codes for the OCFS2 userspace library.
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License, version 2,  as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * Authors: Joel Becker
+ */
+
+#ifndef _BLOCKCHECK_H
+#define _BLOCKCHECK_H
+
+extern void ocfs2_hamming_encode(unsigned char *data, unsigned int d,
+				 uint32_t *parity);
+extern void ocfs2_hamming_fix(unsigned char *data, unsigned int d,
+			      unsigned int fix);
+extern uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len);
+extern void ocfs2_block_check_compute(ocfs2_filesys *fs,
+				      void *data,
+				      struct ocfs2_block_check *bc);
+extern errcode_t ocfs2_block_check_validate(ocfs2_filesys *fs,
+					    void *data,
+					    struct ocfs2_block_check *bc);
+#endif

Modified: branches/ecc/libocfs2/include/ocfs2.h
===================================================================
--- branches/ecc/libocfs2/include/ocfs2.h	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/libocfs2/include/ocfs2.h	2006-06-19 16:36:59 UTC (rev 1205)
@@ -48,6 +48,7 @@
 
 #include "byteorder.h"
 
+#define OCFS2_SB(sb) (sb)
 
 #if OCFS2_FLAT_INCLUDES
 #include "o2dlm.h"

Modified: branches/ecc/libocfs2/include/ocfs2_fs.h
===================================================================
--- branches/ecc/libocfs2/include/ocfs2_fs.h	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/libocfs2/include/ocfs2_fs.h	2006-06-19 16:36:59 UTC (rev 1205)
@@ -85,9 +85,8 @@
 #define OCFS2_CLEAR_INCOMPAT_FEATURE(sb,mask)			\
 	OCFS2_SB(sb)->s_feature_incompat &= ~(mask)
 
-#define OCFS2_FEATURE_COMPAT_SUPP	0
-#define OCFS2_FEATURE_INCOMPAT_SUPP	0
-#define OCFS2_FEATURE_RO_COMPAT_SUPP	0
+/* 802.3 crc32 + ECC */
+#define OCFS2_FEATURE_INCOMPAT_BLOCK_CHECK	0x0001
 
 /*
  * Heartbeat-only devices are missing journals and other files.  The
@@ -97,6 +96,11 @@
 #define OCFS2_FEATURE_INCOMPAT_HEARTBEAT_DEV	0x0002
 
 
+#define OCFS2_FEATURE_COMPAT_SUPP	0
+#define OCFS2_FEATURE_INCOMPAT_SUPP	(OCFS2_FEATURE_INCOMPAT_BLOCK_CHECK)
+#define OCFS2_FEATURE_RO_COMPAT_SUPP	0
+
+
 /*
  * Flags on ocfs2_dinode.i_flags
  */
@@ -234,6 +238,21 @@
 #define OCFS2_RAW_SB(dinode)		(&((dinode)->id2.i_super))
 
 /*
+ * Metadata block check structure.  If OCFS2_FEATURE_INCOMPAT_BLOCK_CHECK
+ * is not set, it is all zeros.
+ */
+struct ocfs2_block_check {
+/*00*/	__le32 bc_crc32e;	/* 802.3 Ethernet II CRC32 */
+	__le16 bc_ecc;		/* Single-error-correction parity vector.
+				   This is a simple Hamming code dependant
+				   on the blocksize.  OCFS2's maximum 
+				   blocksize, 4K, requires 16 parity bits,
+				   so we fit in __le16. */
+	__le16 bc_reserved1;
+/*08*/
+};
+
+/*
  * On disk extent record for OCFS2
  * It describes a range of clusters on disk.
  */
@@ -245,14 +264,16 @@
 };
 
 struct ocfs2_chain_rec {
-	__le32 c_free;	/* Number of free bits in this chain. */
+/*00*/	__le32 c_free;	/* Number of free bits in this chain. */
 	__le32 c_total;	/* Number of total bits in this chain */
 	__le64 c_blkno;	/* Physical disk offset (blocks) of 1st group */
+/*10*/
 };
 
 struct ocfs2_truncate_rec {
-	__le32 t_start;		/* 1st cluster in this log */
+/*00*/	__le32 t_start;		/* 1st cluster in this log */
 	__le32 t_clusters;	/* Number of total clusters covered */
+/*08*/
 };
 
 /*
@@ -306,14 +327,14 @@
 struct ocfs2_extent_block
 {
 /*00*/	__u8 h_signature[8];		/* Signature for verification */
-	__le64 h_reserved1;
+	struct ocfs2_block_check h_check;	/* Error checking */
 /*10*/	__le16 h_suballoc_slot;		/* Slot suballocator this
 					   extent_header belongs to */
 	__le16 h_suballoc_bit;		/* Bit offset in suballocator
 					   block group */
 	__le32 h_fs_generation;		/* Must match super block */
 	__le64 h_blkno;			/* Offset on disk, in blocks */
-/*20*/	__le64 h_reserved3;
+/*20*/	__le64 h_reserved1;
 	__le64 h_next_leaf_blk;		/* Offset on disk, in blocks,
 					   of next leaf header pointing
 					   to data */
@@ -380,7 +401,7 @@
 					   belongs to */
 	__le16 i_suballoc_bit;		/* Bit offset in suballocator
 					   block group */
-/*10*/	__le32 i_reserved0;
+/*10*/	__le32 i_reserved1;
 	__le32 i_clusters;		/* Cluster count */
 	__le32 i_uid;			/* Owner UID */
 	__le32 i_gid;			/* Owning GID */
@@ -399,7 +420,8 @@
 	__le32 i_atime_nsec;
 	__le32 i_ctime_nsec;
 	__le32 i_mtime_nsec;
-/*70*/	__le64 i_reserved1[9];
+	struct ocfs2_block_check i_check;	/* Error checking */
+/*70*/	__le64 i_reserved2[8];
 /*B8*/	union {
 		__le64 i_pad1;		/* Generic way to refer to this
 					   64bit union */
@@ -444,6 +466,22 @@
 } __attribute__ ((packed));
 
 /*
+ * Filesystems with OCFS2_FEATURE_INCOMPAT_BLOCK_CHECK enabled will
+ * have this entry as the first part of each dirblock, except the very first
+ * dirblock, where it follows '.' and '..'.
+ */
+struct ocfs2_dir_check_entry {
+/*00*/	__le64	inode;
+	__le16	rec_len;
+	__u8	name_len;
+	__u8	file_type;
+	__le32	reserved1;
+/*10*/	struct ocfs2_block_check check;
+/*18*/
+/* Actual on-disk length specified by rec_len, but it will always be 0x18 */
+};
+
+/*
  * On disk allocator group structure for OCFS2
  */
 struct ocfs2_group_desc
@@ -462,8 +500,10 @@
 /*20*/	__le64   bg_parent_dinode;       /* dinode which owns me, in
 					   blocks */
 	__le64   bg_blkno;               /* Offset on disk, in blocks */
-/*30*/	__le64   bg_reserved2[2];
+/*30*/	struct ocfs2_block_check bg_check;	/* Error checking */
+	__le64   bg_reserved2;
 /*40*/	__u8    bg_bitmap[0];
+/* Actual on-disk length is one block */
 };
 
 #ifdef __KERNEL__

Modified: branches/ecc/libocfs2/inode.c
===================================================================
--- branches/ecc/libocfs2/inode.c	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/libocfs2/inode.c	2006-06-19 16:36:59 UTC (rev 1205)
@@ -32,6 +32,7 @@
 #include <inttypes.h>
 
 #include "ocfs2.h"
+#include "blockcheck.h"
 
 
 errcode_t ocfs2_check_directory(ocfs2_filesys *fs, uint64_t dir)
@@ -234,6 +235,11 @@
 		   strlen(OCFS2_INODE_SIGNATURE)))
 		goto out;
 
+	/* XXX: Someone tell me if I've got the endianess of this right */
+	ret = ocfs2_block_check_validate(fs, di, &di->i_check);
+	if (ret)
+		goto out;  /* XXX: Should we change EIO to a specific et? */
+
 	memcpy(inode_buf, blk, fs->fs_blocksize);
 
 	di = (struct ocfs2_dinode *) inode_buf;
@@ -269,6 +275,7 @@
 	di = (struct ocfs2_dinode *)blk;
 	ocfs2_swap_inode_from_cpu(di);
 
+	ocfs2_block_check_compute(fs, di, &di->i_check);
 	ret = io_write_block(fs->fs_io, blkno, 1, blk);
 	if (ret)
 		goto out;

Modified: branches/ecc/libocfs2/newdir.c
===================================================================
--- branches/ecc/libocfs2/newdir.c	2006-06-19 16:27:35 UTC (rev 1204)
+++ branches/ecc/libocfs2/newdir.c	2006-06-19 16:36:59 UTC (rev 1205)
@@ -43,6 +43,7 @@
 			      uint64_t parent_ino, char **block)
 {
 	struct ocfs2_dir_entry 	*dir;
+	struct ocfs2_dir_check_entry *dc;
 	errcode_t		ret;
 	char			*buf;
 
@@ -55,6 +56,14 @@
 	dir = (struct ocfs2_dir_entry *) buf;
 	dir->rec_len = fs->fs_blocksize;
 
+	if (OCFS2_HAS_INCOMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super),
+				       OCFS2_FEATURE_INCOMPAT_BLOCK_CHECK)) {
+		dc = (struct ocfs2_dir_check_entry *)dir;
+		memset(dc, 0, sizeof(struct ocfs2_dir_check_entry));
+		dc->rec_len = OCFS2_DIR_REC_LEN(sizeof(struct ocfs2_block_check));
+		dir = (struct ocfs2_dir_entry *) (((char *)dc) + dc->rec_len);
+	}
+
 	if (dir_ino) {
 		/*
 		 * Set up entry for '.'
@@ -68,9 +77,9 @@
 		/*
 		 * Set up entry for '..'
 		 */
-		dir = (struct ocfs2_dir_entry *) (buf + dir->rec_len);
+		dir = (struct ocfs2_dir_entry *) (((char *)dir) + dir->rec_len);
 		dir->inode = parent_ino;
-		dir->rec_len = fs->fs_blocksize - OCFS2_DIR_REC_LEN(1);
+		dir->rec_len = fs->fs_blocksize - (buf - (char *)dir);
 		dir->name_len = 2;
 		dir->file_type = OCFS2_FT_DIR;
 		dir->name[0] = '.';




More information about the Ocfs2-tools-commits mailing list