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....@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 --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 <jlco...@certainkey.com>.
+ *
+ * Copyright (c) Jean-Luc Cooke <jlco...@certainkey.com>
+ * Copyright (c) Andrew McDonald <and...@mcdonald.org.uk>
+ * Copyright (c) 2002 James Morris <jmor...@intercode.com.au>
+ * SHA224 Support Copyright 2007 Intel Corporation <jonathan.ly...@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,
-- 
1.8.2.1

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to