diff mbox

[RFC] Btrfs-progs: support sha256 checksum algorithm

Message ID 1416806586-18050-2-git-send-email-bo.li.liu@oracle.com (mailing list archive)
State Not Applicable
Headers show

Commit Message

Liu Bo Nov. 24, 2014, 5:23 a.m. UTC
This is the progs side patch to support sha256.

Sha256 can be seleted on mkfs stage, "mkfs.btrfs -C 256 /device"

Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
---
 Makefile           |   6 +-
 btrfs-convert.c    |  24 +++--
 btrfs-find-root.c  |   6 +-
 btrfs-image.c      |  35 ++++---
 btrfs-show-super.c |   9 +-
 chunk-recover.c    |  22 ++--
 cmds-check.c       |  17 ++--
 ctree.h            |   4 +-
 disk-io.c          |  32 ++----
 file-item.c        |  13 +--
 free-space-cache.c |   9 +-
 hash.c             |  32 ++++++
 hash.h             |   3 +
 kerncompat.h       |  14 +++
 mkfs.c             |  20 +++-
 sha256.c           | 290 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 sha256.h           |  42 ++++++++
 super-recover.c    |  11 +-
 utils.c            |  30 ++++--
 utils.h            |   3 +-
 20 files changed, 514 insertions(+), 108 deletions(-)
 create mode 100644 hash.c
 create mode 100644 sha256.c
 create mode 100644 sha256.h
diff mbox

Patch

diff --git a/Makefile b/Makefile
index 4cae30c..4b1cf1c 100644
--- a/Makefile
+++ b/Makefile
@@ -17,10 +17,10 @@  cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \
 	       cmds-restore.o cmds-rescue.o chunk-recover.o super-recover.o \
 	       cmds-property.o
 libbtrfs_objects = send-stream.o send-utils.o rbtree.o btrfs-list.o crc32c.o \
-		   uuid-tree.o utils-lib.o rbtree-utils.o
+		   uuid-tree.o utils-lib.o rbtree-utils.o sha256.o hash.o
 libbtrfs_headers = send-stream.h send-utils.h send.h rbtree.h btrfs-list.h \
-	       crc32c.h list.h kerncompat.h radix-tree.h extent-cache.h \
-	       extent_io.h ioctl.h ctree.h btrfsck.h version.h
+	       crc32c.h sha256.h hash.h list.h kerncompat.h radix-tree.h \
+	       extent-cache.h extent_io.h ioctl.h ctree.h btrfsck.h version.h
 TESTS = fsck-tests.sh convert-tests.sh
 
 INSTALL = install
diff --git a/btrfs-convert.c b/btrfs-convert.c
index a544fc6..fba72b8 100644
--- a/btrfs-convert.c
+++ b/btrfs-convert.c
@@ -36,7 +36,7 @@ 
 #include "disk-io.h"
 #include "volumes.h"
 #include "transaction.h"
-#include "crc32c.h"
+#include "hash.h"
 #include "utils.h"
 #include <ext2fs/ext2_fs.h>
 #include <ext2fs/ext2fs.h>
@@ -2197,7 +2197,7 @@  err:
 }
 
 static int do_convert(const char *devname, int datacsum, int packing, int noxattr,
-	       int copylabel, const char *fslabel)
+	       int copylabel, const char *fslabel, int csum_size)
 {
 	int i, ret;
 	int fd = -1;
@@ -2241,7 +2241,7 @@  static int do_convert(const char *devname, int datacsum, int packing, int noxatt
 	}
 	ret = make_btrfs(fd, devname, ext2_fs->super->s_volume_name,
 			 NULL, blocks, total_bytes, blocksize, blocksize,
-			 blocksize, blocksize, 0);
+			 blocksize, blocksize, 0, csum_size);
 	if (ret) {
 		fprintf(stderr, "unable to create initial ctree: %s\n",
 			strerror(-ret));
@@ -2696,13 +2696,14 @@  fail:
 
 static void print_usage(void)
 {
-	printf("usage: btrfs-convert [-d] [-i] [-n] [-r] [-l label] [-L] device\n");
+	printf("usage: btrfs-convert [-d] [-i] [-n] [-r] [-l label] [-L] [-C csum_size] device\n");
 	printf("\t-d           disable data checksum\n");
 	printf("\t-i           ignore xattrs and ACLs\n");
 	printf("\t-n           disable packing of small files\n");
 	printf("\t-r           roll back to ext2fs\n");
 	printf("\t-l LABEL     set filesystem label\n");
 	printf("\t-L           use label from converted fs\n");
+	printf("\t-C           specify the filesystem checksum size, only 32 and 256 are supported\n");
 }
 
 int main(int argc, char *argv[])
@@ -2716,9 +2717,10 @@  int main(int argc, char *argv[])
 	int usage_error = 0;
 	char *file;
 	char *fslabel = NULL;
+	int csum_size = BTRFS_CRC32_SIZE;
 
 	while(1) {
-		int c = getopt(argc, argv, "dinrl:L");
+		int c = getopt(argc, argv, "dinrl:LC:");
 		if (c < 0)
 			break;
 		switch(c) {
@@ -2747,6 +2749,16 @@  int main(int argc, char *argv[])
 			case 'L':
 				copylabel = 1;
 				break;
+			case 'C':
+				csum_size = parse_size(optarg);
+
+				if (csum_size != (BTRFS_CRC32_SIZE << 3) &&
+				    csum_size != (BTRFS_SHA256_SIZE << 3)) {
+					print_usage();
+					return 1;
+				}
+				csum_size = csum_size >> 3;
+				break;
 			default:
 				print_usage();
 				return 1;
@@ -2784,7 +2796,7 @@  int main(int argc, char *argv[])
 	if (rollback) {
 		ret = do_rollback(file);
 	} else {
-		ret = do_convert(file, datacsum, packing, noxattr, copylabel, fslabel);
+		ret = do_convert(file, datacsum, packing, noxattr, copylabel, fslabel, csum_size);
 	}
 	if (ret)
 		return 1;
diff --git a/btrfs-find-root.c b/btrfs-find-root.c
index 6fa61cc..9f7ec84 100644
--- a/btrfs-find-root.c
+++ b/btrfs-find-root.c
@@ -33,7 +33,7 @@ 
 #include "version.h"
 #include "volumes.h"
 #include "utils.h"
-#include "crc32c.h"
+#include "hash.h"
 
 static u16 csum_size = 0;
 static u64 search_objectid = BTRFS_ROOT_TREE_OBJECTID;
@@ -49,7 +49,6 @@  static void usage(void)
 static int csum_block(void *buf, u32 len)
 {
 	char *result;
-	u32 crc = ~(u32)0;
 	int ret = 0;
 
 	result = malloc(csum_size * sizeof(char));
@@ -59,8 +58,7 @@  static int csum_block(void *buf, u32 len)
 	}
 
 	len -= BTRFS_CSUM_SIZE;
-	crc = crc32c(crc, buf + BTRFS_CSUM_SIZE, len);
-	btrfs_csum_final(crc, result);
+	btrfs_csum(buf + BTRFS_CSUM_SIZE, len, (u8 *)result, csum_size);
 
 	if (memcmp(buf, result, csum_size))
 		ret = 1;
diff --git a/btrfs-image.c b/btrfs-image.c
index cb17f16..74e31d8 100644
--- a/btrfs-image.c
+++ b/btrfs-image.c
@@ -28,7 +28,7 @@ 
 #include <dirent.h>
 #include <zlib.h>
 #include "kerncompat.h"
-#include "crc32c.h"
+#include "hash.h"
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -103,6 +103,7 @@  struct metadump_struct {
 	u64 pending_start;
 	u64 pending_size;
 
+	int csum_size;
 	int compress_level;
 	int done;
 	int data;
@@ -131,6 +132,7 @@  struct mdrestore_struct {
 	struct list_head list;
 	size_t num_items;
 	u32 leafsize;
+	u16 csum_size;
 	u64 devid;
 	u8 uuid[BTRFS_UUID_SIZE];
 	u8 fsid[BTRFS_FSID_SIZE];
@@ -149,13 +151,13 @@  static int search_for_chunk_blocks(struct mdrestore_struct *mdres,
 				   u64 search, u64 cluster_bytenr);
 static struct extent_buffer *alloc_dummy_eb(u64 bytenr, u32 size);
 
-static void csum_block(u8 *buf, size_t len)
+static void csum_block(u8 *buf, size_t len, int csum_size)
 {
-	char result[BTRFS_CRC32_SIZE];
-	u32 crc = ~(u32)0;
-	crc = crc32c(crc, buf + BTRFS_CSUM_SIZE, len - BTRFS_CSUM_SIZE);
-	btrfs_csum_final(crc, result);
-	memcpy(buf, result, BTRFS_CRC32_SIZE);
+	char result[BTRFS_CSUM_SIZE];
+
+	btrfs_csum(buf + BTRFS_CSUM_SIZE, len - BTRFS_CSUM_SIZE,
+		   (u8 *)result, csum_size);
+	memcpy(buf, result, BTRFS_CSUM_SIZE);
 }
 
 static int has_name(struct btrfs_key *key)
@@ -577,7 +579,7 @@  static void copy_buffer(struct metadump_struct *md, u8 *dst,
 			sizeof(struct btrfs_key_ptr) * nritems;
 		memset(dst + size, 0, src->len - size);
 	}
-	csum_block(dst, src->len);
+	csum_block(dst, src->len, md->csum_size);
 }
 
 static void *dump_worker(void *data)
@@ -687,6 +689,7 @@  static int metadump_init(struct metadump_struct *md, struct btrfs_root *root,
 	INIT_LIST_HEAD(&md->ordered);
 	md->root = root;
 	md->out = out;
+	md->csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
 	md->pending_start = (u64)-1;
 	md->compress_level = compress_level;
 	md->cluster = calloc(1, BLOCK_SIZE);
@@ -1344,6 +1347,7 @@  static void update_super_old(u8 *buffer)
 	struct btrfs_disk_key *key;
 	u32 sectorsize = btrfs_super_sectorsize(super);
 	u64 flags = btrfs_super_flags(super);
+	u16 csum_size = btrfs_super_csum_size(super);
 
 	flags |= BTRFS_SUPER_FLAG_METADUMP;
 	btrfs_set_super_flags(super, flags);
@@ -1369,7 +1373,7 @@  static void update_super_old(u8 *buffer)
 	btrfs_set_stack_stripe_offset(&chunk->stripe, 0);
 	memcpy(chunk->stripe.dev_uuid, super->dev_item.uuid, BTRFS_UUID_SIZE);
 	btrfs_set_super_sys_array_size(super, sizeof(*key) + sizeof(*chunk));
-	csum_block(buffer, BTRFS_SUPER_INFO_SIZE);
+	csum_block(buffer, BTRFS_SUPER_INFO_SIZE, csum_size);
 }
 
 static int update_super(u8 *buffer)
@@ -1383,6 +1387,7 @@  static int update_super(u8 *buffer)
 	u32 cur = 0;
 	u8 *ptr, *write_ptr;
 	int old_num_stripes;
+	u16 csum_size = btrfs_super_csum_size(super);
 
 	write_ptr = ptr = super->sys_chunk_array;
 	array_size = btrfs_super_sys_array_size(super);
@@ -1423,7 +1428,7 @@  static int update_super(u8 *buffer)
 	}
 
 	btrfs_set_super_sys_array_size(super, new_array_size);
-	csum_block(buffer, BTRFS_SUPER_INFO_SIZE);
+	csum_block(buffer, BTRFS_SUPER_INFO_SIZE, csum_size);
 
 	return 0;
 }
@@ -1540,7 +1545,7 @@  static int fixup_chunk_tree_block(struct mdrestore_struct *mdres,
 					    sizeof(chunk));
 		}
 		memcpy(buffer, eb->data, eb->len);
-		csum_block(buffer, eb->len);
+		csum_block(buffer, eb->len, mdres->csum_size);
 next:
 		size_left -= mdres->leafsize;
 		buffer += mdres->leafsize;
@@ -1559,6 +1564,7 @@  static void write_backup_supers(int fd, u8 *buf)
 	u64 bytenr;
 	int i;
 	int ret;
+	u16 csum_size = btrfs_super_csum_size(super);
 
 	if (fstat(fd, &st)) {
 		fprintf(stderr, "Couldn't stat restore point, won't be able "
@@ -1573,7 +1579,7 @@  static void write_backup_supers(int fd, u8 *buf)
 		if (bytenr + BTRFS_SUPER_INFO_SIZE > size)
 			break;
 		btrfs_set_super_bytenr(super, bytenr);
-		csum_block(buf, BTRFS_SUPER_INFO_SIZE);
+		csum_block(buf, BTRFS_SUPER_INFO_SIZE, csum_size);
 		ret = pwrite64(fd, buf, BTRFS_SUPER_INFO_SIZE, bytenr);
 		if (ret < BTRFS_SUPER_INFO_SIZE) {
 			if (ret < 0)
@@ -1831,6 +1837,7 @@  static int fill_mdres_info(struct mdrestore_struct *mdres,
 
 	super = (struct btrfs_super_block *)outbuf;
 	mdres->leafsize = btrfs_super_leafsize(super);
+	mdres->csum_size = btrfs_super_csum_size(super);
 	memcpy(mdres->fsid, super->fsid, BTRFS_FSID_SIZE);
 	memcpy(mdres->uuid, super->dev_item.uuid,
 		       BTRFS_UUID_SIZE);
@@ -2240,6 +2247,7 @@  static int build_chunk_tree(struct mdrestore_struct *mdres,
 	super = (struct btrfs_super_block *)buffer;
 	chunk_root_bytenr = btrfs_super_chunk_root(super);
 	mdres->leafsize = btrfs_super_leafsize(super);
+	mdres->csum_size = btrfs_super_csum_size(super);
 	memcpy(mdres->fsid, super->fsid, BTRFS_FSID_SIZE);
 	memcpy(mdres->uuid, super->dev_item.uuid,
 		       BTRFS_UUID_SIZE);
@@ -2440,7 +2448,8 @@  static int update_disk_super_on_device(struct btrfs_fs_info *info,
 	btrfs_set_stack_device_sector_size(dev_item, sector_size);
 	memcpy(dev_item->uuid, dev_uuid, BTRFS_UUID_SIZE);
 	memcpy(dev_item->fsid, fs_uuid, BTRFS_UUID_SIZE);
-	csum_block((u8 *)buf, BTRFS_SUPER_INFO_SIZE);
+	csum_block((u8 *)buf, BTRFS_SUPER_INFO_SIZE,
+		   btrfs_super_csum_size(info->super_copy));
 
 	ret = pwrite64(fp, buf, BTRFS_SUPER_INFO_SIZE, BTRFS_SUPER_INFO_OFFSET);
 	if (ret != BTRFS_SUPER_INFO_SIZE) {
diff --git a/btrfs-show-super.c b/btrfs-show-super.c
index 2b48f44..b3e22cc 100644
--- a/btrfs-show-super.c
+++ b/btrfs-show-super.c
@@ -35,7 +35,7 @@ 
 #include "list.h"
 #include "version.h"
 #include "utils.h"
-#include "crc32c.h"
+#include "hash.h"
 
 static void print_usage(void);
 static void dump_superblock(struct btrfs_super_block *sb, int full);
@@ -170,11 +170,10 @@  static int load_and_dump_sb(char *filename, int fd, u64 sb_bytenr, int full,
 static int check_csum_sblock(void *sb, int csum_size)
 {
 	char result[BTRFS_CSUM_SIZE];
-	u32 crc = ~(u32)0;
 
-	crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE,
-				crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
-	btrfs_csum_final(crc, result);
+	btrfs_csum((char *)sb + BTRFS_CSUM_SIZE,
+		   BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE,
+		   (u8 *)result, csum_size);
 
 	return !memcmp(sb, &result, csum_size);
 }
diff --git a/chunk-recover.c b/chunk-recover.c
index 6f43066..7e491f2 100644
--- a/chunk-recover.c
+++ b/chunk-recover.c
@@ -36,7 +36,7 @@ 
 #include "disk-io.h"
 #include "volumes.h"
 #include "transaction.h"
-#include "crc32c.h"
+#include "hash.h"
 #include "utils.h"
 #include "version.h"
 #include "btrfsck.h"
@@ -1647,7 +1647,7 @@  static int next_csum(struct btrfs_root *root,
 		     struct btrfs_path *path,
 		     int *slot,
 		     u64 *csum_offset,
-		     u32 *tree_csum,
+		     u8 *tree_csum,
 		     u64 end,
 		     struct btrfs_key *key)
 {
@@ -1711,11 +1711,13 @@  static u64 calc_data_offset(struct btrfs_key *key,
 	return dev_offset + data_offset;
 }
 
-static int check_one_csum(int fd, u64 start, u32 len, u32 tree_csum)
+static int check_one_csum(struct btrfs_root *root, int fd, u64 start, u32 len,
+			  u8 *tree_csum)
 {
 	char *data;
 	int ret = 0;
-	u32 csum_result = ~(u32)0;
+	u8 csum_result[BTRFS_CSUM_SIZE];
+	u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
 
 	data = malloc(len);
 	if (!data)
@@ -1726,9 +1728,9 @@  static int check_one_csum(int fd, u64 start, u32 len, u32 tree_csum)
 		goto out;
 	}
 	ret = 0;
-	csum_result = btrfs_csum_data(NULL, data, csum_result, len);
-	btrfs_csum_final(csum_result, (char *)&csum_result);
-	if (csum_result != tree_csum)
+
+	btrfs_csum(data, len, csum_result, csum_size);
+	if (memcmp(csum_result, tree_csum, csum_size))
 		ret = 1;
 out:
 	free(data);
@@ -1825,7 +1827,7 @@  static int rebuild_raid_data_chunk_stripes(struct recover_control *rc,
 	u64 csum_offset = 0;
 	u64 data_offset;
 	u32 blocksize = root->sectorsize;
-	u32 tree_csum;
+	u8 tree_csum[BTRFS_CSUM_SIZE];
 	int index = 0;
 	int num_unordered = 0;
 	LIST_HEAD(unordered);
@@ -1898,7 +1900,7 @@  again:
 			goto out;
 	}
 next_csum:
-	ret = next_csum(root, &leaf, &path, &slot, &csum_offset, &tree_csum,
+	ret = next_csum(root, &leaf, &path, &slot, &csum_offset, tree_csum,
 			end, &key);
 	if (ret < 0) {
 		fprintf(stderr, "Fetch csum failed\n");
@@ -1922,7 +1924,7 @@  next_csum:
 		BUG_ON(btrfs_find_device_by_devid(rc->fs_devices,
 						  devext->objectid, 1));
 
-		ret = check_one_csum(dev->fd, data_offset, blocksize,
+		ret = check_one_csum(root, dev->fd, data_offset, blocksize,
 				     tree_csum);
 		if (ret < 0)
 			goto fail_out;
diff --git a/cmds-check.c b/cmds-check.c
index 389674f..2f05cff 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -42,6 +42,7 @@ 
 #include "rbtree-utils.h"
 #include "backref.h"
 #include "ulist.h"
+#include "hash.h"
 
 static u64 bytes_used = 0;
 static u64 total_csum_bytes = 0;
@@ -4301,8 +4302,8 @@  static int check_extent_csums(struct btrfs_root *root, u64 bytenr,
 	u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
 	char *data;
 	unsigned long csum_offset;
-	u32 csum;
-	u32 csum_expected;
+	u8 csum[BTRFS_CSUM_SIZE];
+	u8 csum_expected[BTRFS_CSUM_SIZE];
 	u64 read_len;
 	u64 data_checked = 0;
 	u64 tmp;
@@ -4329,22 +4330,18 @@  again:
 		data_checked = 0;
 		/* verify every 4k data's checksum */
 		while (data_checked < read_len) {
-			csum = ~(u32)0;
 			tmp = offset + data_checked;
 
-			csum = btrfs_csum_data(NULL, (char *)data + tmp,
-					       csum, root->sectorsize);
-			btrfs_csum_final(csum, (char *)&csum);
+			btrfs_csum((char *)data + tmp, root->sectorsize, csum, csum_size);
 
 			csum_offset = leaf_offset +
 				 tmp / root->sectorsize * csum_size;
 			read_extent_buffer(eb, (char *)&csum_expected,
 					   csum_offset, csum_size);
 			/* try another mirror */
-			if (csum != csum_expected) {
-				fprintf(stderr, "mirror %d bytenr %llu csum %u expected csum %u\n",
-						mirror, bytenr + tmp,
-						csum, csum_expected);
+			if (!memcmp(csum, csum_expected, csum_size)) {
+				fprintf(stderr, "mirror %d bytenr %llu\n",
+						mirror, bytenr + tmp);
 				num_copies = btrfs_num_copies(
 						&root->fs_info->mapping_tree,
 						bytenr, num_bytes);
diff --git a/ctree.h b/ctree.h
index 89036de..af13e59 100644
--- a/ctree.h
+++ b/ctree.h
@@ -148,11 +148,13 @@  struct btrfs_free_space_ctl;
 
 /* csum types */
 #define BTRFS_CSUM_TYPE_CRC32	0
+#define BTRFS_CSUM_TYPE_SHA256	1
 
-static int btrfs_csum_sizes[] = { 4, 0 };
+static int btrfs_csum_sizes[] = { 4, 32, 0 };
 
 /* four bytes for CRC32 */
 #define BTRFS_CRC32_SIZE 4
+#define BTRFS_SHA256_SIZE 32
 #define BTRFS_EMPTY_DIR_SIZE 0
 
 #define BTRFS_FT_UNKNOWN	0
diff --git a/disk-io.c b/disk-io.c
index 03edf8e..6670dc5 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -31,7 +31,7 @@ 
 #include "disk-io.h"
 #include "volumes.h"
 #include "transaction.h"
-#include "crc32c.h"
+#include "hash.h"
 #include "utils.h"
 #include "print-tree.h"
 #include "rbtree-utils.h"
@@ -61,30 +61,18 @@  static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
 	return ret;
 }
 
-u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len)
-{
-	return crc32c(seed, data, len);
-}
-
-void btrfs_csum_final(u32 crc, char *result)
-{
-	*(__le32 *)result = ~cpu_to_le32(crc);
-}
-
 static int __csum_tree_block_size(struct extent_buffer *buf, u16 csum_size,
 				  int verify, int silent)
 {
 	char *result;
 	u32 len;
-	u32 crc = ~(u32)0;
 
 	result = malloc(csum_size * sizeof(char));
 	if (!result)
 		return 1;
 
 	len = buf->len - BTRFS_CSUM_SIZE;
-	crc = crc32c(crc, buf->data + BTRFS_CSUM_SIZE, len);
-	btrfs_csum_final(crc, result);
+	btrfs_csum(buf->data + BTRFS_CSUM_SIZE, len, (u8 *)result, csum_size);
 
 	if (verify) {
 		if (memcmp_extent_buffer(buf, result, 0, csum_size)) {
@@ -1286,15 +1274,14 @@  static int write_dev_supers(struct btrfs_root *root,
 			    struct btrfs_device *device)
 {
 	u64 bytenr;
-	u32 crc;
 	int i, ret;
+	int csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
 
 	if (root->fs_info->super_bytenr != BTRFS_SUPER_INFO_OFFSET) {
 		btrfs_set_super_bytenr(sb, root->fs_info->super_bytenr);
-		crc = ~(u32)0;
-		crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc,
-				      BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
-		btrfs_csum_final(crc, (char *)&sb->csum[0]);
+		btrfs_csum((char *)sb + BTRFS_CSUM_SIZE,
+			   BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE,
+			   &sb->csum[0], csum_size);
 
 		/*
 		 * super_copy is BTRFS_SUPER_INFO_SIZE bytes and is
@@ -1314,10 +1301,9 @@  static int write_dev_supers(struct btrfs_root *root,
 
 		btrfs_set_super_bytenr(sb, bytenr);
 
-		crc = ~(u32)0;
-		crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc,
-				      BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
-		btrfs_csum_final(crc, (char *)&sb->csum[0]);
+		btrfs_csum((char *)sb + BTRFS_CSUM_SIZE,
+			   BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE,
+			   &sb->csum[0], csum_size);
 
 		/*
 		 * super_copy is BTRFS_SUPER_INFO_SIZE bytes and is
diff --git a/file-item.c b/file-item.c
index b46d7f1..37867ef 100644
--- a/file-item.c
+++ b/file-item.c
@@ -24,7 +24,7 @@ 
 #include "disk-io.h"
 #include "transaction.h"
 #include "print-tree.h"
-#include "crc32c.h"
+#include "hash.h"
 
 #define MAX_CSUM_ITEMS(r,size) ((((BTRFS_LEAF_DATA_SIZE(r) - \
 			       sizeof(struct btrfs_item) * 2) / \
@@ -180,7 +180,7 @@  int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
 	struct btrfs_csum_item *item;
 	struct extent_buffer *leaf = NULL;
 	u64 csum_offset;
-	u32 csum_result = ~(u32)0;
+	u8 csum_result[BTRFS_CSUM_SIZE];
 	u32 nritems;
 	u32 ins_size;
 	u16 csum_size =
@@ -295,14 +295,9 @@  csum:
 	item = (struct btrfs_csum_item *)((unsigned char *)item +
 					  csum_offset * csum_size);
 found:
-	csum_result = btrfs_csum_data(root, data, csum_result, len);
-	btrfs_csum_final(csum_result, (char *)&csum_result);
-	if (csum_result == 0) {
-		printk("csum result is 0 for block %llu\n",
-		       (unsigned long long)bytenr);
-	}
+	btrfs_csum(data, len, csum_result, csum_size);
 
-	write_extent_buffer(leaf, &csum_result, (unsigned long)item,
+	write_extent_buffer(leaf, csum_result, (unsigned long)item,
 			    csum_size);
 	btrfs_mark_buffer_dirty(path->nodes[0]);
 fail:
diff --git a/free-space-cache.c b/free-space-cache.c
index 220449e..617f1a0 100644
--- a/free-space-cache.c
+++ b/free-space-cache.c
@@ -22,7 +22,7 @@ 
 #include "transaction.h"
 #include "disk-io.h"
 #include "extent_io.h"
-#include "crc32c.h"
+#include "hash.h"
 #include "bitops.h"
 
 /*
@@ -207,8 +207,11 @@  static int io_ctl_check_crc(struct io_ctl *io_ctl, int index)
 	val = *tmp;
 
 	io_ctl_map_page(io_ctl, 0);
-	crc = crc32c(crc, io_ctl->orig + offset, io_ctl->root->sectorsize - offset);
-	btrfs_csum_final(crc, (char *)&crc);
+
+	/* liubo: free space cache always uses crc32c for checksum */
+
+	btrfs_csum(io_ctl->orig + offset, io_ctl->root->sectorsize - offset,
+		   (u8 *)&crc, BTRFS_CRC32_SIZE);
 	if (val != crc) {
 		printk("btrfs: csum mismatch on free space cache\n");
 		io_ctl_unmap_page(io_ctl);
diff --git a/hash.c b/hash.c
new file mode 100644
index 0000000..3282f7b
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,32 @@ 
+/*
+ * Copyright (C) 2014 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 v2 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.
+ *
+ */
+
+#include "hash.h"
+#include "ctree.h"
+
+void btrfs_csum(const void *buf, int len, u8 *out, int csum_size)
+{
+	if (csum_size == BTRFS_CRC32_SIZE) {
+		u32 crc = ~(u32)0;
+
+		crc = crc32c(crc, buf, len);
+		*(__le32 *)out = ~cpu_to_le32(crc);
+	} else if (csum_size == BTRFS_SHA256_SIZE) {
+		struct sha256_ctx sctx;
+
+		sha256_init(&sctx);
+		sha256_update(&sctx, buf, len);
+		sha256_final(&sctx, out);
+	}
+}
diff --git a/hash.h b/hash.h
index 804fcda..7ade73a 100644
--- a/hash.h
+++ b/hash.h
@@ -19,6 +19,9 @@ 
 #ifndef __HASH__
 #define __HASH__
 #include "crc32c.h"
+#include "sha256.h"
+
+void btrfs_csum(const void *buf, int len, u8 *out, int csum_size);
 
 static inline u64 btrfs_name_hash(const char *name, int len)
 {
diff --git a/kerncompat.h b/kerncompat.h
index 8afadc8..d6aacf3 100644
--- a/kerncompat.h
+++ b/kerncompat.h
@@ -322,6 +322,13 @@  typedef u64 __bitwise __be64;
 #define le32_to_cpu(x) ((__force u32)(__le32)(bswap_32(x)))
 #define cpu_to_le16(x) ((__force __le16)(u16)(bswap_16(x)))
 #define le16_to_cpu(x) ((__force u16)(__le16)(bswap_16(x)))
+/* be{16,32,64} */
+#define cpu_to_be64(x) ((__force __be64)(u64)(x))
+#define be64_to_cpu(x) ((__force u64)(__be64)(x))
+#define cpu_to_be32(x) ((__force __be32)(u32)(x))
+#define be32_to_cpu(x) ((__force u32)(__be32)(x))
+#define cpu_to_be16(x) ((__force __be16)(u16)(x))
+#define be16_to_cpu(x) ((__force u16)(__be16)(x))
 #else
 #define cpu_to_le64(x) ((__force __le64)(u64)(x))
 #define le64_to_cpu(x) ((__force u64)(__le64)(x))
@@ -329,6 +336,13 @@  typedef u64 __bitwise __be64;
 #define le32_to_cpu(x) ((__force u32)(__le32)(x))
 #define cpu_to_le16(x) ((__force __le16)(u16)(x))
 #define le16_to_cpu(x) ((__force u16)(__le16)(x))
+/* be{16,32,64} */
+#define cpu_to_be64(x) ((__force __be64)(u64)(bswap_64(x)))
+#define be64_to_cpu(x) ((__force u64)(__be64)(bswap_64(x)))
+#define cpu_to_be32(x) ((__force __be32)(u32)(bswap_32(x)))
+#define be32_to_cpu(x) ((__force u32)(__be32)(bswap_32(x)))
+#define cpu_to_be16(x) ((__force __be16)(u16)(bswap_16(x)))
+#define be16_to_cpu(x) ((__force u16)(__be16)(bswap_16(x)))
 #endif
 
 struct __una_u16 { __le16 x; } __attribute__((__packed__));
diff --git a/mkfs.c b/mkfs.c
index e10e62d..d91921c 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -277,6 +277,7 @@  static void print_usage(void)
 	fprintf(stderr, "options:\n");
 	fprintf(stderr, "\t -A --alloc-start the offset to start the FS\n");
 	fprintf(stderr, "\t -b --byte-count total number of bytes in the FS\n");
+	fprintf(stderr, "\t -C --checksum-size specify the filesystem checksum size, only 32 and 256 are supported\n");
 	fprintf(stderr, "\t -d --data data profile, raid0, raid1, raid5, raid6, raid10, dup or single\n");
 	fprintf(stderr, "\t -f --force force overwrite of existing filesystem\n");
 	fprintf(stderr, "\t -l --leafsize size of btree leaves\n");
@@ -340,6 +341,7 @@  static char *parse_label(char *input)
 static struct option long_options[] = {
 	{ "alloc-start", 1, NULL, 'A'},
 	{ "byte-count", 1, NULL, 'b' },
+	{ "checksum-size", 1, NULL, 'C' },
 	{ "force", 0, NULL, 'f' },
 	{ "leafsize", 1, NULL, 'l' },
 	{ "label", 1, NULL, 'L'},
@@ -1266,6 +1268,7 @@  int main(int ac, char **av)
 	int discard = 1;
 	int ssd = 0;
 	int force_overwrite = 0;
+	int csum_size = BTRFS_CRC32_SIZE;
 
 	char *source_dir = NULL;
 	int source_dir_set = 0;
@@ -1280,7 +1283,7 @@  int main(int ac, char **av)
 
 	while(1) {
 		int c;
-		c = getopt_long(ac, av, "A:b:fl:n:s:m:d:L:O:r:U:VMK",
+		c = getopt_long(ac, av, "A:b:C:fl:n:s:m:d:L:O:r:U:VMK",
 				long_options, &option_index);
 		if (c < 0)
 			break;
@@ -1288,6 +1291,15 @@  int main(int ac, char **av)
 			case 'A':
 				alloc_start = parse_size(optarg);
 				break;
+			case 'C':
+				csum_size = parse_size(optarg);
+
+				if (csum_size != (BTRFS_CRC32_SIZE << 3) &&
+				    csum_size != (BTRFS_SHA256_SIZE << 3))
+					print_usage();
+
+				csum_size = csum_size >> 3;
+				break;
 			case 'f':
 				force_overwrite = 1;
 				break;
@@ -1566,7 +1578,7 @@  int main(int ac, char **av)
 
 	ret = make_btrfs(fd, file, label, fs_uuid, blocks, dev_block_count,
 			 nodesize, leafsize,
-			 sectorsize, stripesize, features);
+			 sectorsize, stripesize, features, csum_size);
 	if (ret) {
 		fprintf(stderr, "error during mkfs: %s\n", strerror(-ret));
 		exit(1);
@@ -1643,9 +1655,9 @@  raid_groups:
 	BUG_ON(ret);
 
 	printf("fs created label %s on %s\n\tnodesize %u leafsize %u "
-	    "sectorsize %u size %s\n",
+	    "sectorsize %u size %s csum_size %d\n",
 	    label, first_file, nodesize, leafsize, sectorsize,
-	    pretty_size(btrfs_super_total_bytes(root->fs_info->super_copy)));
+	    pretty_size(btrfs_super_total_bytes(root->fs_info->super_copy)), csum_size << 3);
 
 	btrfs_commit_transaction(trans, root);
 
diff --git a/sha256.c b/sha256.c
new file mode 100644
index 0000000..77eb0df
--- /dev/null
+++ b/sha256.c
@@ -0,0 +1,290 @@ 
+/*
+ * Copied from the kernel source code, crypto/sha256_generic.c.
+ *
+ * Cryptographic API.
+ *
+ * SHA-256, as specified in
+ * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf
+ *
+ * SHA-256 code by Jean-Luc Cooke <jlcooke@certainkey.com>.
+ *
+ * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * SHA224 Support Copyright 2007 Intel Corporation <jonathan.lynch@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include "kerncompat.h"
+#include "sha256.h"
+
+static inline u32 Ch(u32 x, u32 y, u32 z)
+{
+	return z ^ (x & (y ^ z));
+}
+
+static inline u32 Maj(u32 x, u32 y, u32 z)
+{
+	return (x & y) | (z & (x | y));
+}
+
+static inline uint32_t ror32(uint32_t word, unsigned int shift)
+{
+	return (word >> shift) | (word << (32 - shift));
+}
+
+#define e0(x)       (ror32(x, 2) ^ ror32(x,13) ^ ror32(x,22))
+#define e1(x)       (ror32(x, 6) ^ ror32(x,11) ^ ror32(x,25))
+#define s0(x)       (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3))
+#define s1(x)       (ror32(x,17) ^ ror32(x,19) ^ (x >> 10))
+
+static inline void LOAD_OP(int I, u32 *W, const u8 *input)
+{
+	W[I] = be32_to_cpu( ((__be32*)(input))[I] );
+}
+
+static inline void BLEND_OP(int I, u32 *W)
+{
+	W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
+}
+
+static void sha256_transform(u32 *state, const u8 *input)
+{
+	u32 a, b, c, d, e, f, g, h, t1, t2;
+	u32 W[64];
+	int i;
+
+	/* load the input */
+	for (i = 0; i < 16; i++)
+		LOAD_OP(i, W, input);
+
+	/* now blend */
+	for (i = 16; i < 64; i++)
+		BLEND_OP(i, W);
+
+	/* load the state into our registers */
+	a=state[0];  b=state[1];  c=state[2];  d=state[3];
+	e=state[4];  f=state[5];  g=state[6];  h=state[7];
+
+	/* now iterate */
+	t1 = h + e1(e) + Ch(e,f,g) + 0x428a2f98 + W[ 0];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0x71374491 + W[ 1];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0xb5c0fbcf + W[ 2];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0xe9b5dba5 + W[ 3];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x3956c25b + W[ 4];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0x59f111f1 + W[ 5];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x923f82a4 + W[ 6];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0xab1c5ed5 + W[ 7];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0xd807aa98 + W[ 8];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0x12835b01 + W[ 9];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0x243185be + W[10];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0x550c7dc3 + W[11];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x72be5d74 + W[12];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0x80deb1fe + W[13];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x9bdc06a7 + W[14];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0xc19bf174 + W[15];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0xe49b69c1 + W[16];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0xefbe4786 + W[17];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0x0fc19dc6 + W[18];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0x240ca1cc + W[19];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x2de92c6f + W[20];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0x4a7484aa + W[21];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x5cb0a9dc + W[22];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0x76f988da + W[23];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0x983e5152 + W[24];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0xa831c66d + W[25];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0xb00327c8 + W[26];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0xbf597fc7 + W[27];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0xc6e00bf3 + W[28];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0xd5a79147 + W[29];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x06ca6351 + W[30];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0x14292967 + W[31];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0x27b70a85 + W[32];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0x2e1b2138 + W[33];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0x4d2c6dfc + W[34];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0x53380d13 + W[35];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x650a7354 + W[36];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0x766a0abb + W[37];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x81c2c92e + W[38];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0x92722c85 + W[39];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0xa2bfe8a1 + W[40];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0xa81a664b + W[41];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0xc24b8b70 + W[42];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0xc76c51a3 + W[43];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0xd192e819 + W[44];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0xd6990624 + W[45];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0xf40e3585 + W[46];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0x106aa070 + W[47];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0x19a4c116 + W[48];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0x1e376c08 + W[49];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0x2748774c + W[50];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0x34b0bcb5 + W[51];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x391c0cb3 + W[52];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0x4ed8aa4a + W[53];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x5b9cca4f + W[54];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0x682e6ff3 + W[55];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0x748f82ee + W[56];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0x78a5636f + W[57];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0x84c87814 + W[58];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0x8cc70208 + W[59];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x90befffa + W[60];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0xa4506ceb + W[61];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0xbef9a3f7 + W[62];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0xc67178f2 + W[63];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	state[0] += a; state[1] += b; state[2] += c; state[3] += d;
+	state[4] += e; state[5] += f; state[6] += g; state[7] += h;
+
+	/* clear any sensitive info... */
+	a = b = c = d = e = f = g = h = t1 = t2 = 0;
+	memset(W, 0, 64 * sizeof(u32));
+}
+
+int sha256_init(struct sha256_ctx *sctx)
+{
+	sctx->state[0] = SHA256_H0;
+	sctx->state[1] = SHA256_H1;
+	sctx->state[2] = SHA256_H2;
+	sctx->state[3] = SHA256_H3;
+	sctx->state[4] = SHA256_H4;
+	sctx->state[5] = SHA256_H5;
+	sctx->state[6] = SHA256_H6;
+	sctx->state[7] = SHA256_H7;
+	sctx->count = 0;
+
+	return 0;
+}
+
+int sha256_update(struct sha256_ctx *sctx, const u8 *data, unsigned int len)
+{
+	unsigned int partial, done;
+	const u8 *src;
+
+	partial = sctx->count & 0x3f;
+	sctx->count += len;
+	done = 0;
+	src = data;
+
+	if ((partial + len) > 63) {
+		if (partial) {
+			done = -partial;
+			memcpy(sctx->buf + partial, data, done + 64);
+			src = sctx->buf;
+		}
+
+		do {
+			sha256_transform(sctx->state, src);
+			done += 64;
+			src = data + done;
+		} while (done + 63 < len);
+
+		partial = 0;
+	}
+	memcpy(sctx->buf + partial, src, len - done);
+
+	return 0;
+}
+
+int sha256_final(struct sha256_ctx *sctx, u8 *out)
+{
+	__be32 *dst = (__be32 *)out;
+	__be64 bits;
+	unsigned int index, pad_len;
+	int i;
+	static const u8 padding[64] = { 0x80, };
+
+	/* Save number of bits */
+	bits = cpu_to_be64(sctx->count << 3);
+
+	/* Pad out to 56 mod 64. */
+	index = sctx->count & 0x3f;
+	pad_len = (index < 56) ? (56 - index) : ((64+56) - index);
+	sha256_update(sctx, padding, pad_len);
+
+	/* Append length (before padding) */
+	sha256_update(sctx, (const u8 *)&bits, sizeof(bits));
+
+	/* Store state in digest */
+	for (i = 0; i < 8; i++)
+		dst[i] = cpu_to_be32(sctx->state[i]);
+
+	/* Zeroize sensitive information. */
+	memset(sctx, 0, sizeof(*sctx));
+
+	return 0;
+}
diff --git a/sha256.h b/sha256.h
new file mode 100644
index 0000000..91c826d
--- /dev/null
+++ b/sha256.h
@@ -0,0 +1,42 @@ 
+/*
+ * Copyright (C) 2007 Red Hat.  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 v2 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.
+ */
+
+#ifndef __SHA256__
+#define __SHA256__
+
+#if BTRFS_FLAT_INCLUDES
+#include "kerncompat.h"
+#else
+#include <btrfs/kerncompat.h>
+#endif /* BTRFS_FLAT_INCLUDES */
+
+struct sha256_ctx {
+	u64 count;
+	u32 state[8];
+	u8 buf[64];
+};
+
+#define SHA256_H0       0x6a09e667UL
+#define SHA256_H1       0xbb67ae85UL
+#define SHA256_H2       0x3c6ef372UL
+#define SHA256_H3       0xa54ff53aUL
+#define SHA256_H4       0x510e527fUL
+#define SHA256_H5       0x9b05688cUL
+#define SHA256_H6       0x1f83d9abUL
+#define SHA256_H7       0x5be0cd19UL
+
+int sha256_init(struct sha256_ctx *sctx);
+int sha256_update(struct sha256_ctx *sctx, const u8 *data, unsigned int len);
+int sha256_final(struct sha256_ctx *sctx, u8 *out);
+
+#endif
diff --git a/super-recover.c b/super-recover.c
index adb2c44..7666c56 100644
--- a/super-recover.c
+++ b/super-recover.c
@@ -34,7 +34,7 @@ 
 #include "disk-io.h"
 #include "list.h"
 #include "utils.h"
-#include "crc32c.h"
+#include "hash.h"
 #include "volumes.h"
 #include "commands.h"
 
@@ -94,17 +94,16 @@  void free_recover_superblock(struct btrfs_recover_superblock *recover)
 static int check_super(u64 bytenr, struct btrfs_super_block *sb)
 {
 	int csum_size = btrfs_super_csum_size(sb);
-	char result[csum_size];
-	u32 crc = ~(u32)0;
+	char result[BTRFS_CSUM_SIZE];
 
 	if (btrfs_super_bytenr(sb) != bytenr)
 		return 0;
 	if (sb->magic != cpu_to_le64(BTRFS_MAGIC))
 		return 0;
 
-	crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE,
-			crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
-	btrfs_csum_final(crc, result);
+	btrfs_csum((char *)sb + BTRFS_CSUM_SIZE,
+		    BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE,
+		    (u8 *)result, csum_size);
 
 	return !memcmp(sb, &result, csum_size);
 }
diff --git a/utils.c b/utils.c
index 2a92416..06691b5 100644
--- a/utils.c
+++ b/utils.c
@@ -43,7 +43,7 @@ 
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
-#include "crc32c.h"
+#include "hash.h"
 #include "utils.h"
 #include "volumes.h"
 #include "ioctl.h"
@@ -173,7 +173,8 @@  int test_uuid_unique(char *fs_uuid)
 
 int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 	       u64 blocks[7], u64 num_bytes, u32 nodesize,
-	       u32 leafsize, u32 sectorsize, u32 stripesize, u64 features)
+	       u32 leafsize, u32 sectorsize, u32 stripesize, u64 features,
+	       int csum_size_assign)
 {
 	struct btrfs_super_block super;
 	struct extent_buffer *buf = NULL;
@@ -194,9 +195,16 @@  int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 	u64 ref_root;
 	u32 array_size;
 	u32 item_size;
+	int csum_size = 0;
+	int csum_type = BTRFS_CSUM_TYPE_CRC32;
 	int skinny_metadata = !!(features &
 				 BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA);
 
+	if (csum_size_assign == BTRFS_CRC32_SIZE)
+		csum_type = BTRFS_CSUM_TYPE_CRC32;
+	else if (csum_size_assign == BTRFS_SHA256_SIZE)
+		csum_type = BTRFS_CSUM_TYPE_SHA256;
+
 	first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize * 2 - 1;
 	first_free &= ~((u64)sectorsize - 1);
 
@@ -232,13 +240,15 @@  int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 	btrfs_set_super_leafsize(&super, leafsize);
 	btrfs_set_super_nodesize(&super, nodesize);
 	btrfs_set_super_stripesize(&super, stripesize);
-	btrfs_set_super_csum_type(&super, BTRFS_CSUM_TYPE_CRC32);
+	btrfs_set_super_csum_type(&super, csum_type);
 	btrfs_set_super_chunk_root_generation(&super, 1);
 	btrfs_set_super_cache_generation(&super, -1);
 	btrfs_set_super_incompat_flags(&super, features);
 	if (label)
 		strncpy(super.label, label, BTRFS_LABEL_SIZE - 1);
 
+	csum_size = btrfs_super_csum_size(&super);
+
 	buf = malloc(sizeof(*buf) + max(sectorsize, leafsize));
 
 	/* create the tree of root objects */
@@ -321,7 +331,7 @@  int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 	nritems++;
 
 
-	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
+	csum_tree_block_size(buf, csum_size, 0);
 	ret = pwrite(fd, buf->data, leafsize, blocks[1]);
 	if (ret != leafsize) {
 		ret = (ret < 0 ? -errno : -EIO);
@@ -380,7 +390,7 @@  int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 	btrfs_set_header_bytenr(buf, blocks[2]);
 	btrfs_set_header_owner(buf, BTRFS_EXTENT_TREE_OBJECTID);
 	btrfs_set_header_nritems(buf, nritems);
-	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
+	csum_tree_block_size(buf, csum_size, 0);
 	ret = pwrite(fd, buf->data, leafsize, blocks[2]);
 	if (ret != leafsize) {
 		ret = (ret < 0 ? -errno : -EIO);
@@ -467,7 +477,7 @@  int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 	btrfs_set_header_bytenr(buf, blocks[3]);
 	btrfs_set_header_owner(buf, BTRFS_CHUNK_TREE_OBJECTID);
 	btrfs_set_header_nritems(buf, nritems);
-	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
+	csum_tree_block_size(buf, csum_size, 0);
 	ret = pwrite(fd, buf->data, leafsize, blocks[3]);
 	if (ret != leafsize) {
 		ret = (ret < 0 ? -errno : -EIO);
@@ -506,7 +516,7 @@  int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 	btrfs_set_header_bytenr(buf, blocks[4]);
 	btrfs_set_header_owner(buf, BTRFS_DEV_TREE_OBJECTID);
 	btrfs_set_header_nritems(buf, nritems);
-	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
+	csum_tree_block_size(buf, csum_size, 0);
 	ret = pwrite(fd, buf->data, leafsize, blocks[4]);
 	if (ret != leafsize) {
 		ret = (ret < 0 ? -errno : -EIO);
@@ -519,7 +529,7 @@  int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 	btrfs_set_header_bytenr(buf, blocks[5]);
 	btrfs_set_header_owner(buf, BTRFS_FS_TREE_OBJECTID);
 	btrfs_set_header_nritems(buf, 0);
-	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
+	csum_tree_block_size(buf, csum_size, 0);
 	ret = pwrite(fd, buf->data, leafsize, blocks[5]);
 	if (ret != leafsize) {
 		ret = (ret < 0 ? -errno : -EIO);
@@ -531,7 +541,7 @@  int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 	btrfs_set_header_bytenr(buf, blocks[6]);
 	btrfs_set_header_owner(buf, BTRFS_CSUM_TREE_OBJECTID);
 	btrfs_set_header_nritems(buf, 0);
-	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
+	csum_tree_block_size(buf, csum_size, 0);
 	ret = pwrite(fd, buf->data, leafsize, blocks[6]);
 	if (ret != leafsize) {
 		ret = (ret < 0 ? -errno : -EIO);
@@ -543,7 +553,7 @@  int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 	memset(buf->data, 0, sectorsize);
 	memcpy(buf->data, &super, sizeof(super));
 	buf->len = sectorsize;
-	csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
+	csum_tree_block_size(buf, csum_size, 0);
 	ret = pwrite(fd, buf->data, sectorsize, blocks[0]);
 	if (ret != sectorsize) {
 		ret = (ret < 0 ? -errno : -EIO);
diff --git a/utils.h b/utils.h
index 289e86b..cc93424 100644
--- a/utils.h
+++ b/utils.h
@@ -71,7 +71,8 @@  void units_set_base(unsigned *units, unsigned base);
 
 int make_btrfs(int fd, const char *device, const char *label,
 	       char *fs_uuid, u64 blocks[6], u64 num_bytes, u32 nodesize,
-	       u32 leafsize, u32 sectorsize, u32 stripesize, u64 features);
+	       u32 leafsize, u32 sectorsize, u32 stripesize, u64 features,
+	       int csum_size_assign);
 int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
 			struct btrfs_root *root, u64 objectid);
 int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret,