[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