Whamcloud - gitweb
LU-1201 checksum: add libcfs crypto hash
authorAlexander.Boyko <alexander_boyko@xyratex.com>
Thu, 28 Jun 2012 06:04:06 +0000 (10:04 +0400)
committerAndreas Dilger <adilger@whamcloud.com>
Fri, 29 Jun 2012 17:24:18 +0000 (13:24 -0400)
Add libcfs crypto hash and cleanup all lustre hash checksumming.
Now lustre hash calculations base on linux kernel crypto api for kernel,
and base on libcfs crypto implementation for userlevel. So any improvement
at linux kernel for hashes would improve lustre.

Signed-off-by: Alexander Boyko <alexander_boyko@xyratex.com>
Reviewed-by: Alexey Lyashkov <alexey_lyashkov@xyratex.com>
Reviewed-by: Alexander Zarochentsev <alexander_zarochentsev@xyratex.com>
Xyratex-bug-id: MRP-337, MRP-471
Change-Id: I2fbf0f4d0c8ce7e7c3c7ea411c6ccd9dcfc7e03a
Reviewed-on: http://review.whamcloud.com/3098
Tested-by: Hudson
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: Maloo <whamcloud.maloo@gmail.com>
33 files changed:
libcfs/autoconf/lustre-libcfs.m4
libcfs/include/libcfs/Makefile.am
libcfs/include/libcfs/libcfs.h
libcfs/include/libcfs/libcfs_crypto.h [new file with mode: 0644]
libcfs/include/libcfs/linux/Makefile.am
libcfs/include/libcfs/linux/linux-crypto.h [new file with mode: 0644]
libcfs/include/libcfs/posix/Makefile.am
libcfs/include/libcfs/posix/posix-crypto.h [new file with mode: 0644]
libcfs/libcfs/Makefile.in
libcfs/libcfs/autoMakefile.am
libcfs/libcfs/linux/Makefile.am
libcfs/libcfs/linux/linux-crypto-adler.c [new file with mode: 0644]
libcfs/libcfs/linux/linux-crypto-crc32.c [new file with mode: 0644]
libcfs/libcfs/linux/linux-crypto.c [new file with mode: 0644]
libcfs/libcfs/module.c
libcfs/libcfs/posix/posix-adler.c [new file with mode: 0644]
libcfs/libcfs/posix/posix-crc32.c [new file with mode: 0644]
libcfs/libcfs/user-crypto.c [new file with mode: 0644]
lustre/include/linux/Makefile.am
lustre/include/linux/obd_cksum.h [deleted file]
lustre/include/lustre_sec.h
lustre/include/obd_cksum.h
lustre/llite/llite_lib.c
lustre/mds/mds_lov.c
lustre/obdfilter/filter.c
lustre/ofd/ofd_obd.c
lustre/osc/osc_request.c
lustre/ost/ost_handler.c
lustre/ptlrpc/import.c
lustre/ptlrpc/pack_generic.c
lustre/ptlrpc/sec_bulk.c
lustre/ptlrpc/sec_plain.c
lustre/tests/sanity.sh

index dfd9c03..8ff37b5 100644 (file)
@@ -93,6 +93,30 @@ AC_DEFINE(HAVE_TASKLIST_LOCK, 1,
 ])
 ])
 
+# LIBCFS_DIGEST_SETKEY_FLAGS
+# digest_alg.dia_setkey takes 4 args (2.6.18)
+#
+AC_DEFUN([LIBCFS_DIGEST_SETKEY_FLAGS],
+[AC_MSG_CHECKING([if kernel dia_setkey takes 4 args])
+LB_LINUX_TRY_COMPILE([
+       #include <linux/err.h>
+       #include <linux/crypto.h>
+
+       static int foo(struct crypto_tfm *tfm, const u8 *key, unsigned int l, u32* f)
+       {
+               return 1;
+       }
+],[
+       struct digest_alg alg = {.dia_setkey=foo};
+],[
+       AC_MSG_RESULT([yes])
+       AC_DEFINE(HAVE_DIGEST_SETKEY_FLAGS, 1, [kernel dia_setkey takes 4 args])
+],[
+       AC_MSG_RESULT([no])
+])
+])
+
+
 # 2.6.19 API changes
 # kmem_cache_destroy(cachep) return void instead of
 # int
@@ -222,6 +246,7 @@ LB_LINUX_TRY_COMPILE([
 ])
 ])
 
+
 # 2.6.20 API change INIT_WORK use 2 args and not
 # store data inside
 AC_DEFUN([LIBCFS_3ARGS_INIT_WORK],
@@ -490,6 +515,25 @@ LB_LINUX_TRY_COMPILE([
 ])
 ])
 
+# LIBCFS_STRUCT_SHASH_ALG
+# struct shash_alg was introduced in 2.6.29
+#
+AC_DEFUN([LIBCFS_STRUCT_SHASH_ALG],
+[AC_MSG_CHECKING([if kernel has struct shash_alg])
+LB_LINUX_TRY_COMPILE([
+       #include <linux/err.h>
+       #include <crypto/internal/hash.h>
+],[
+       struct shash_alg foo;
+],[
+       AC_MSG_RESULT([yes])
+       AC_DEFINE(HAVE_STRUCT_SHASH_ALG, 1, [kernel has struct shash_alg])
+],[
+       AC_MSG_RESULT([no])
+])
+])
+
+
 #
 # LIBCFS_FUNC_UNSHARE_FS_STRUCT
 #
@@ -712,6 +756,7 @@ LIBCFS_U64_LONG_LONG_LINUX
 # 2.6.18
 LIBCFS_TASKLIST_LOCK
 LIBCFS_HAVE_IS_COMPAT_TASK
+LIBCFS_DIGEST_SETKEY_FLAGS
 # 2.6.19
 LIBCFS_KMEM_CACHE_DESTROY_INT
 # 2.6.20
@@ -735,6 +780,7 @@ LIBCFS_CPUMASK_SIZE
 # 2.6.29
 LIBCFS_STRUCT_CRED_IN_TASK
 LIBCFS_CPU_TOPOLOGY
+LIBCFS_STRUCT_SHASH_ALG
 # 2.6.30
 LIBCFS_FUNC_UNSHARE_FS_STRUCT
 LIBCFS_SOCK_MAP_FD_2ARG
index 79f923a..89054ee 100644 (file)
@@ -11,4 +11,4 @@ EXTRA_DIST := curproc.h libcfs_private.h libcfs.h list.h lltrace.h \
                libcfs_debug.h libcfsutil.h libcfs_ioctl.h \
                libcfs_pack.h libcfs_unpack.h libcfs_string.h \
                libcfs_kernelcomm.h libcfs_workitem.h lucache.h \
-               libcfs_fail.h params_tree.h
+               libcfs_fail.h params_tree.h libcfs_crypto.h
index c231439..7ce9c66 100644 (file)
@@ -316,6 +316,7 @@ void cfs_get_random_bytes(void *buf, int size);
 #include <libcfs/libcfs_hash.h>
 #include <libcfs/libcfs_fail.h>
 #include <libcfs/params_tree.h>
+#include <libcfs/libcfs_crypto.h>
 
 /* container_of depends on "likely" which is defined in libcfs_private.h */
 static inline void *__container_of(void *ptr, unsigned long shift)
diff --git a/libcfs/include/libcfs/libcfs_crypto.h b/libcfs/include/libcfs/libcfs_crypto.h
new file mode 100644 (file)
index 0000000..291191a
--- /dev/null
@@ -0,0 +1,201 @@
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please  visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ */
+
+#ifndef _LIBCFS_CRYPTO_H
+#define _LIBCFS_CRYPTO_H
+
+struct cfs_crypto_hash_type {
+       char            *cht_name;      /**< hash algorithm name, equal to
+                                        * format name for crypto api */
+       unsigned int    cht_key;        /**< init key by default (vaild for
+                                        * 4 bytes context like crc32, adler */
+       unsigned int    cht_size;       /**< hash digest size */
+};
+
+enum cfs_crypto_hash_alg {
+       CFS_HASH_ALG_NULL       = 0,
+       CFS_HASH_ALG_ADLER32,
+       CFS_HASH_ALG_CRC32,
+       CFS_HASH_ALG_MD5,
+       CFS_HASH_ALG_SHA1,
+       CFS_HASH_ALG_SHA256,
+       CFS_HASH_ALG_SHA384,
+       CFS_HASH_ALG_SHA512,
+       CFS_HASH_ALG_CRC32C,
+       CFS_HASH_ALG_MAX
+};
+
+static struct cfs_crypto_hash_type hash_types[] = {
+       [CFS_HASH_ALG_NULL]    = { "null",     0,      0 },
+       [CFS_HASH_ALG_ADLER32] = { "adler32",  1,      4 },
+       [CFS_HASH_ALG_CRC32]   = { "crc32",   ~0,      4 },
+       [CFS_HASH_ALG_CRC32C]  = { "crc32c",  ~0,      4 },
+       [CFS_HASH_ALG_MD5]     = { "md5",      0,     16 },
+       [CFS_HASH_ALG_SHA1]    = { "sha1",     0,     20 },
+       [CFS_HASH_ALG_SHA256]  = { "sha256",   0,     32 },
+       [CFS_HASH_ALG_SHA384]  = { "sha384",   0,     48 },
+       [CFS_HASH_ALG_SHA512]  = { "sha512",   0,     64 },
+};
+
+/**    Return pointer to type of hash for valid hash algorithm identifier */
+static inline const struct cfs_crypto_hash_type *
+                   cfs_crypto_hash_type(unsigned char hash_alg)
+{
+       struct cfs_crypto_hash_type *ht;
+
+       if (hash_alg < CFS_HASH_ALG_MAX) {
+               ht = &hash_types[hash_alg];
+               if (ht->cht_name)
+                       return ht;
+       }
+       return NULL;
+}
+
+/**     Return hash name for valid hash algorithm identifier or "unknown" */
+static inline const char *cfs_crypto_hash_name(unsigned char hash_alg)
+{
+       const struct cfs_crypto_hash_type *ht;
+
+       ht = cfs_crypto_hash_type(hash_alg);
+       if (ht)
+               return ht->cht_name;
+       else
+               return "unknown";
+}
+
+/**     Return digest size for valid algorithm identifier or 0 */
+static inline int cfs_crypto_hash_digestsize(unsigned char hash_alg)
+{
+       const struct cfs_crypto_hash_type *ht;
+
+       ht = cfs_crypto_hash_type(hash_alg);
+       if (ht)
+               return ht->cht_size;
+       else
+               return 0;
+}
+
+/**     Return hash identifier for valid hash algorithm name or 0xFF */
+static inline unsigned char cfs_crypto_hash_alg(const char *algname)
+{
+       unsigned char   i;
+
+       for (i = 0; i < CFS_HASH_ALG_MAX; i++)
+               if (!strcmp(hash_types[i].cht_name, algname))
+                       break;
+       return (i == CFS_HASH_ALG_MAX ? 0xFF : i);
+}
+
+/**     Calculate hash digest for buffer.
+ *      @param alg         id of hash algorithm
+ *      @param buf         buffer of data
+ *      @param buf_len buffer len
+ *      @param key         initial value for algorithm, if it is NULL,
+ *                         default initial value should be used.
+ *      @param key_len len of initial value
+ *      @param hash       [out] pointer to hash, if it is NULL, hash_len is
+ *                         set to valid digest size in bytes, retval -ENOSPC.
+ *      @param hash_len       [in,out] size of hash buffer
+ *      @returns             status of operation
+ *      @retval -EINVAL       if buf, buf_len, hash_len or alg_id is invalid
+ *      @retval -ENODEV       if this algorithm is unsupported
+ *      @retval -ENOSPC       if pointer to hash is NULL, or hash_len less than
+ *                         digest size
+ *      @retval 0           for success
+ *      @retval < 0       other errors from lower layers.
+ */
+int cfs_crypto_hash_digest(unsigned char alg,
+                          const void *buf, unsigned int buf_len,
+                          unsigned char *key, unsigned int key_len,
+                          unsigned char *hash, unsigned int *hash_len);
+
+/* cfs crypto hash descriptor */
+struct cfs_crypto_hash_desc;
+
+/**     Allocate and initialize desriptor for hash algorithm.
+ *      @param alg         algorithm id
+ *      @param key         initial value for algorithm, if it is NULL,
+ *                         default initial value should be used.
+ *      @param key_len len of initial value
+ *      @returns             pointer to descriptor of hash instance
+ *      @retval ERR_PTR(error) when errors occured.
+ */
+struct cfs_crypto_hash_desc*
+       cfs_crypto_hash_init(unsigned char alg,
+                            unsigned char *key, unsigned int key_len);
+
+/**    Update digest by part of data.
+ *     @param desc           hash descriptor
+ *     @param page           data page
+ *     @param offset       data offset
+ *     @param len             data len
+ *     @returns                 status of operation
+ *     @retval 0               for success.
+ */
+int cfs_crypto_hash_update_page(struct cfs_crypto_hash_desc *desc,
+                               cfs_page_t *page, unsigned int offset,
+                               unsigned int len);
+
+/**    Update digest by part of data.
+ *     @param desc           hash descriptor
+ *     @param buf             pointer to data buffer
+ *     @param buf_len     size of data at buffer
+ *     @returns                 status of operation
+ *     @retval 0               for success.
+ */
+int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *desc, const void *buf,
+                          unsigned int buf_len);
+
+/**    Finalize hash calculation, copy hash digest to buffer, destroy hash
+ *     descriptor.
+ *     @param desc           hash descriptor
+ *     @param hash           buffer pointer to store hash digest
+ *     @param hash_len   pointer to hash buffer size, if NULL
+ *                           destory hash descriptor
+ *     @returns                 status of operation
+ *     @retval -ENOSPC   if hash is NULL, or *hash_len less than
+ *                           digest size
+ *     @retval 0               for success
+ *     @retval < 0           other errors from lower layers.
+ */
+int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *desc,
+                         unsigned char *hash, unsigned int *hash_len);
+/**
+ *      Register crypto hash algorithms
+ */
+int cfs_crypto_register(void);
+
+/**
+ *      Unregister
+ */
+void cfs_crypto_unregister(void);
+
+/**     Return hash speed in Mbytes per second for valid hash algorithm
+ *      identifier. If test was unsuccessfull -1 would be return.
+ */
+int cfs_crypto_hash_speed(unsigned char hash_alg);
+#endif
index a7ca7cc..0a5917f 100644 (file)
@@ -1,3 +1,3 @@
 EXTRA_DIST := kp30.h libcfs.h linux-fs.h linux-lock.h linux-mem.h      \
        linux-prim.h linux-time.h linux-tcpip.h lltrace.h linux-cpu.h   \
-       portals_compat25.h linux-bitops.h linux-types.h
+       portals_compat25.h linux-bitops.h linux-types.h linux-crypto.h
diff --git a/libcfs/include/libcfs/linux/linux-crypto.h b/libcfs/include/libcfs/linux/linux-crypto.h
new file mode 100644 (file)
index 0000000..c8a4e76
--- /dev/null
@@ -0,0 +1,43 @@
+ /*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please  visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ */
+
+/**
+ * Linux crypto hash specific functions.
+ */
+
+/**
+ * Functions for start/stop shash CRC32 algorithm.
+ */
+int cfs_crypto_crc32_register(void);
+void cfs_crypto_crc32_unregister(void);
+
+/**
+ * Functions for start/stop shash adler32 algorithm.
+ */
+int cfs_crypto_adler32_register(void);
+void cfs_crypto_adler32_unregister(void);
index ca5c0da..609bb0c 100644 (file)
@@ -4,4 +4,4 @@ if UTILS
 libcfsposix_HEADERS = posix-types.h
 endif
 
-EXTRA_DIST := libcfs.h posix-wordsize.h posix-types.h
+EXTRA_DIST := libcfs.h posix-wordsize.h posix-types.h posix-crypto.h
diff --git a/libcfs/include/libcfs/posix/posix-crypto.h b/libcfs/include/libcfs/posix/posix-crypto.h
new file mode 100644 (file)
index 0000000..72a9fc1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please  visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ */
+
+/**
+ *      User crypto hash specific functions.
+ */
+
+/**
+ *      CRC32 functions.
+ */
+int crc32init_le(void);
+unsigned int crc32_le(unsigned int crc, unsigned char const *p, size_t len);
+
+/**
+ *      Adler32 functions.
+ */
+unsigned long zlib_adler32(unsigned long adler,
+                          const unsigned char *buf,
+                          unsigned int len);
index 026dcab..2b040b0 100644 (file)
@@ -5,6 +5,8 @@ libcfs-linux-objs += linux-prim.o linux-mem.o linux-cpu.o
 libcfs-linux-objs += linux-fs.o linux-sync.o linux-tcpip.o
 libcfs-linux-objs += linux-lwt.o linux-proc.o linux-curproc.o
 libcfs-linux-objs += linux-utils.o linux-module.o
+libcfs-linux-objs += linux-crypto.o linux-crypto-crc32.o
+libcfs-linux-objs += linux-crypto-adler.o
 
 default: all
 
index 3b143e7..295cab5 100644 (file)
@@ -45,7 +45,8 @@ noinst_LIBRARIES= libcfs.a
 libcfs_a_SOURCES= posix/posix-debug.c user-prim.c user-lock.c user-tcpip.c \
                  prng.c user-bitops.c user-mem.c hash.c kernel_user_comm.c \
                  workitem.c fail.c libcfs_cpu.c libcfs_mem.c libcfs_lock.c \
-                 posix/rbtree.c
+                 posix/rbtree.c user-crypto.c posix/posix-crc32.c \
+                 posix/posix-adler.c
 libcfs_a_CPPFLAGS = $(LLCPPFLAGS)
 libcfs_a_CFLAGS = $(LLCFLAGS)
 endif
index 4792d73..8d206cf 100644 (file)
@@ -1,5 +1,7 @@
 EXTRA_DIST := linux-debug.c linux-lwt.c linux-prim.c linux-tracefile.c \
        linux-fs.c linux-mem.c linux-proc.c linux-utils.c linux-lock.c  \
-       linux-module.c linux-sync.c linux-curproc.c linux-tcpip.c linux-cpu.c
+       linux-module.c linux-sync.c linux-curproc.c linux-tcpip.c       \
+       linux-cpu.c linux-crypto.c linux-crypto-crc32.c linux-crypto-adler.c
+
 
 
diff --git a/libcfs/libcfs/linux/linux-crypto-adler.c b/libcfs/libcfs/linux/linux-crypto-adler.c
new file mode 100644 (file)
index 0000000..9eeda9c
--- /dev/null
@@ -0,0 +1,218 @@
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please  visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ */
+
+/*
+ * This is crypto api shash wrappers to zlib_adler32.
+ */
+
+#include <linux/zutil.h>
+#ifdef HAVE_STRUCT_SHASH_ALG
+#include <crypto/internal/hash.h>
+#else
+#include <linux/crypto.h>
+#endif
+
+
+#define CHKSUM_BLOCK_SIZE      1
+#define CHKSUM_DIGEST_SIZE     4
+
+
+static u32 __adler32(u32 cksum, unsigned char const *p, size_t len)
+{
+       return zlib_adler32(cksum, p, len);
+}
+
+static int adler32_cra_init(struct crypto_tfm *tfm)
+{
+       u32 *key = crypto_tfm_ctx(tfm);
+
+       *key = 1;
+
+       return 0;
+}
+
+#ifdef HAVE_STRUCT_SHASH_ALG
+static int adler32_setkey(struct crypto_shash *hash, const u8 *key,
+                         unsigned int keylen)
+{
+       u32 *mctx = crypto_shash_ctx(hash);
+
+       if (keylen != sizeof(u32)) {
+               crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+               return -EINVAL;
+       }
+       *mctx = *(u32 *)key;
+       return 0;
+}
+
+static int adler32_init(struct shash_desc *desc)
+{
+       u32 *mctx = crypto_shash_ctx(desc->tfm);
+       u32 *cksump = shash_desc_ctx(desc);
+
+       *cksump = *mctx;
+
+       return 0;
+}
+
+static int adler32_update(struct shash_desc *desc, const u8 *data,
+                         unsigned int len)
+{
+       u32 *cksump = shash_desc_ctx(desc);
+
+       *cksump = __adler32(*cksump, data, len);
+       return 0;
+}
+static int __adler32_finup(u32 *cksump, const u8 *data, unsigned int len,
+                          u8 *out)
+{
+       *(u32 *)out = __adler32(*cksump, data, len);
+       return 0;
+}
+
+static int adler32_finup(struct shash_desc *desc, const u8 *data,
+                        unsigned int len, u8 *out)
+{
+       return __adler32_finup(shash_desc_ctx(desc), data, len, out);
+}
+
+static int adler32_final(struct shash_desc *desc, u8 *out)
+{
+       u32 *cksump = shash_desc_ctx(desc);
+
+       *(u32 *)out = *cksump;
+       return 0;
+}
+
+static int adler32_digest(struct shash_desc *desc, const u8 *data,
+                         unsigned int len, u8 *out)
+{
+       return __adler32_finup(crypto_shash_ctx(desc->tfm), data, len,
+                                   out);
+}
+static struct shash_alg alg = {
+       .setkey         = adler32_setkey,
+       .init           = adler32_init,
+       .update         = adler32_update,
+       .final          = adler32_final,
+       .finup          = adler32_finup,
+       .digest         = adler32_digest,
+       .descsize       = sizeof(u32),
+       .digestsize     = CHKSUM_DIGEST_SIZE,
+       .base           = {
+               .cra_name               = "adler32",
+               .cra_driver_name        = "adler32-zlib",
+               .cra_priority           = 100,
+               .cra_blocksize          = CHKSUM_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(u32),
+               .cra_module             = THIS_MODULE,
+               .cra_init               = adler32_cra_init,
+       }
+};
+#else   /* HAVE_STRUCT_SHASH_ALG */
+#ifdef HAVE_DIGEST_SETKEY_FLAGS
+static int adler32_digest_setkey(struct crypto_tfm *tfm, const u8 *key,
+                                unsigned int keylen, u32 *flags)
+#else
+static int adler32_digest_setkey(struct crypto_tfm *tfm, const u8 *key,
+                                unsigned int keylen)
+#endif
+{
+       u32 *mctx = crypto_tfm_ctx(tfm);
+
+       if (keylen != sizeof(u32)) {
+               tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+       *mctx = le32_to_cpup((__le32 *)key);
+       return 0;
+}
+
+static void adler32_digest_init(struct crypto_tfm *tfm)
+{
+       u32 *mctx = crypto_tfm_ctx(tfm);
+
+       *mctx = 0;
+
+}
+static void adler32_digest_update(struct crypto_tfm *tfm, const u8 *data,
+                                 unsigned int len)
+{
+       u32 *crcp = crypto_tfm_ctx(tfm);
+
+       *crcp = __adler32(*crcp, data, len);
+}
+
+static void adler32_digest_final(struct crypto_tfm *tfm, u8 *out)
+{
+       u32 *chksum = crypto_tfm_ctx(tfm);
+
+       *(__le32 *)out = cpu_to_le32p(chksum);
+}
+
+static struct crypto_alg alg = {
+       .cra_name               = "adler32",
+       .cra_flags              = CRYPTO_ALG_TYPE_DIGEST,
+       .cra_driver_name        = "adler32-zlib",
+       .cra_priority           = 100,
+       .cra_blocksize          = CHKSUM_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(u32),
+       .cra_module             = THIS_MODULE,
+       .cra_init               = adler32_cra_init,
+       .cra_list               = LIST_HEAD_INIT(alg.cra_list),
+       .cra_u                  = {
+               .digest         = {
+                               .dia_digestsize = CHKSUM_DIGEST_SIZE,
+                               .dia_setkey     = adler32_digest_setkey,
+                               .dia_init       = adler32_digest_init,
+                               .dia_update     = adler32_digest_update,
+                               .dia_final      = adler32_digest_final
+               }
+       }
+};
+#endif  /* HAVE_STRUCT_SHASH_ALG */
+
+
+int cfs_crypto_adler32_register(void)
+{
+#ifdef HAVE_STRUCT_SHASH_ALG
+       return crypto_register_shash(&alg);
+#else
+       return crypto_register_alg(&alg);
+#endif
+}
+EXPORT_SYMBOL(cfs_crypto_adler32_register);
+
+void cfs_crypto_adler32_unregister(void)
+{
+#ifdef HAVE_STRUCT_SHASH_ALG
+       crypto_unregister_shash(&alg);
+#else
+       crypto_unregister_alg(&alg);
+#endif
+}
+EXPORT_SYMBOL(cfs_crypto_adler32_unregister);
diff --git a/libcfs/libcfs/linux/linux-crypto-crc32.c b/libcfs/libcfs/linux/linux-crypto-crc32.c
new file mode 100644 (file)
index 0000000..0c8fc25
--- /dev/null
@@ -0,0 +1,223 @@
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please  visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ */
+
+/*
+ * This is crypto api shash wrappers to crc32_le.
+ */
+
+#include <linux/crc32.h>
+#ifdef HAVE_STRUCT_SHASH_ALG
+#include <crypto/internal/hash.h>
+#else
+#include <linux/crypto.h>
+#endif
+
+#define CHKSUM_BLOCK_SIZE      1
+#define CHKSUM_DIGEST_SIZE     4
+
+static u32 __crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+       return crc32_le(crc, p, len);
+}
+
+/** No default init with ~0 */
+static int crc32_cra_init(struct crypto_tfm *tfm)
+{
+       u32 *key = crypto_tfm_ctx(tfm);
+
+       *key = 0;
+
+       return 0;
+}
+
+
+#ifdef HAVE_STRUCT_SHASH_ALG
+/*
+ * Setting the seed allows arbitrary accumulators and flexible XOR policy
+ * If your algorithm starts with ~0, then XOR with ~0 before you set
+ * the seed.
+ */
+static int crc32_setkey(struct crypto_shash *hash, const u8 *key,
+                       unsigned int keylen)
+{
+       u32 *mctx = crypto_shash_ctx(hash);
+
+       if (keylen != sizeof(u32)) {
+               crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+               return -EINVAL;
+       }
+       *mctx = le32_to_cpup((__le32 *)key);
+       return 0;
+}
+
+static int crc32_init(struct shash_desc *desc)
+{
+       u32 *mctx = crypto_shash_ctx(desc->tfm);
+       u32 *crcp = shash_desc_ctx(desc);
+
+       *crcp = *mctx;
+
+       return 0;
+}
+
+static int crc32_update(struct shash_desc *desc, const u8 *data,
+                       unsigned int len)
+{
+       u32 *crcp = shash_desc_ctx(desc);
+
+       *crcp = __crc32_le(*crcp, data, len);
+       return 0;
+}
+/* No final XOR 0xFFFFFFFF, like crc32_le */
+static int __crc32_finup(u32 *crcp, const u8 *data, unsigned int len,
+                        u8 *out)
+{
+       *(__le32 *)out = cpu_to_le32(__crc32_le(*crcp, data, len));
+       return 0;
+}
+
+static int crc32_finup(struct shash_desc *desc, const u8 *data,
+                      unsigned int len, u8 *out)
+{
+       return __crc32_finup(shash_desc_ctx(desc), data, len, out);
+}
+
+static int crc32_final(struct shash_desc *desc, u8 *out)
+{
+       u32 *crcp = shash_desc_ctx(desc);
+
+       *(__le32 *)out = cpu_to_le32p(crcp);
+       return 0;
+}
+
+static int crc32_digest(struct shash_desc *desc, const u8 *data,
+                       unsigned int len, u8 *out)
+{
+       return __crc32_finup(crypto_shash_ctx(desc->tfm), data, len,
+                            out);
+}
+static struct shash_alg alg = {
+       .setkey         = crc32_setkey,
+       .init           = crc32_init,
+       .update         = crc32_update,
+       .final          = crc32_final,
+       .finup          = crc32_finup,
+       .digest         = crc32_digest,
+       .descsize       = sizeof(u32),
+       .digestsize     = CHKSUM_DIGEST_SIZE,
+       .base           = {
+               .cra_name               = "crc32",
+               .cra_driver_name        = "crc32-table",
+               .cra_priority           = 100,
+               .cra_blocksize          = CHKSUM_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(u32),
+               .cra_module             = THIS_MODULE,
+               .cra_init               = crc32_cra_init,
+       }
+};
+#else   /* HAVE_STRUCT_SHASH_ALG */
+#ifdef HAVE_DIGEST_SETKEY_FLAGS
+static int crc32_digest_setkey(struct crypto_tfm *tfm, const u8 *key,
+                              unsigned int keylen, unsigned int *flags)
+#else
+static int crc32_digest_setkey(struct crypto_tfm *tfm, const u8 *key,
+                              unsigned int keylen)
+#endif
+{
+       u32 *mctx = crypto_tfm_ctx(tfm);
+
+       if (keylen != sizeof(u32)) {
+               tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+       *mctx = le32_to_cpup((__le32 *)key);
+       return 0;
+}
+
+static void crc32_digest_init(struct crypto_tfm *tfm)
+{
+       u32 *mctx = crypto_tfm_ctx(tfm);
+
+       *mctx = 0;
+
+}
+static void crc32_digest_update(struct crypto_tfm *tfm, const u8 *data,
+                               unsigned int len)
+{
+       u32 *crcp = crypto_tfm_ctx(tfm);
+
+       *crcp = __crc32_le(*crcp, data, len);
+}
+
+static void crc32_digest_final(struct crypto_tfm *tfm, u8 *out)
+{
+       u32 *crcp = crypto_tfm_ctx(tfm);
+
+       *(__le32 *)out = cpu_to_le32p(crcp);
+}
+
+static struct crypto_alg alg = {
+       .cra_name               = "crc32",
+       .cra_flags              = CRYPTO_ALG_TYPE_DIGEST,
+       .cra_driver_name        = "crc32-table",
+       .cra_priority           = 100,
+       .cra_blocksize          = CHKSUM_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(u32),
+       .cra_module             = THIS_MODULE,
+       .cra_init               = crc32_cra_init,
+       .cra_list               = LIST_HEAD_INIT(alg.cra_list),
+       .cra_u                  = {
+               .digest         = {
+                       .dia_digestsize = CHKSUM_DIGEST_SIZE,
+                       .dia_setkey     = crc32_digest_setkey,
+                       .dia_init       = crc32_digest_init,
+                       .dia_update     = crc32_digest_update,
+                       .dia_final      = crc32_digest_final
+               }
+       }
+};
+#endif  /* HAVE_STRUCT_SHASH_ALG */
+
+int cfs_crypto_crc32_register(void)
+{
+#ifdef HAVE_STRUCT_SHASH_ALG
+       return crypto_register_shash(&alg);
+#else
+       return crypto_register_alg(&alg);
+#endif
+}
+EXPORT_SYMBOL(cfs_crypto_crc32_register);
+
+void cfs_crypto_crc32_unregister(void)
+{
+#ifdef HAVE_STRUCT_SHASH_ALG
+       crypto_unregister_shash(&alg);
+#else
+       crypto_unregister_alg(&alg);
+#endif
+}
+EXPORT_SYMBOL(cfs_crypto_crc32_unregister);
diff --git a/libcfs/libcfs/linux/linux-crypto.c b/libcfs/libcfs/linux/linux-crypto.c
new file mode 100644 (file)
index 0000000..245fca2
--- /dev/null
@@ -0,0 +1,358 @@
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please  visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ */
+
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <libcfs/libcfs.h>
+#include <libcfs/linux/linux-crypto.h>
+/**
+ *  Array of  hash algorithm speed in MByte per second
+ */
+static int cfs_crypto_hash_speeds[CFS_HASH_ALG_MAX];
+
+
+#ifndef HAVE_STRUCT_HASH_DESC
+/** 2.6.18 kernel have no crypto_hash function
+ *  this part was copied from lustre_compat25.h */
+#define crypto_hash     crypto_tfm
+struct hash_desc {
+       struct crypto_hash      *tfm;
+       unsigned int            flags;
+};
+
+static inline
+struct crypto_hash *crypto_alloc_hash(const char *alg, unsigned int type,
+                                     unsigned int mask)
+{
+       return crypto_alloc_tfm(alg, 0);
+}
+
+static inline void crypto_free_hash(struct crypto_hash *tfm)
+{
+       crypto_free_tfm(tfm);
+}
+
+static inline int crypto_hash_init(struct hash_desc *desc)
+{
+       crypto_digest_init(desc->tfm);
+       return 0;
+}
+
+static inline int crypto_hash_update(struct hash_desc *desc,
+                                    struct scatterlist *sg,
+                                    unsigned int nbytes)
+{
+       if (desc->tfm->crt_digest.dit_update == NULL)
+               return -1;
+
+       LASSERT(nbytes == sg->length);
+       crypto_digest_update(desc->tfm, sg, 1);
+
+       return 0;
+}
+
+static inline int crypto_hash_digest(struct hash_desc *desc,
+                                    struct scatterlist *sg,
+                                    unsigned int nbytes, unsigned char *out)
+{
+       crypto_hash_update(desc, sg, nbytes);
+       crypto_digest_final(desc->tfm, out);
+       return 0;
+}
+
+static inline int crypto_hash_final(struct hash_desc *desc, unsigned char *out)
+{
+       crypto_digest_final(desc->tfm, out);
+       return 0;
+}
+
+static inline struct crypto_tfm *crypto_hash_tfm(struct crypto_hash *tfm)
+{
+       return tfm;
+}
+
+#define crypto_hash_setkey(tfm, key, keylen) \
+               crypto_digest_setkey(tfm, key, keylen)
+#define crypto_hash_digestsize(tfm)  crypto_tfm_alg_digestsize(tfm)
+#define crypto_hash_blocksize(tfm)   crypto_tfm_alg_blocksize(tfm)
+#endif
+
+static int cfs_crypto_hash_alloc(unsigned char alg_id,
+                                const struct cfs_crypto_hash_type **type,
+                                struct hash_desc *desc, unsigned char *key,
+                                unsigned int key_len)
+{
+       int     err = 0;
+
+       *type = cfs_crypto_hash_type(alg_id);
+
+       if (*type == NULL) {
+               CWARN("Unsupported hash algorithm id = %d, max id is %d\n",
+                     alg_id, CFS_HASH_ALG_MAX);
+               return -EINVAL;
+       }
+       desc->tfm = crypto_alloc_hash((*type)->cht_name, 0, 0);
+
+       if (desc->tfm == NULL)
+               return -EINVAL;
+
+       if (IS_ERR(desc->tfm)) {
+               CDEBUG(D_INFO, "Failed to alloc crypto hash %s\n",
+                      (*type)->cht_name);
+               return PTR_ERR(desc->tfm);
+       }
+
+       desc->flags = 0;
+
+       /** Shash have different logic for initialization then digest
+        * shash: crypto_hash_setkey, crypto_hash_init
+        * digest: crypto_digest_init, crypto_digest_setkey
+        * Skip this function for digest, because we use shash logic at
+        * cfs_crypto_hash_alloc.
+        */
+#ifndef HAVE_STRUCT_SHASH_ALG
+       crypto_hash_init(desc);
+#endif
+       if (key != NULL) {
+               err = crypto_hash_setkey(desc->tfm, key, key_len);
+       } else if ((*type)->cht_key != 0) {
+               err = crypto_hash_setkey(desc->tfm,
+                                        (unsigned char *)&((*type)->cht_key),
+                                        (*type)->cht_size);
+       }
+
+       if (err != 0) {
+               crypto_free_hash(desc->tfm);
+               return err;
+       }
+
+       CDEBUG(D_INFO, "Using crypto hash: %s (%s) speed %d MB/s\n",
+              (crypto_hash_tfm(desc->tfm))->__crt_alg->cra_name,
+              (crypto_hash_tfm(desc->tfm))->__crt_alg->cra_driver_name,
+              cfs_crypto_hash_speeds[alg_id]);
+
+#ifdef HAVE_STRUCT_SHASH_ALG
+       return crypto_hash_init(desc);
+#else
+       return 0;
+#endif
+}
+
+int cfs_crypto_hash_digest(unsigned char alg_id,
+                          const void *buf, unsigned int buf_len,
+                          unsigned char *key, unsigned int key_len,
+                          unsigned char *hash, unsigned int *hash_len)
+{
+       struct scatterlist      sl = {0};
+       struct hash_desc        hdesc;
+       int                     err;
+       const struct cfs_crypto_hash_type       *type;
+
+       if (buf == NULL || buf_len == 0 || hash_len == NULL)
+               return -EINVAL;
+
+       err = cfs_crypto_hash_alloc(alg_id, &type, &hdesc, key, key_len);
+       if (err != 0)
+               return err;
+
+       if (hash == NULL || *hash_len < type->cht_size) {
+               *hash_len = type->cht_size;
+               crypto_free_hash(hdesc.tfm);
+               return -ENOSPC;
+       }
+       sg_set_buf(&sl, (void *)buf, buf_len);
+
+       hdesc.flags = 0;
+       err = crypto_hash_digest(&hdesc, &sl, sl.length, hash);
+       crypto_free_hash(hdesc.tfm);
+
+       return err;
+}
+EXPORT_SYMBOL(cfs_crypto_hash_digest);
+
+struct cfs_crypto_hash_desc *
+       cfs_crypto_hash_init(unsigned char alg_id,
+                            unsigned char *key, unsigned int key_len)
+{
+
+       struct  hash_desc       *hdesc;
+       int                  err;
+       const struct cfs_crypto_hash_type       *type;
+
+       hdesc = cfs_alloc(sizeof(*hdesc), 0);
+       if (hdesc == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       err = cfs_crypto_hash_alloc(alg_id, &type, hdesc, key, key_len);
+
+       if (err) {
+               cfs_free(hdesc);
+               return ERR_PTR(err);
+       }
+       return (struct cfs_crypto_hash_desc *)hdesc;
+}
+EXPORT_SYMBOL(cfs_crypto_hash_init);
+
+int cfs_crypto_hash_update_page(struct cfs_crypto_hash_desc *hdesc,
+                               cfs_page_t *page, unsigned int offset,
+                               unsigned int len)
+{
+       struct scatterlist      sl = {0};
+
+       sg_set_page(&sl, page, len, offset & ~CFS_PAGE_MASK);
+
+       return crypto_hash_update((struct hash_desc *)hdesc, &sl, sl.length);
+}
+EXPORT_SYMBOL(cfs_crypto_hash_update_page);
+
+int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *hdesc,
+                          const void *buf, unsigned int buf_len)
+{
+       struct scatterlist      sl = {0};
+
+       sg_set_buf(&sl, (void *)buf, buf_len);
+
+       return crypto_hash_update((struct hash_desc *)hdesc, &sl, sl.length);
+}
+EXPORT_SYMBOL(cfs_crypto_hash_update);
+
+/*      If hash_len pointer is NULL - destroy descriptor. */
+int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *hdesc,
+                         unsigned char *hash, unsigned int *hash_len)
+{
+       int     err;
+       int     size = crypto_hash_digestsize(((struct hash_desc *)hdesc)->tfm);
+
+       if (hash_len == NULL) {
+               crypto_free_hash(((struct hash_desc *)hdesc)->tfm);
+               return 0;
+       }
+       if (hash == NULL || *hash_len < size) {
+               *hash_len = size;
+               return -ENOSPC;
+       }
+       err = crypto_hash_final((struct hash_desc *) hdesc, hash);
+
+       if (err < 0) {
+               /* May be caller can fix error */
+               return err;
+       }
+       crypto_free_hash(((struct hash_desc *)hdesc)->tfm);
+       return err;
+}
+EXPORT_SYMBOL(cfs_crypto_hash_final);
+
+static void cfs_crypto_performance_test(unsigned char alg_id,
+                                       const unsigned char *buf,
+                                       unsigned int buf_len)
+{
+       unsigned long              start, end;
+       int                          bcount, err = 0;
+       int                          sec = 1; /* do test only 1 sec */
+       unsigned char              hash[64];
+       unsigned int                hash_len = 64;
+
+       for (start = jiffies, end = start + sec * HZ, bcount = 0;
+            time_before(jiffies, end); bcount++) {
+               err = cfs_crypto_hash_digest(alg_id, buf, buf_len, NULL, 0,
+                                            hash, &hash_len);
+               if (err)
+                       break;
+
+       }
+       end = jiffies;
+
+       if (err) {
+               cfs_crypto_hash_speeds[alg_id] =  -1;
+               CDEBUG(D_INFO, "Crypto hash algorithm %s, err = %d\n",
+                      cfs_crypto_hash_name(alg_id), err);
+       } else {
+               unsigned long   tmp;
+               tmp = ((bcount * buf_len / jiffies_to_msecs(end - start)) *
+                      1000) / (1024 * 1024);
+               cfs_crypto_hash_speeds[alg_id] = (int)tmp;
+       }
+       CDEBUG(D_INFO, "Crypto hash algorithm %s speed = %d MB/s\n",
+              cfs_crypto_hash_name(alg_id), cfs_crypto_hash_speeds[alg_id]);
+}
+
+int cfs_crypto_hash_speed(unsigned char hash_alg)
+{
+       if (hash_alg < CFS_HASH_ALG_MAX)
+               return cfs_crypto_hash_speeds[hash_alg];
+       else
+               return -1;
+}
+EXPORT_SYMBOL(cfs_crypto_hash_speed);
+
+/**
+ * Do performance test for all hash algorithms.
+ */
+static int cfs_crypto_test_hashes(void)
+{
+       unsigned char      i;
+       unsigned char      *data;
+       unsigned int        j;
+       /* Data block size for testing hash. Maximum
+        * kmalloc size for 2.6.18 kernel is 128K */
+       unsigned int        data_len = 1 * 128 * 1024;
+
+       data = cfs_alloc(data_len, 0);
+       if (data == NULL) {
+               CERROR("Failed to allocate mem\n");
+               return -ENOMEM;
+       }
+
+       for (j = 0; j < data_len; j++)
+               data[j] = j & 0xff;
+
+       for (i = 0; i < CFS_HASH_ALG_MAX; i++)
+               cfs_crypto_performance_test(i, data, data_len);
+
+       cfs_free(data);
+       return 0;
+}
+
+static int crc32, adler32;
+
+int cfs_crypto_register(void)
+{
+       crc32 = cfs_crypto_crc32_register();
+       adler32 = cfs_crypto_adler32_register();
+
+       /* check all algorithms and do perfermance test */
+       cfs_crypto_test_hashes();
+       return 0;
+}
+void cfs_crypto_unregister(void)
+{
+       if (crc32 == 0)
+               cfs_crypto_crc32_unregister();
+       if (adler32 == 0)
+               cfs_crypto_adler32_unregister();
+       return;
+}
index 6640ab1..b6cb94f 100644 (file)
@@ -35,6 +35,7 @@
 #define DEBUG_SUBSYSTEM S_LNET
 
 #include <libcfs/libcfs.h>
+#include <libcfs/libcfs_crypto.h>
 #include <lnet/lib-lnet.h>
 #include <lnet/lnet.h>
 #include "tracefile.h"
@@ -374,38 +375,38 @@ extern void libcfs_arch_cleanup(void);
 
 static int init_libcfs_module(void)
 {
-        int rc;
-
-        libcfs_arch_init();
-        libcfs_init_nidstrings();
-        cfs_init_rwsem(&cfs_tracefile_sem);
-        cfs_mutex_init(&cfs_trace_thread_mutex);
-        cfs_init_rwsem(&ioctl_list_sem);
-        CFS_INIT_LIST_HEAD(&ioctl_list);
-        cfs_waitq_init(&cfs_race_waitq);
-
-        rc = libcfs_debug_init(5 * 1024 * 1024);
-        if (rc < 0) {
-                printk(CFS_KERN_ERR "LustreError: libcfs_debug_init: %d\n", rc);
-                return (rc);
-        }
+       int rc;
+
+       libcfs_arch_init();
+       libcfs_init_nidstrings();
+       cfs_init_rwsem(&cfs_tracefile_sem);
+       cfs_mutex_init(&cfs_trace_thread_mutex);
+       cfs_init_rwsem(&ioctl_list_sem);
+       CFS_INIT_LIST_HEAD(&ioctl_list);
+       cfs_waitq_init(&cfs_race_waitq);
+
+       rc = libcfs_debug_init(5 * 1024 * 1024);
+       if (rc < 0) {
+               printk(CFS_KERN_ERR "LustreError: libcfs_debug_init: %d\n", rc);
+               return (rc);
+       }
 
        rc = cfs_cpu_init();
        if (rc != 0)
                goto cleanup_debug;
 
 #if LWT_SUPPORT
-        rc = lwt_init();
-        if (rc != 0) {
-                CERROR("lwt_init: error %d\n", rc);
-                goto cleanup_debug;
-        }
+       rc = lwt_init();
+       if (rc != 0) {
+               CERROR("lwt_init: error %d\n", rc);
+               goto cleanup_debug;
+       }
 #endif
-        rc = cfs_psdev_register(&libcfs_dev);
-        if (rc) {
-                CERROR("misc_register: error %d\n", rc);
-                goto cleanup_lwt;
-        }
+       rc = cfs_psdev_register(&libcfs_dev);
+       if (rc) {
+               CERROR("misc_register: error %d\n", rc);
+               goto cleanup_lwt;
+       }
 
        rc = cfs_wi_startup();
        if (rc) {
@@ -422,66 +423,75 @@ static int init_libcfs_module(void)
                goto cleanup_deregister;
        }
 
-        rc = insert_proc();
-        if (rc) {
-                CERROR("insert_proc: error %d\n", rc);
-                goto cleanup_wi;
-        }
+       rc = cfs_crypto_register();
+       if (rc) {
+               CERROR("cfs_crypto_regster: error %d\n", rc);
+               goto cleanup_wi;
+       }
+
 
-        CDEBUG (D_OTHER, "portals setup OK\n");
-        return (0);
+       rc = insert_proc();
+       if (rc) {
+               CERROR("insert_proc: error %d\n", rc);
+               goto cleanup_crypto;
+       }
 
+       CDEBUG (D_OTHER, "portals setup OK\n");
+       return 0;
+ cleanup_crypto:
+       cfs_crypto_unregister();
  cleanup_wi:
-        cfs_wi_shutdown();
+       cfs_wi_shutdown();
  cleanup_deregister:
-        cfs_psdev_deregister(&libcfs_dev);
+       cfs_psdev_deregister(&libcfs_dev);
  cleanup_lwt:
 #if LWT_SUPPORT
-        lwt_fini();
+       lwt_fini();
 #endif
  cleanup_debug:
-        libcfs_debug_cleanup();
-        return rc;
+       libcfs_debug_cleanup();
+       return rc;
 }
 
 static void exit_libcfs_module(void)
 {
-        int rc;
+       int rc;
 
-        remove_proc();
+       remove_proc();
 
-        CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
-               cfs_atomic_read(&libcfs_kmemory));
+       CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
+              cfs_atomic_read(&libcfs_kmemory));
 
        if (cfs_sched_rehash != NULL) {
                cfs_wi_sched_destroy(cfs_sched_rehash);
                cfs_sched_rehash = NULL;
        }
 
+       cfs_crypto_unregister();
        cfs_wi_shutdown();
 
-        rc = cfs_psdev_deregister(&libcfs_dev);
-        if (rc)
-                CERROR("misc_deregister error %d\n", rc);
+       rc = cfs_psdev_deregister(&libcfs_dev);
+       if (rc)
+               CERROR("misc_deregister error %d\n", rc);
 
 #if LWT_SUPPORT
-        lwt_fini();
+       lwt_fini();
 #endif
        cfs_cpu_fini();
 
-        if (cfs_atomic_read(&libcfs_kmemory) != 0)
-                CERROR("Portals memory leaked: %d bytes\n",
-                       cfs_atomic_read(&libcfs_kmemory));
+       if (cfs_atomic_read(&libcfs_kmemory) != 0)
+               CERROR("Portals memory leaked: %d bytes\n",
+                      cfs_atomic_read(&libcfs_kmemory));
 
-        rc = libcfs_debug_cleanup();
-        if (rc)
-                printk(CFS_KERN_ERR "LustreError: libcfs_debug_cleanup: %d\n",
-                       rc);
+       rc = libcfs_debug_cleanup();
+       if (rc)
+               printk(CFS_KERN_ERR "LustreError: libcfs_debug_cleanup: %d\n",
+                      rc);
 
-        cfs_fini_rwsem(&ioctl_list_sem);
-        cfs_fini_rwsem(&cfs_tracefile_sem);
+       cfs_fini_rwsem(&ioctl_list_sem);
+       cfs_fini_rwsem(&cfs_tracefile_sem);
 
-        libcfs_arch_cleanup();
+       libcfs_arch_cleanup();
 }
 
 cfs_module(libcfs, "1.0.0", init_libcfs_module, exit_libcfs_module);
diff --git a/libcfs/libcfs/posix/posix-adler.c b/libcfs/libcfs/posix/posix-adler.c
new file mode 100644 (file)
index 0000000..36931d4
--- /dev/null
@@ -0,0 +1,83 @@
+/*   Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+        claim that you wrote the original software. If you use this software
+        in a product, an acknowledgment in the product documentation would be
+        appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+        misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly     Mark Adler
+  jloup@gzip.org         madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+#include <libcfs/libcfs.h>
+
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf, i)  {s1 += buf[i]; s2 += s1; }
+#define DO2(buf, i)  DO1(buf, i); DO1(buf, i + 1);
+#define DO4(buf, i)  DO2(buf, i); DO2(buf, i + 2);
+#define DO8(buf, i)  DO4(buf, i); DO4(buf, i + 4);
+#define DO16(buf)      DO8(buf, 0); DO8(buf, 8);
+
+/* ========================================================================= */
+/*
+        Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+        uLong adler = adler32(0L, NULL, 0);
+
+        while (read_buffer(buffer, length) != EOF) {
+          adler = adler32(adler, buffer, length);
+        }
+        if (adler != original_adler) error();
+*/
+unsigned long zlib_adler32(unsigned long adler,
+                          const unsigned char *buf,
+                          unsigned int len)
+{
+       unsigned long s1 = adler & 0xffff;
+       unsigned long s2 = (adler >> 16) & 0xffff;
+       int k;
+
+       if (buf == NULL)
+               return 1L;
+
+       while (len > 0) {
+               k = len < NMAX ? len : NMAX;
+               len -= k;
+               while (k >= 16) {
+                       DO16(buf);
+                       buf += 16;
+                       k -= 16;
+               }
+               if (k != 0)
+                       do {
+                               s1 += *buf++;
+                               s2 += s1;
+                       } while (--k);
+               s1 %= BASE;
+               s2 %= BASE;
+       }
+       return (s2 << 16) | s1;
+}
diff --git a/libcfs/libcfs/posix/posix-crc32.c b/libcfs/libcfs/posix/posix-crc32.c
new file mode 100644 (file)
index 0000000..972c5ff
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *      This file contains part of linux kernel implementation of crc32
+ *      kernel version 2.6.32
+ */
+#include <libcfs/libcfs.h>
+#define CRCPOLY_LE      0xedb88320
+#define CRC_LE_BITS     8
+#define LE_TABLE_SIZE   (1 << CRC_LE_BITS)
+
+static unsigned int crc32table_le[LE_TABLE_SIZE];
+/**
+ * crc32init_le() - allocate and initialize LE table data
+ *
+ * crc is the crc of the byte i; other entries are filled in based on the
+ * fact that crctable[i^j] = crctable[i] ^ crctable[j].
+ *
+ */
+void crc32init_le(void)
+{
+       unsigned i, j;
+       unsigned int crc = 1;
+
+       crc32table_le[0] = 0;
+
+       for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
+               crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+               for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
+                       crc32table_le[i + j] = crc ^ crc32table_le[j];
+       }
+}
+
+unsigned int crc32_le(unsigned int crc, unsigned char const *p, size_t len)
+{
+       const unsigned int      *b = (unsigned int *)p;
+       const unsigned int      *tab = crc32table_le;
+
+# ifdef __LITTLE_ENDIAN
+#  define DO_CRC(x) crc = tab[(crc ^ (x)) & 255] ^ (crc>>8)
+# else
+#  define DO_CRC(x) crc = tab[((crc >> 24) ^ (x)) & 255] ^ (crc<<8)
+# endif
+
+       crc = cpu_to_le32(crc);
+       /* Align it */
+       if (unlikely(((long)b) & 3 && len)) {
+               do {
+                       unsigned char *p = (unsigned char *)b;
+                       DO_CRC(*p++);
+                       b = (void *)p;
+               } while ((--len) && ((long)b) & 3);
+       }
+       if (likely(len >= 4)) {
+               /* load data 32 bits wide, xor data 32 bits wide. */
+               size_t save_len = len & 3;
+               len = len >> 2;
+               --b; /* use pre increment below(*++b) for speed */
+               do {
+                       crc ^= *++b;
+                       DO_CRC(0);
+                       DO_CRC(0);
+                       DO_CRC(0);
+                       DO_CRC(0);
+               } while (--len);
+               b++; /* point to next byte(s) */
+               len = save_len;
+       }
+       /* And the last few bytes */
+       if (len) {
+               do {
+                       unsigned char *p = (unsigned char *)b;
+                       DO_CRC(*p++);
+                       b = (void *)p;
+               } while (--len);
+       }
+
+       return le32_to_cpu(crc);
+#undef DO_CRC
+}
diff --git a/libcfs/libcfs/user-crypto.c b/libcfs/libcfs/user-crypto.c
new file mode 100644 (file)
index 0000000..66d0bae
--- /dev/null
@@ -0,0 +1,396 @@
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please  visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ */
+
+/*
+ * Libcfs crypto hash interfaces for user mode.
+ */
+
+#include <libcfs/libcfs.h>
+#include <libcfs/posix/posix-crypto.h>
+
+static int cfs_crypto_hash_speeds[CFS_HASH_ALG_MAX];
+
+struct __hash_alg {
+       /**
+        * Initialization of algorithm
+        */
+       int (*init)(void);
+       /**
+        * Start function for the hash instance
+        */
+       int (*start)(void *ctx, unsigned char *p, unsigned int len);
+       /**
+        * Partial update checksum
+        */
+       int (*update)(void *ctx, const unsigned char *p, unsigned int len);
+       /**
+        * Final function for the instance destroy context and copy digest
+        */
+       int (*final)(void *ctx, unsigned char *p, unsigned int len);
+       /**
+        * Destroy algorithm
+        */
+       void (*fini)(void);
+       unsigned int    ha_ctx_size;    /**< size of context */
+       unsigned int    ha_priority;    /**< implementation priority
+                                            defined by developer
+                                            to get one from equal algorithm */
+       unsigned char   ha_id;    /**< algorithm identifier */
+};
+
+struct hash_desc {
+       const struct __hash_alg *hd_hash;
+       unsigned char   hd_ctx[0];
+};
+
+static int crc32_update_wrapper(void *ctx, const unsigned char *p,
+                               unsigned int len)
+{
+       unsigned int crc = *(unsigned int *)ctx;
+
+       crc = crc32_le(crc, p, len);
+
+       *(unsigned int *)ctx = crc;
+       return 0;
+}
+
+static int adler_wrapper(void *ctx, const unsigned char *p,
+                               unsigned int len)
+{
+       unsigned int cksum = *(unsigned int *)ctx;
+
+       cksum = zlib_adler32(cksum, p, len);
+
+       *(unsigned int *)ctx = cksum;
+       return 0;
+}
+
+static int start_generic(void *ctx, unsigned char *key,
+                                        unsigned int key_len)
+{
+       const struct cfs_crypto_hash_type       *type;
+       struct hash_desc        *hd = container_of(ctx, struct hash_desc,
+                                                  hd_ctx);
+       type = cfs_crypto_hash_type(hd->hd_hash->ha_id);
+       LASSERT(type != NULL);
+
+       /* copy key to context */
+       if (key && key_len == hd->hd_hash->ha_ctx_size) {
+               memcpy(ctx, key, key_len);
+       } else if (type->cht_key != 0) {
+               memcpy(ctx, &type->cht_key, type->cht_size);
+       } else {
+               CWARN("Invalid key or key_len, zero context\n");
+               memset(ctx, 0, hd->hd_hash->ha_ctx_size);
+       }
+       return 0;
+}
+
+static int final_generic(void *ctx, unsigned char *hash,
+                                        unsigned int hash_len)
+{
+       const struct cfs_crypto_hash_type       *type;
+       struct hash_desc        *hd = container_of(ctx, struct hash_desc,
+                                                  hd_ctx);
+       type = cfs_crypto_hash_type(hd->hd_hash->ha_id);
+       LASSERT(type != NULL);
+        /* copy context to out hash */
+       LASSERT(hd->hd_hash->ha_ctx_size == type->cht_size);
+       memcpy(hash, ctx, hd->hd_hash->ha_ctx_size);
+
+
+       return 0;
+}
+
+static struct __hash_alg crypto_hash[] = {
+                                         {.ha_id = CFS_HASH_ALG_CRC32,
+                                          .ha_ctx_size = sizeof(unsigned int),
+                                          .ha_priority = 10,
+                                          .init = crc32init_le,
+                                          .update = crc32_update_wrapper,
+                                          .start = start_generic,
+                                          .final = final_generic,
+                                          .fini = NULL},
+                                         {.ha_id = CFS_HASH_ALG_ADLER32,
+                                          .ha_ctx_size = sizeof(unsigned int),
+                                          .ha_priority = 10,
+                                          .init = NULL,
+                                          .update = adler_wrapper,
+                                          .start = start_generic,
+                                          .final = final_generic,
+                                          .fini = NULL} };
+
+/**
+ * Go through hashes to find the hash with  max priority
+ * for the alg_id algorithm. This is done for different  implementation
+ * of the same algorithm. Priotity is staticaly defined by developer, and
+ * can be zeroed if initialization of algo is unsuccessfull.
+ */
+static const struct __hash_alg *cfs_crypto_hash_best_alg(unsigned char alg_id)
+{
+       int max_priority = 0;
+       const struct __hash_alg *alg = NULL;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(crypto_hash); i++) {
+               if (alg_id == crypto_hash[i].ha_id &&
+                   max_priority < crypto_hash[i].ha_priority) {
+                       max_priority = crypto_hash[i].ha_priority;
+                       alg = &crypto_hash[i];
+               }
+       }
+
+       return alg;
+}
+
+struct cfs_crypto_hash_desc
+       *cfs_crypto_hash_init(unsigned char alg,
+                             unsigned char *key, unsigned int key_len)
+{
+       struct hash_desc                        *hdesc = NULL;
+       const struct cfs_crypto_hash_type       *type;
+       const struct __hash_alg                 *ha = NULL;
+       int                                     err;
+
+       type = cfs_crypto_hash_type(alg);
+       if (type == NULL) {
+               CWARN("Unsupported hash algorithm id = %d, max id is %d\n",
+                     alg, CFS_HASH_ALG_MAX);
+               return ERR_PTR(-EINVAL);
+       }
+
+       ha = cfs_crypto_hash_best_alg(alg);
+       if (ha == NULL) {
+               CERROR("Failed to get hash algorithm\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       hdesc = cfs_alloc(sizeof(*hdesc) + ha->ha_ctx_size, 0);
+       if (hdesc == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       hdesc->hd_hash = ha;
+
+       if (ha->start != NULL) {
+               err = ha->start(hdesc->hd_ctx, key, key_len);
+               if (err == 0) {
+                       return (struct cfs_crypto_hash_desc *) hdesc;
+               } else {
+                       cfs_free(hdesc);
+                       return ERR_PTR(err);
+               }
+       }
+
+       return (struct cfs_crypto_hash_desc *) hdesc;
+}
+
+int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *desc, const void *buf,
+                          unsigned int buf_len)
+{
+       struct hash_desc *d = (struct hash_desc *)desc;
+       return d->hd_hash->update(d->hd_ctx, buf, buf_len);
+}
+
+int cfs_crypto_hash_update_page(struct cfs_crypto_hash_desc *desc,
+                               cfs_page_t *page, unsigned int offset,
+                               unsigned int len)
+{
+       const void *p = page->addr + offset;
+
+       return cfs_crypto_hash_update(desc, p, len);
+}
+
+/**
+ *      To get final hash and destroy cfs_crypto_hash_desc, caller
+ *      should use valid hash buffer with enougth len for hash.
+ *      If hash_len pointer is NULL - destroy descriptor.
+ */
+int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *desc,
+                         unsigned char *hash, unsigned int *hash_len)
+{
+       struct hash_desc        *d = (struct hash_desc *)desc;
+       int     size = (cfs_crypto_hash_type(d->hd_hash->ha_id))->cht_size;
+       int     err;
+
+       if (hash_len == NULL) {
+               cfs_free(d);
+               return 0;
+       }
+       if (hash == NULL || *hash_len < size) {
+               *hash_len = d->hd_hash->ha_ctx_size;
+               return -ENOMEM;
+       }
+
+       LASSERT(d->hd_hash->final != NULL);
+       err = d->hd_hash->final(d->hd_ctx, hash, *hash_len);
+       if (err == 0) {
+                 /* If get final digest success free hash descriptor */
+                 cfs_free(d);
+       }
+
+       return err;
+}
+
+int cfs_crypto_hash_digest(unsigned char alg,
+                          const void *buf, unsigned int buf_len,
+                          unsigned char *key, unsigned int key_len,
+                          unsigned char *hash, unsigned int *hash_len)
+{
+       struct cfs_crypto_hash_desc      *desc;
+       int                          err;
+
+       desc = cfs_crypto_hash_init(alg, key, key_len);
+
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       err = cfs_crypto_hash_update(desc, buf, buf_len);
+       if (err) {
+               cfs_crypto_hash_final(desc, NULL, NULL);
+               return err;
+       }
+       err = cfs_crypto_hash_final(desc, hash, hash_len);
+       if (err != 0)
+               cfs_crypto_hash_final(desc, NULL, NULL);
+       return err;
+}
+
+
+static void cfs_crypto_start_timer(struct timeval *start)
+{
+       gettimeofday(start, NULL);
+       return;
+}
+
+/** return usec */
+static long cfs_crypto_get_sec(struct timeval *start)
+{
+       struct timeval  end;
+
+       gettimeofday(&end, NULL);
+
+       return cfs_timeval_sub(&end, start, NULL);
+}
+
+static void cfs_crypto_performance_test(unsigned char alg_id,
+                                       const unsigned char *buf,
+                                       unsigned int buf_len)
+{
+       struct timeval            start;
+       int                          bcount, err, msec;
+       int                          iteration = 400; /* do test 400 times */
+       unsigned char              hash[64];
+       unsigned int                hash_len = 64;
+
+       cfs_crypto_start_timer(&start);
+       for (bcount = 0; bcount < iteration; bcount++) {
+               err = cfs_crypto_hash_digest(alg_id, buf, buf_len, NULL, 0,
+                                            hash, &hash_len);
+               if (err)
+                       break;
+
+       }
+
+       msec = (int)(cfs_crypto_get_sec(&start) / 1000.0);
+       if (err) {
+               cfs_crypto_hash_speeds[alg_id] =  -1;
+               CDEBUG(D_INFO, "Crypto hash algorithm err = %d\n", err);
+       } else {
+               long tmp;
+               tmp =  ((bcount * buf_len / msec) * 1000) / (1024 * 1024);
+               cfs_crypto_hash_speeds[alg_id] = (int)tmp;
+       }
+       CDEBUG(D_INFO, "Crypto hash algorithm %s speed = %d MB/s\n",
+              cfs_crypto_hash_name(alg_id), cfs_crypto_hash_speeds[alg_id]);
+}
+
+int cfs_crypto_hash_speed(unsigned char hash_alg)
+{
+       if (hash_alg < CFS_HASH_ALG_MAX)
+               return cfs_crypto_hash_speeds[hash_alg];
+       else
+               return -1;
+}
+
+/**
+ * Do performance test for all hash algorithms.
+ */
+static int cfs_crypto_test_hashes(void)
+{
+       unsigned char      i;
+       unsigned char      *data;
+       unsigned int        j, data_len = 1024 * 1024;
+
+       data = cfs_alloc(data_len, 0);
+       if (data == NULL) {
+               CERROR("Failed to allocate mem\n");
+               return -ENOMEM;
+       }
+       for (j = 0; j < data_len; j++)
+               data[j] = j & 0xff;
+
+       for (i = 0; i < CFS_HASH_ALG_MAX; i++)
+               cfs_crypto_performance_test(i, data, data_len);
+
+       cfs_free(data);
+       return 0;
+}
+
+/**
+ *      Register crypto hash algorithms
+ */
+int cfs_crypto_register(void)
+{
+       int i, err;
+       for (i = 0; i < ARRAY_SIZE(crypto_hash); i++) {
+               if (crypto_hash[i].init == NULL)
+                       continue;
+               err = crypto_hash[i].init();
+               if (err < 0) {
+                       crypto_hash[i].ha_priority = 0;
+                       CWARN("Failed to initialize hash %s, error %d\n",
+                             cfs_crypto_hash_name(crypto_hash[i].ha_id), err);
+               }
+       }
+
+       cfs_crypto_test_hashes();
+       return 0;
+}
+
+/**
+ *      Unregister
+ */
+void cfs_crypto_unregister(void)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(crypto_hash); i++) {
+               if (crypto_hash[i].fini == NULL)
+                       continue;
+               if (crypto_hash[i].ha_priority > 0)
+                       crypto_hash[i].fini();
+       }
+}
index 690deba..2dd1aae 100644 (file)
@@ -41,8 +41,7 @@ linux_HEADERS = lustre_user.h
 endif
 
 EXTRA_DIST = lprocfs_status.h lustre_acl.h lustre_debug.h lustre_lib.h \
-     lustre_dlm.h  lustre_handles.h lustre_net.h obd_class.h obd_support.h \
-     lustre_log.h lustre_compat25.h lustre_fsfilt.h lustre_mds.h \
-     obd.h lvfs.h lvfs_linux.h lustre_lite.h lustre_quota.h \
-     lustre_user.h lustre_patchless_compat.h lustre_intent.h \
-     obd_cksum.h
+       lustre_dlm.h  lustre_handles.h lustre_net.h obd_class.h obd_support.h \
+       lustre_log.h lustre_compat25.h lustre_fsfilt.h lustre_mds.h \
+       obd.h lvfs.h lvfs_linux.h lustre_lite.h lustre_quota.h \
+       lustre_user.h lustre_patchless_compat.h lustre_intent.h
diff --git a/lustre/include/linux/obd_cksum.h b/lustre/include/linux/obd_cksum.h
deleted file mode 100644 (file)
index aedbc23..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, Whamcloud, Inc.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- */
-
-#ifndef __LINUX_OBD_CKSUM
-#define __LINUX_OBD_CKSUM
-
-#ifndef __OBD_CKSUM
-#error Do not #include this file directly. #include <obd_chsum.h> instead
-#endif
-
-#include <libcfs/libcfs.h>
-
-/* Prefer the kernel's version, if it exports it, because it might be
- * optimized for this CPU. */
-#if defined(__KERNEL__) && (defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE))
-# include <linux/crc32.h>
-# define HAVE_ARCH_CRC32
-#endif
-
-#ifdef __KERNEL__
-# include <linux/zutil.h>
-# ifndef HAVE_ADLER
-#  define HAVE_ADLER
-# endif
-# define adler32(a,b,l) zlib_adler32(a,b,l)
-#else /*  __KERNEL__ */
-# ifdef HAVE_ADLER
-#  include <zlib.h>
-# endif
-#endif /*! __KERNEL__ */
-
-#endif
index fab2299..6c4207c 100644 (file)
@@ -883,13 +883,6 @@ enum sptlrpc_bulk_hash_alg {
         BULK_HASH_ALG_MAX
 };
 
-struct sptlrpc_hash_type {
-        char           *sht_name;
-        char           *sht_tfm_name;
-        unsigned int    sht_size;
-};
-
-const struct sptlrpc_hash_type *sptlrpc_get_hash_type(__u8 hash_alg);
 const char * sptlrpc_get_hash_name(__u8 hash_alg);
 __u8 sptlrpc_get_hash_alg(const char *algname);
 
index 7166f7a..d546bb8 100644 (file)
 
 #ifndef __OBD_CKSUM
 #define __OBD_CKSUM
-
-#if defined(__linux__)
-#include <linux/obd_cksum.h>
-#elif defined(__APPLE__)
-#include <darwin/obd_chksum.h>
-#elif defined(__WINNT__)
-#include <winnt/obd_cksum.h>
-#else
-#error Unsupported operating system.
-#endif
-
+#include <libcfs/libcfs.h>
 #include <lustre/lustre_idl.h>
 
-/*
- * Checksums
- */
-
-#ifndef HAVE_ARCH_CRC32
-/* crc32_le lifted from the Linux kernel, which had the following to say:
- *
- * This code is in the public domain; copyright abandoned.
- * Liability for non-performance of this code is limited to the amount
- * you paid for it.  Since it is distributed for free, your refund will
- * be very very small.  If it breaks, you get to keep both pieces.
- */
-#define CRCPOLY_LE 0xedb88320
-/**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * \param crc  seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *             other uses, or the previous crc32 value if computing incrementally.
- * \param p  - pointer to buffer over which CRC is run
- * \param len- length of buffer \a p
- */
-static inline __u32 crc32_le(__u32 crc, unsigned char const *p, size_t len)
-{
-        int i;
-        while (len--) {
-                crc ^= *p++;
-                for (i = 0; i < 8; i++)
-                        crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
-        }
-        return crc;
-}
-#endif
-#ifdef HAVE_ADLER
-/* Adler-32 is supported */
-#define CHECKSUM_ADLER OBD_CKSUM_ADLER
-#else
-#define CHECKSUM_ADLER 0
-#endif
-
-#ifdef X86_FEATURE_XMM4_2
-/* Call Nehalem+ CRC32C harware acceleration instruction on individual bytes. */
-static inline __u32 crc32c_hw_byte(__u32 crc, unsigned char const *p,
-                                  size_t bytes)
+static inline unsigned char cksum_obd2cfs(cksum_type_t cksum_type)
 {
-        while (bytes--) {
-                __asm__ __volatile__ (
-                        ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
-                        : "=S"(crc)
-                        : "0"(crc), "c"(*p)
-                );
-                p++;
-        }
-
-        return crc;
-}
-
-#if BITS_PER_LONG > 32
-#define WORD_SHIFT 3
-#define WORD_MASK  7
-#define REX "0x48, "
-#else
-#define WORD_SHIFT 2
-#define WORD_MASK  3
-#define REX ""
-#endif
-
-/* Do we need to worry about unaligned input data here? */
-static inline __u32 crc32c_hw(__u32 crc, unsigned char const *p, size_t len)
-{
-        unsigned int words = len >> WORD_SHIFT;
-        unsigned int bytes = len &  WORD_MASK;
-        long *ptmp = (long *)p;
-
-        while (words--) {
-                __asm__ __volatile__(
-                        ".byte 0xf2, " REX "0xf, 0x38, 0xf1, 0xf1;"
-                        : "=S"(crc)
-                        : "0"(crc), "c"(*ptmp)
-                );
-                ptmp++;
-        }
-
-        if (bytes)
-                crc = crc32c_hw_byte(crc, (unsigned char *)ptmp, bytes);
-
-        return crc;
-}
-#else
-/* We should never call this unless the CPU has previously been detected to
- * support this instruction in the SSE4.2 feature set. b=23549  */
-static inline __u32 crc32c_hw(__u32 crc, unsigned char const *p,size_t len)
-{
-        LBUG();
-}
-#endif
-
-static inline __u32 init_checksum(cksum_type_t cksum_type)
-{
-        switch(cksum_type) {
-        case OBD_CKSUM_CRC32C:
-                return ~0U;
-#ifdef HAVE_ADLER
-        case OBD_CKSUM_ADLER:
-                return 1U;
-#endif
-        case OBD_CKSUM_CRC32:
-                return ~0U;
-        default:
-                CERROR("Unknown checksum type (%x)!!!\n", cksum_type);
-                LBUG();
-        }
-        return 0;
-}
-
-static inline __u32 fini_checksum(__u32 cksum, cksum_type_t cksum_type)
-{
-        if (cksum_type == OBD_CKSUM_CRC32C)
-                return ~cksum;
-        return cksum;
-}
-
-static inline __u32 compute_checksum(__u32 cksum, unsigned char const *p,
-                                     size_t len, cksum_type_t cksum_type)
-{
-        switch(cksum_type) {
-        case OBD_CKSUM_CRC32C:
-                return crc32c_hw(cksum, p, len);
-#ifdef HAVE_ADLER
-        case OBD_CKSUM_ADLER:
-                return adler32(cksum, p, len);
-#endif
-        case OBD_CKSUM_CRC32:
-                return crc32_le(cksum, p, len);
-        default:
-                CERROR("Unknown checksum type (%x)!!!\n", cksum_type);
-                LBUG();
-        }
-        return 0;
+       switch (cksum_type) {
+       case OBD_CKSUM_CRC32:
+               return CFS_HASH_ALG_CRC32;
+       case OBD_CKSUM_ADLER:
+               return CFS_HASH_ALG_ADLER32;
+       case OBD_CKSUM_CRC32C:
+               return CFS_HASH_ALG_CRC32C;
+       default:
+               CERROR("Unknown checksum type (%x)!!!\n", cksum_type);
+               LBUG();
+       }
+       return 0;
 }
 
 /* The OBD_FL_CKSUM_* flags is packed into 5 bits of o_flags, since there can
@@ -194,79 +60,113 @@ static inline __u32 compute_checksum(__u32 cksum, unsigned char const *p,
  * since they need to represent the full range of checksum algorithms that
  * both the client and server can understand.
  *
- * In case of an unsupported types/flags we fall back to CRC32 (even though
- * it isn't very fast) because that is supported by all clients
- * checksums, since 1.6.5 (or earlier via patches).
+ * In case of an unsupported types/flags we fall back to ADLER
+ * because that is supported by all clients since 1.8
  *
- * These flags should be listed in order of descending performance, so that
- * in case multiple algorithms are supported the best one is used. */
+ * In case multiple algorithms are supported the best one is used. */
 static inline obd_flag cksum_type_pack(cksum_type_t cksum_type)
 {
-        if (cksum_type & OBD_CKSUM_CRC32C)
-                return OBD_FL_CKSUM_CRC32C;
-#ifdef HAVE_ADLER
-        if (cksum_type & OBD_CKSUM_ADLER)
-                return OBD_FL_CKSUM_ADLER;
-#endif
-        if (unlikely(cksum_type && !(cksum_type & OBD_CKSUM_CRC32)))
-                CWARN("unknown cksum type %x\n", cksum_type);
-
-        return OBD_FL_CKSUM_CRC32;
+       unsigned int    performance = 0, tmp;
+       obd_flag        flag = OBD_FL_CKSUM_ADLER;
+
+       if (cksum_type & OBD_CKSUM_CRC32) {
+               tmp = cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32));
+               if (tmp > performance) {
+                       performance = tmp;
+                       flag = OBD_FL_CKSUM_CRC32;
+               }
+       }
+       if (cksum_type & OBD_CKSUM_CRC32C) {
+               tmp = cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C));
+               if (tmp > performance) {
+                       performance = tmp;
+                       flag = OBD_FL_CKSUM_CRC32C;
+               }
+       }
+       if (cksum_type & OBD_CKSUM_ADLER) {
+               tmp = cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_ADLER));
+               if (tmp > performance) {
+                       performance = tmp;
+                       flag = OBD_FL_CKSUM_ADLER;
+               }
+       }
+       if (unlikely(cksum_type && !(cksum_type & (OBD_CKSUM_CRC32C |
+                                                  OBD_CKSUM_CRC32 |
+                                                  OBD_CKSUM_ADLER))))
+               CWARN("unknown cksum type %x\n", cksum_type);
+
+       return flag;
 }
 
 static inline cksum_type_t cksum_type_unpack(obd_flag o_flags)
 {
-        switch (o_flags & OBD_FL_CKSUM_ALL) {
-        case OBD_FL_CKSUM_CRC32C:
-                return OBD_CKSUM_CRC32C;
-        case OBD_FL_CKSUM_ADLER:
-#ifdef HAVE_ADLER
-                return OBD_CKSUM_ADLER;
-#else
-                CWARN("checksum type is set to adler32, but adler32 is not "
-                      "supported (%x)\n", o_flags);
-                break;
-#endif
-        default:
-                break;
-        }
-
-        /* 1.6.4- only supported CRC32 and didn't set o_flags */
-        return OBD_CKSUM_CRC32;
+       switch (o_flags & OBD_FL_CKSUM_ALL) {
+       case OBD_FL_CKSUM_CRC32C:
+               return OBD_CKSUM_CRC32C;
+       case OBD_FL_CKSUM_CRC32:
+               return OBD_CKSUM_CRC32;
+       default:
+               break;
+       }
+
+       return OBD_CKSUM_ADLER;
 }
 
 /* Return a bitmask of the checksum types supported on this system.
- *
- * CRC32 is a required for compatibility (starting with 1.6.5),
- * after which we could move to Adler as the base checksum type.
- *
- * If hardware crc32c support is not available, it is slower than Adler,
- * so don't include it, even if it could be emulated in software. b=23549 */
-static inline cksum_type_t cksum_types_supported(void)
+ * 1.8 supported ADLER it is base and not depend on hw
+ * Client uses all available local algos
+ */
+static inline cksum_type_t cksum_types_supported_client(void)
 {
-        cksum_type_t ret = OBD_CKSUM_CRC32;
+       cksum_type_t ret = OBD_CKSUM_ADLER;
+
+       CDEBUG(D_INFO, "Crypto hash speed: crc %d, crc32c %d, adler %d\n",
+              cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)),
+              cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)),
+              cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_ADLER)));
+
+       if (cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)) > 0)
+               ret |= OBD_CKSUM_CRC32C;
+       if (cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)) > 0)
+               ret |= OBD_CKSUM_CRC32;
 
-#ifdef X86_FEATURE_XMM4_2
-        if (cpu_has_xmm4_2)
-                ret |= OBD_CKSUM_CRC32C;
-#endif
-#ifdef HAVE_ADLER
-        ret |= OBD_CKSUM_ADLER;
-#endif
-        return ret;
+       return ret;
 }
 
+/* Server uses algos that perform at 50% or better of the Adler */
+static inline cksum_type_t cksum_types_supported_server(void)
+{
+       int          base_speed;
+       cksum_type_t    ret = OBD_CKSUM_ADLER;
+
+       CDEBUG(D_INFO, "Crypto hash speed: crc %d, crc32c %d, adler %d\n",
+              cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)),
+              cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)),
+              cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_ADLER)));
+
+       base_speed = cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_ADLER)) / 2;
+
+       if (cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)) >=
+           base_speed)
+               ret |= OBD_CKSUM_CRC32C;
+       if (cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)) >=
+           base_speed)
+               ret |= OBD_CKSUM_CRC32;
+
+       return ret;
+}
+
+
 /* Select the best checksum algorithm among those supplied in the cksum_types
  * input.
  *
  * Currently, calling cksum_type_pack() with a mask will return the fastest
- * checksum type due to its ordering, but in the future we might want to
- * determine this based on benchmarking the different algorithms quickly.
+ * checksum type due to its benchmarking at libcfs module load.
  * Caution is advised, however, since what is fastest on a single client may
  * not be the fastest or most efficient algorithm on the server.  */
 static inline cksum_type_t cksum_type_select(cksum_type_t cksum_types)
 {
-        return cksum_type_unpack(cksum_type_pack(cksum_types));
+       return cksum_type_unpack(cksum_type_pack(cksum_types));
 }
 
 /* Checksum algorithm names. Must be defined in the same order as the
index 1ce9807..4c89098 100644 (file)
@@ -399,10 +399,10 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
                  * agreement on the supported algorithms at connect time */
                 data->ocd_connect_flags |= OBD_CONNECT_CKSUM;
 
-                if (OBD_FAIL_CHECK(OBD_FAIL_OSC_CKSUM_ADLER_ONLY))
-                        data->ocd_cksum_types = OBD_CKSUM_ADLER;
-                else
-                        data->ocd_cksum_types = cksum_types_supported();
+               if (OBD_FAIL_CHECK(OBD_FAIL_OSC_CKSUM_ADLER_ONLY))
+                       data->ocd_cksum_types = OBD_CKSUM_ADLER;
+               else
+                       data->ocd_cksum_types = cksum_types_supported_client();
         }
 
 #ifdef HAVE_LRU_RESIZE_SUPPORT
index 79d137f..c2b58cb 100644 (file)
@@ -730,7 +730,7 @@ int mds_lov_connect(struct obd_device *obd, char * lov_name)
         /* send max bytes per rpc */
         data->ocd_brw_size = PTLRPC_MAX_BRW_PAGES << CFS_PAGE_SHIFT;
         /* send the list of supported checksum types */
-        data->ocd_cksum_types = cksum_types_supported();
+       data->ocd_cksum_types = cksum_types_supported_client();
         /* NB: lov_connect() needs to fill in .ocd_index for each OST */
         rc = obd_connect(NULL, &mds->mds_lov_exp, mds->mds_lov_obd, &obd->obd_uuid, data, NULL);
         OBD_FREE(data, sizeof(*data));
index dfb7d2f..70e8d52 100644 (file)
@@ -2777,11 +2777,9 @@ static int filter_connect_internal(struct obd_export *exp,
                 /* The client set in ocd_cksum_types the checksum types it
                  * supports. We have to mask off the algorithms that we don't
                  * support */
-                data->ocd_cksum_types &= cksum_types_supported();
+               data->ocd_cksum_types &= cksum_types_supported_server();
 
-                /* 1.6.4- only support CRC32 and didn't set ocd_cksum_types */
-                if (unlikely(data->ocd_cksum_types == 0))
-                        data->ocd_cksum_types = OBD_CKSUM_CRC32;
+               /* 1.6.4 clients are not supported any more */
 
                 CDEBUG(D_RPCTRACE, "%s: cli %s supports cksum type %x, return "
                                    "%x\n", exp->exp_obd->obd_name,
index a7cd74c..415bfe8 100644 (file)
@@ -213,7 +213,7 @@ static int ofd_parse_connect_data(const struct lu_env *env,
                /* The client set in ocd_cksum_types the checksum types it
                 * supports. We have to mask off the algorithms that we don't
                 * support */
-               data->ocd_cksum_types &= cksum_types_supported();
+               data->ocd_cksum_types &= cksum_types_supported_server();
 
                if (unlikely(data->ocd_cksum_types == 0)) {
                        CERROR("%s: Connect with checksum support but no "
index b52d974..879b30c 100644 (file)
@@ -1141,39 +1141,60 @@ static inline int can_merge_pages(struct brw_page *p1, struct brw_page *p2)
 }
 
 static obd_count osc_checksum_bulk(int nob, obd_count pg_count,
-                                   struct brw_page **pga, int opc,
-                                   cksum_type_t cksum_type)
-{
-        __u32 cksum;
-        int i = 0;
+                                  struct brw_page **pga, int opc,
+                                  cksum_type_t cksum_type)
+{
+       __u32                           cksum;
+       int                             i = 0;
+       struct cfs_crypto_hash_desc     *hdesc;
+       unsigned int                    bufsize;
+       int                             err;
+       unsigned char                   cfs_alg = cksum_obd2cfs(cksum_type);
+
+       LASSERT(pg_count > 0);
+
+       hdesc = cfs_crypto_hash_init(cfs_alg, NULL, 0);
+       if (IS_ERR(hdesc)) {
+               CERROR("Unable to initialize checksum hash %s\n",
+                      cfs_crypto_hash_name(cfs_alg));
+               return PTR_ERR(hdesc);
+       }
 
-        LASSERT (pg_count > 0);
-        cksum = init_checksum(cksum_type);
-        while (nob > 0 && pg_count > 0) {
-                unsigned char *ptr = cfs_kmap(pga[i]->pg);
-                int off = pga[i]->off & ~CFS_PAGE_MASK;
-                int count = pga[i]->count > nob ? nob : pga[i]->count;
-
-                /* corrupt the data before we compute the checksum, to
-                 * simulate an OST->client data error */
-                if (i == 0 && opc == OST_READ &&
-                    OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_RECEIVE))
-                        memcpy(ptr + off, "bad1", min(4, nob));
-                cksum = compute_checksum(cksum, ptr + off, count, cksum_type);
-                cfs_kunmap(pga[i]->pg);
-                LL_CDEBUG_PAGE(D_PAGE, pga[i]->pg, "off %d checksum %x\n",
-                               off, cksum);
+       while (nob > 0 && pg_count > 0) {
+               int count = pga[i]->count > nob ? nob : pga[i]->count;
+
+               /* corrupt the data before we compute the checksum, to
+                * simulate an OST->client data error */
+               if (i == 0 && opc == OST_READ &&
+                   OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_RECEIVE)) {
+                       unsigned char *ptr = cfs_kmap(pga[i]->pg);
+                       int off = pga[i]->off & ~CFS_PAGE_MASK;
+                       memcpy(ptr + off, "bad1", min(4, nob));
+                       cfs_kunmap(pga[i]->pg);
+               }
+               cfs_crypto_hash_update_page(hdesc, pga[i]->pg,
+                                 pga[i]->off & ~CFS_PAGE_MASK,
+                                 count);
+               LL_CDEBUG_PAGE(D_PAGE, pga[i]->pg, "off %d checksum %x\n",
+                              (int)(pga[i]->off & ~CFS_PAGE_MASK), cksum);
+
+               nob -= pga[i]->count;
+               pg_count--;
+               i++;
+       }
 
-                nob -= pga[i]->count;
-                pg_count--;
-                i++;
-        }
-        /* For sending we only compute the wrong checksum instead
-         * of corrupting the data so it is still correct on a redo */
-        if (opc == OST_WRITE && OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_SEND))
-                cksum++;
+       bufsize = 4;
+       err = cfs_crypto_hash_final(hdesc, (unsigned char *)&cksum, &bufsize);
+
+       if (err)
+               cfs_crypto_hash_final(hdesc, NULL, NULL);
+
+       /* For sending we only compute the wrong checksum instead
+        * of corrupting the data so it is still correct on a redo */
+       if (opc == OST_WRITE && OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_SEND))
+               cksum++;
 
-        return fini_checksum(cksum, cksum_type);
+       return cksum;
 }
 
 static int osc_brw_prep_request(int cmd, struct client_obd *cli,struct obdo *oa,
index 20cd111..179b127 100644 (file)
@@ -521,36 +521,57 @@ static int ost_setattr(struct obd_export *exp, struct ptlrpc_request *req,
 }
 
 static __u32 ost_checksum_bulk(struct ptlrpc_bulk_desc *desc, int opc,
-                               cksum_type_t cksum_type)
+                              cksum_type_t cksum_type)
 {
-        __u32 cksum;
-        int i;
+       struct cfs_crypto_hash_desc     *hdesc;
+       unsigned int                    bufsize;
+       int                             i, err;
+       unsigned char                   cfs_alg = cksum_obd2cfs(cksum_type);
+       __u32                           cksum;
+
+       hdesc = cfs_crypto_hash_init(cfs_alg, NULL, 0);
+       if (IS_ERR(hdesc)) {
+               CERROR("Unable to initialize checksum hash %s\n",
+                      cfs_crypto_hash_name(cfs_alg));
+               return PTR_ERR(hdesc);
+       }
+       CDEBUG(D_INFO, "Checksum for algo %s\n", cfs_crypto_hash_name(cfs_alg));
+       for (i = 0; i < desc->bd_iov_count; i++) {
+
+               /* corrupt the data before we compute the checksum, to
+                * simulate a client->OST data error */
+               if (i == 0 && opc == OST_WRITE &&
+                   OBD_FAIL_CHECK(OBD_FAIL_OST_CHECKSUM_RECEIVE)) {
+                       int off = desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK;
+                       int len = desc->bd_iov[i].kiov_len;
+                       char *ptr = kmap(desc->bd_iov[i].kiov_page) + off;
+                       memcpy(ptr, "bad3", min(4, len));
+                       kunmap(desc->bd_iov[i].kiov_page);
+               }
+               cfs_crypto_hash_update_page(hdesc, desc->bd_iov[i].kiov_page,
+                                 desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK,
+                                 desc->bd_iov[i].kiov_len);
+
+                /* corrupt the data after we compute the checksum, to
+                * simulate an OST->client data error */
+               if (i == 0 && opc == OST_READ &&
+                   OBD_FAIL_CHECK(OBD_FAIL_OST_CHECKSUM_SEND)) {
+                       int off = desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK;
+                       int len = desc->bd_iov[i].kiov_len;
+                       char *ptr = kmap(desc->bd_iov[i].kiov_page) + off;
+                       memcpy(ptr, "bad4", min(4, len));
+                       kunmap(desc->bd_iov[i].kiov_page);
+                       /* nobody should use corrupted page again */
+                       ClearPageUptodate(desc->bd_iov[i].kiov_page);
+               }
+       }
 
-        cksum = init_checksum(cksum_type);
-        for (i = 0; i < desc->bd_iov_count; i++) {
-                struct page *page = desc->bd_iov[i].kiov_page;
-                int off = desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK;
-                char *ptr = kmap(page) + off;
-                int len = desc->bd_iov[i].kiov_len;
-
-                /* corrupt the data before we compute the checksum, to
-                 * simulate a client->OST data error */
-                if (i == 0 && opc == OST_WRITE &&
-                    OBD_FAIL_CHECK(OBD_FAIL_OST_CHECKSUM_RECEIVE))
-                        memcpy(ptr, "bad3", min(4, len));
-                cksum = compute_checksum(cksum, ptr, len, cksum_type);
-                /* corrupt the data after we compute the checksum, to
-                 * simulate an OST->client data error */
-                if (i == 0 && opc == OST_READ &&
-                    OBD_FAIL_CHECK(OBD_FAIL_OST_CHECKSUM_SEND)) {
-                        memcpy(ptr, "bad4", min(4, len));
-                        /* nobody should use corrupted page again */
-                        ClearPageUptodate(page);
-                }
-                kunmap(page);
-        }
+       bufsize = 4;
+       err = cfs_crypto_hash_final(hdesc, (unsigned char *)&cksum, &bufsize);
+       if (err)
+               cfs_crypto_hash_final(hdesc, NULL, NULL);
 
-        return fini_checksum(cksum, cksum_type);
+       return cksum;
 }
 
 static int ost_brw_lock_get(int mode, struct obd_export *exp,
index 7e68efb..4ef4afe 100644 (file)
@@ -1024,28 +1024,29 @@ finish:
                                       newer : older, LUSTRE_VERSION_STRING);
                 }
 
-                if (ocd->ocd_connect_flags & OBD_CONNECT_CKSUM) {
-                        /* We sent to the server ocd_cksum_types with bits set
-                         * for algorithms we understand. The server masked off
-                         * the checksum types it doesn't support */
-                        if ((ocd->ocd_cksum_types & cksum_types_supported()) == 0) {
-                                LCONSOLE_WARN("The negotiation of the checksum "
-                                              "alogrithm to use with server %s "
-                                              "failed (%x/%x), disabling "
-                                              "checksums\n",
-                                              obd2cli_tgt(imp->imp_obd),
-                                              ocd->ocd_cksum_types,
-                                              cksum_types_supported());
-                                cli->cl_checksum = 0;
-                                cli->cl_supp_cksum_types = OBD_CKSUM_CRC32;
-                        } else {
-                                cli->cl_supp_cksum_types = ocd->ocd_cksum_types;
-                        }
-                } else {
-                        /* The server does not support OBD_CONNECT_CKSUM.
-                         * Enforce CRC32 for backward compatibility*/
-                        cli->cl_supp_cksum_types = OBD_CKSUM_CRC32;
-                }
+               if (ocd->ocd_connect_flags & OBD_CONNECT_CKSUM) {
+                       /* We sent to the server ocd_cksum_types with bits set
+                        * for algorithms we understand. The server masked off
+                        * the checksum types it doesn't support */
+                       if ((ocd->ocd_cksum_types &
+                            cksum_types_supported_client()) == 0) {
+                               LCONSOLE_WARN("The negotiation of the checksum "
+                                             "alogrithm to use with server %s "
+                                             "failed (%x/%x), disabling "
+                                             "checksums\n",
+                                             obd2cli_tgt(imp->imp_obd),
+                                             ocd->ocd_cksum_types,
+                                             cksum_types_supported_client());
+                               cli->cl_checksum = 0;
+                               cli->cl_supp_cksum_types = OBD_CKSUM_ADLER;
+                       } else {
+                               cli->cl_supp_cksum_types = ocd->ocd_cksum_types;
+                       }
+               } else {
+                       /* The server does not support OBD_CONNECT_CKSUM.
+                        * Enforce ADLER for backward compatibility*/
+                       cli->cl_supp_cksum_types = OBD_CKSUM_ADLER;
+               }
                 cli->cl_cksum_type =cksum_type_select(cli->cl_supp_cksum_types);
 
                 if (ocd->ocd_connect_flags & OBD_CONNECT_BRW_SIZE)
index edc835d..e20a03d 100644 (file)
@@ -1300,24 +1300,33 @@ __u32 lustre_msg_calc_cksum(struct lustre_msg *msg, int compat18)
 __u32 lustre_msg_calc_cksum(struct lustre_msg *msg)
 #endif
 {
-        switch (msg->lm_magic) {
-        case LUSTRE_MSG_MAGIC_V2: {
-                struct ptlrpc_body *pb = lustre_msg_ptlrpc_body(msg);
+       switch (msg->lm_magic) {
+       case LUSTRE_MSG_MAGIC_V2: {
+               struct ptlrpc_body *pb = lustre_msg_ptlrpc_body(msg);
 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 0, 0)
-                __u32 len = compat18 ? ptlrpc_body_cksum_size_compat18 :
-                            lustre_msg_buflen(msg, MSG_PTLRPC_BODY_OFF);
-                LASSERTF(pb, "invalid msg %p: no ptlrpc body!\n", msg);
-                return crc32_le(~(__u32)0, (unsigned char *)pb, len);
+               __u32 crc;
+               unsigned int hsize = 4;
+               __u32 len = compat18 ? ptlrpc_body_cksum_size_compat18 :
+                           lustre_msg_buflen(msg, MSG_PTLRPC_BODY_OFF);
+               LASSERTF(pb, "invalid msg %p: no ptlrpc body!\n", msg);
+               cfs_crypto_hash_digest(CFS_HASH_ALG_CRC32, (unsigned char *)pb,
+                                      len, NULL, 0, (unsigned char *)&crc,
+                                      &hsize);
+               return crc;
 #else
 # warning "remove checksum compatibility support for b1_8"
-                return crc32_le(~(__u32)0, (unsigned char *)pb,
-                                lustre_msg_buflen(msg, MSG_PTLRPC_BODY_OFF));
+               __u32 crc;
+               unsigned int hsize = 4;
+               cfs_crypto_hash_digest(CFS_HASH_ALG_CRC32, (unsigned char *)pb,
+                                  lustre_msg_buflen(msg, MSG_PTLRPC_BODY_OFF),
+                                  NULL, 0, (unsigned char *)&crc, &hsize);
+               return crc;
 #endif
-        }
-        default:
-                CERROR("incorrect message magic: %08x\n", msg->lm_magic);
-                return 0;
-        }
+       }
+       default:
+               CERROR("incorrect message magic: %08x\n", msg->lm_magic);
+               return 0;
+       }
 }
 
 void lustre_msg_set_handle(struct lustre_msg *msg, struct lustre_handle *handle)
index bfce3e1..a9eaccb 100644 (file)
@@ -803,55 +803,25 @@ void sptlrpc_enc_pool_fini(void)
 }
 #endif
 
-/****************************************
- * Helpers to assist policy modules to  *
- * implement checksum funcationality    *
- ****************************************/
-
-static struct sptlrpc_hash_type hash_types[] = {
-        [BULK_HASH_ALG_NULL]    = { "null",     "null",         0 },
-        [BULK_HASH_ALG_ADLER32] = { "adler32",  "adler32",      4 },
-        [BULK_HASH_ALG_CRC32]   = { "crc32",    "crc32",        4 },
-        [BULK_HASH_ALG_MD5]     = { "md5",      "md5",          16 },
-        [BULK_HASH_ALG_SHA1]    = { "sha1",     "sha1",         20 },
-        [BULK_HASH_ALG_SHA256]  = { "sha256",   "sha256",       32 },
-        [BULK_HASH_ALG_SHA384]  = { "sha384",   "sha384",       48 },
-        [BULK_HASH_ALG_SHA512]  = { "sha512",   "sha512",       64 },
+static int cfs_hash_alg_id[] = {
+       [BULK_HASH_ALG_NULL]    = CFS_HASH_ALG_NULL,
+       [BULK_HASH_ALG_ADLER32] = CFS_HASH_ALG_ADLER32,
+       [BULK_HASH_ALG_CRC32]   = CFS_HASH_ALG_CRC32,
+       [BULK_HASH_ALG_MD5]     = CFS_HASH_ALG_MD5,
+       [BULK_HASH_ALG_SHA1]    = CFS_HASH_ALG_SHA1,
+       [BULK_HASH_ALG_SHA256]  = CFS_HASH_ALG_SHA256,
+       [BULK_HASH_ALG_SHA384]  = CFS_HASH_ALG_SHA384,
+       [BULK_HASH_ALG_SHA512]  = CFS_HASH_ALG_SHA512,
 };
-
-const struct sptlrpc_hash_type *sptlrpc_get_hash_type(__u8 hash_alg)
-{
-        struct sptlrpc_hash_type *ht;
-
-        if (hash_alg < BULK_HASH_ALG_MAX) {
-                ht = &hash_types[hash_alg];
-                if (ht->sht_tfm_name)
-                        return ht;
-        }
-        return NULL;
-}
-EXPORT_SYMBOL(sptlrpc_get_hash_type);
-
 const char * sptlrpc_get_hash_name(__u8 hash_alg)
 {
-        const struct sptlrpc_hash_type *ht;
-
-        ht = sptlrpc_get_hash_type(hash_alg);
-        if (ht)
-                return ht->sht_name;
-        else
-                return "unknown";
+       return cfs_crypto_hash_name(cfs_hash_alg_id[hash_alg]);
 }
 EXPORT_SYMBOL(sptlrpc_get_hash_name);
 
 __u8 sptlrpc_get_hash_alg(const char *algname)
 {
-        int     i;
-
-        for (i = 0; i < BULK_HASH_ALG_MAX; i++)
-                if (!strcmp(hash_types[i].sht_name, algname))
-                        break;
-        return i;
+       return cfs_crypto_hash_alg(algname);
 }
 EXPORT_SYMBOL(sptlrpc_get_hash_alg);
 
@@ -893,149 +863,52 @@ int bulk_sec_desc_unpack(struct lustre_msg *msg, int offset, int swabbed)
 }
 EXPORT_SYMBOL(bulk_sec_desc_unpack);
 
-#ifdef __KERNEL__
-
-#ifdef HAVE_ADLER
-static int do_bulk_checksum_adler32(struct ptlrpc_bulk_desc *desc, void *buf)
-{
-        struct page    *page;
-        int             off;
-        char           *ptr;
-        __u32           adler32 = 1;
-        int             len, i;
-
-        for (i = 0; i < desc->bd_iov_count; i++) {
-                page = desc->bd_iov[i].kiov_page;
-                off = desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK;
-                ptr = cfs_kmap(page) + off;
-                len = desc->bd_iov[i].kiov_len;
-
-                adler32 = adler32(adler32, ptr, len);
-
-                cfs_kunmap(page);
-        }
-
-        adler32 = cpu_to_le32(adler32);
-        memcpy(buf, &adler32, sizeof(adler32));
-        return 0;
-}
-#endif
-
-static int do_bulk_checksum_crc32(struct ptlrpc_bulk_desc *desc, void *buf)
+int sptlrpc_get_bulk_checksum(struct ptlrpc_bulk_desc *desc, __u8 alg,
+                             void *buf, int buflen)
 {
-        struct page    *page;
-        int             off;
-        char           *ptr;
-        __u32           crc32 = ~0;
-        int             len, i;
-
-        for (i = 0; i < desc->bd_iov_count; i++) {
-                page = desc->bd_iov[i].kiov_page;
-                off = desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK;
-                ptr = cfs_kmap(page) + off;
-                len = desc->bd_iov[i].kiov_len;
+       struct cfs_crypto_hash_desc     *hdesc;
+       int                             hashsize;
+       char                            hashbuf[64];
+       unsigned int                    bufsize;
+       int                             i, err;
 
-                crc32 = crc32_le(crc32, ptr, len);
+       LASSERT(alg > BULK_HASH_ALG_NULL && alg < BULK_HASH_ALG_MAX);
+       LASSERT(buflen >= 4);
 
-                cfs_kunmap(page);
-        }
+       hdesc = cfs_crypto_hash_init(cfs_hash_alg_id[alg], NULL, 0);
+       if (IS_ERR(hdesc)) {
+               CERROR("Unable to initialize checksum hash %s\n",
+                      cfs_crypto_hash_name(cfs_hash_alg_id[alg]));
+               return PTR_ERR(hdesc);
+       }
 
-        crc32 = cpu_to_le32(crc32);
-        memcpy(buf, &crc32, sizeof(crc32));
-        return 0;
-}
+       hashsize = cfs_crypto_hash_digestsize(cfs_hash_alg_id[alg]);
 
-int sptlrpc_get_bulk_checksum(struct ptlrpc_bulk_desc *desc, __u8 alg,
-                              void *buf, int buflen)
-{
-        struct hash_desc    hdesc;
-        int                 hashsize;
-        char                hashbuf[64];
-        struct scatterlist  sl;
-        int                 i;
-
-        LASSERT(alg > BULK_HASH_ALG_NULL && alg < BULK_HASH_ALG_MAX);
-        LASSERT(buflen >= 4);
-
-        switch (alg) {
-        case BULK_HASH_ALG_ADLER32:
-#ifdef HAVE_ADLER
-                return do_bulk_checksum_adler32(desc, buf);
+       for (i = 0; i < desc->bd_iov_count; i++) {
+#ifdef __KERNEL__
+               cfs_crypto_hash_update_page(hdesc, desc->bd_iov[i].kiov_page,
+                                 desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK,
+                                 desc->bd_iov[i].kiov_len);
 #else
-                CERROR("Adler32 not supported\n");
-                return -EINVAL;
+               cfs_crypto_hash_update(hdesc, desc->bd_iov[i].iov_base,
+                                 desc->bd_iov[i].iov_len);
 #endif
-        case BULK_HASH_ALG_CRC32:
-                return do_bulk_checksum_crc32(desc, buf);
-        }
-
-        hdesc.tfm = ll_crypto_alloc_hash(hash_types[alg].sht_tfm_name, 0, 0);
-        if (hdesc.tfm == NULL) {
-                CERROR("Unable to allocate TFM %s\n", hash_types[alg].sht_name);
-                return -ENOMEM;
-        }
-
-        hdesc.flags = 0;
-        ll_crypto_hash_init(&hdesc);
-
-        hashsize = ll_crypto_hash_digestsize(hdesc.tfm);
-
-        for (i = 0; i < desc->bd_iov_count; i++) {
-                sg_set_page(&sl, desc->bd_iov[i].kiov_page,
-                             desc->bd_iov[i].kiov_len,
-                             desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK);
-                ll_crypto_hash_update(&hdesc, &sl, sl.length);
-        }
-
-        if (hashsize > buflen) {
-                ll_crypto_hash_final(&hdesc, hashbuf);
-                memcpy(buf, hashbuf, buflen);
-        } else {
-                ll_crypto_hash_final(&hdesc, buf);
-        }
-
-        ll_crypto_free_hash(hdesc.tfm);
-        return 0;
+       }
+       if (hashsize > buflen) {
+               bufsize = sizeof(hashbuf);
+               err = cfs_crypto_hash_final(hdesc, (unsigned char *)hashbuf,
+                                           &bufsize);
+               memcpy(buf, hashbuf, buflen);
+       } else {
+               bufsize = buflen;
+               err = cfs_crypto_hash_final(hdesc, (unsigned char *)buf,
+                                           &bufsize);
+       }
+
+       if (err)
+               cfs_crypto_hash_final(hdesc, NULL, NULL);
+       return err;
 }
 EXPORT_SYMBOL(sptlrpc_get_bulk_checksum);
 
-#else /* !__KERNEL__ */
-
-int sptlrpc_get_bulk_checksum(struct ptlrpc_bulk_desc *desc, __u8 alg,
-                              void *buf, int buflen)
-{
-        __u32   csum32;
-        int     i;
-
-        LASSERT(alg == BULK_HASH_ALG_ADLER32 || alg == BULK_HASH_ALG_CRC32);
-
-        if (alg == BULK_HASH_ALG_ADLER32)
-                csum32 = 1;
-        else
-                csum32 = ~0;
-
-        for (i = 0; i < desc->bd_iov_count; i++) {
-                unsigned char *ptr = desc->bd_iov[i].iov_base;
-                int len = desc->bd_iov[i].iov_len;
-
-                switch (alg) {
-                case BULK_HASH_ALG_ADLER32:
-#ifdef HAVE_ADLER
-                        csum32 = adler32(csum32, ptr, len);
-#else
-                        CERROR("Adler32 not supported\n");
-                        return -EINVAL;
-#endif
-                        break;
-                case BULK_HASH_ALG_CRC32:
-                        csum32 = crc32_le(csum32, ptr, len);
-                        break;
-                }
-        }
-
-        csum32 = cpu_to_le32(csum32);
-        memcpy(buf, &csum32, sizeof(csum32));
-        return 0;
-}
 
-#endif /* __KERNEL__ */
index d123e30..10f88fa 100644 (file)
@@ -270,15 +270,18 @@ int plain_ctx_verify(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
         }
 
         if (unlikely(req->rq_early)) {
-                cksum = crc32_le(!(__u32) 0,
-                                 lustre_msg_buf(msg, PLAIN_PACK_MSG_OFF, 0),
-                                 lustre_msg_buflen(msg, PLAIN_PACK_MSG_OFF));
-                if (cksum != msg->lm_cksum) {
-                        CDEBUG(D_SEC,
-                               "early reply checksum mismatch: %08x != %08x\n",
-                               cpu_to_le32(cksum), msg->lm_cksum);
-                        RETURN(-EINVAL);
-                }
+               unsigned int hsize = 4;
+
+               cfs_crypto_hash_digest(CFS_HASH_ALG_CRC32,
+                               lustre_msg_buf(msg, PLAIN_PACK_MSG_OFF, 0),
+                               lustre_msg_buflen(msg, PLAIN_PACK_MSG_OFF),
+                               NULL, 0, (unsigned char *)&cksum, &hsize);
+               if (cksum != msg->lm_cksum) {
+                       CDEBUG(D_SEC,
+                              "early reply checksum mismatch: %08x != %08x\n",
+                              cpu_to_le32(cksum), msg->lm_cksum);
+                       RETURN(-EINVAL);
+               }
         } else {
                 /* whether we sent with bulk or not, we expect the same
                  * in reply, except for early reply */
@@ -892,10 +895,13 @@ int plain_authorize(struct ptlrpc_request *req)
                 else
                         req->rq_reply_off = 0;
         } else {
-                msg->lm_cksum = crc32_le(!(__u32) 0,
-                                lustre_msg_buf(msg, PLAIN_PACK_MSG_OFF, 0),
-                                lustre_msg_buflen(msg, PLAIN_PACK_MSG_OFF));
-                req->rq_reply_off = 0;
+               unsigned int hsize = 4;
+
+               cfs_crypto_hash_digest(CFS_HASH_ALG_CRC32,
+                       lustre_msg_buf(msg, PLAIN_PACK_MSG_OFF, 0),
+                       lustre_msg_buflen(msg, PLAIN_PACK_MSG_OFF),
+                       NULL, 0, (unsigned char *)&msg->lm_cksum, &hsize);
+                       req->rq_reply_off = 0;
         }
 
         RETURN(0);
index 5815b5f..5c21ca0 100644 (file)
@@ -4716,7 +4716,7 @@ test_77i() { # bug 13805
        for VALUE in `lctl get_param osc.*osc-[^mM]*.checksum_type`; do
                PARAM=`echo ${VALUE[0]} | cut -d "=" -f1`
                algo=`lctl get_param -n $PARAM | sed 's/.*\[\(.*\)\].*/\1/g'`
-               [ "$algo" = "crc32" ] || error "algo set to $algo instead of crc32"
+               [ "$algo" = "adler" ] || error "algo set to $algo instead of adler"
        done
        remount_client $MOUNT
 }