@@ -5,8 +5,6 @@ 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

@@ -44,8 +44,7 @@ if LIBLUSTRE
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 \
user-crypto.c posix/posix-crc32.c posix/posix-adler.c
workitem.c fail.c libcfs_cpu.c libcfs_mem.c libcfs_lock.c
libcfs_a_CPPFLAGS = $(LLCPPFLAGS)
libcfs_a_CFLAGS = $(LLCFLAGS)
endif
@@ -1,7 +1,5 @@
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-crypto.c linux-crypto-crc32.c linux-crypto-adler.c

linux-module.c linux-sync.c linux-curproc.c linux-tcpip.c linux-cpu.c


This file was deleted.

This file was deleted.

This file was deleted.

@@ -35,7 +35,6 @@
#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,108 +373,99 @@ 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_wi_startup();
if (rc) {
CERROR("startup workitem: error %d\n", rc);
goto cleanup_deregister;
}

rc = cfs_crypto_register();
if (rc) {
CERROR("cfs_crypto_regster: error %d\n", rc);
goto cleanup_wi;
}

rc = insert_proc();
if (rc) {
CERROR("insert_proc: error %d\n", rc);
goto cleanup_crypto;
}

CDEBUG(D_OTHER, "libcfs setup OK\n");

return 0;
cleanup_crypto:
cfs_crypto_unregister();
rc = cfs_psdev_register(&libcfs_dev);
if (rc) {
CERROR("misc_register: error %d\n", rc);
goto cleanup_lwt;
}

rc = cfs_wi_startup();
if (rc) {
CERROR("startup workitem: error %d\n", rc);
goto cleanup_deregister;
}

rc = insert_proc();
if (rc) {
CERROR("insert_proc: error %d\n", rc);
goto cleanup_wi;
}

CDEBUG (D_OTHER, "portals setup OK\n");
return (0);

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));

cfs_crypto_unregister();
cfs_wi_shutdown();
rc = cfs_psdev_deregister(&libcfs_dev);
if (rc)
CERROR("misc_deregister error %d\n", rc);
cfs_wi_shutdown();
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);

This file was deleted.

This file was deleted.

This file was deleted.

@@ -41,7 +41,8 @@ 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
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
@@ -0,0 +1,65 @@
/*
* 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
@@ -883,6 +883,13 @@ 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);

@@ -34,23 +34,157 @@

#ifndef __OBD_CKSUM
#define __OBD_CKSUM
#include <libcfs/libcfs.h>

#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 <lustre/lustre_idl.h>

static inline unsigned char cksum_obd2cfs(cksum_type_t cksum_type)
/*
* 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)
{
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;
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;
}

/* The OBD_FL_CKSUM_* flags is packed into 5 bits of o_flags, since there can
@@ -60,113 +194,79 @@ static inline unsigned char cksum_obd2cfs(cksum_type_t cksum_type)
* 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 ADLER
* because that is supported by all clients since 1.8
* 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 multiple algorithms are supported the best one is used. */
* These flags should be listed in order of descending performance, so that
* in case multiple algorithms are supported the best one is used. */
static inline obd_flag cksum_type_pack(cksum_type_t cksum_type)
{
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;
}
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);

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_CRC32:
return OBD_CKSUM_CRC32;
default:
break;
}

return OBD_CKSUM_ADLER;
return OBD_FL_CKSUM_CRC32;
}

/* Return a bitmask of the checksum types supported on this system.
* 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)
static inline cksum_type_t cksum_type_unpack(obd_flag o_flags)
{
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)));
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;
}

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;

return ret;
/* 1.6.4- only supported CRC32 and didn't set o_flags */
return OBD_CKSUM_CRC32;
}

/* Server uses algos that perform at 50% or better of the Adler */
static inline cksum_type_t cksum_types_supported_server(void)
/* 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)
{
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;
cksum_type_t ret = OBD_CKSUM_CRC32;

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;
#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;
}


/* 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 benchmarking at libcfs module load.
* checksum type due to its ordering, but in the future we might want to
* determine this based on benchmarking the different algorithms quickly.
* 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
@@ -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_client();
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();
}

#ifdef HAVE_LRU_RESIZE_SUPPORT
@@ -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_client();
data->ocd_cksum_types = cksum_types_supported();
/* 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));
@@ -2777,9 +2777,11 @@ 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_server();
data->ocd_cksum_types &= cksum_types_supported();

/* 1.6.4 clients are not supported any more */
/* 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;

CDEBUG(D_RPCTRACE, "%s: cli %s supports cksum type %x, return "
"%x\n", exp->exp_obd->obd_name,
@@ -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_server();
data->ocd_cksum_types &= cksum_types_supported();

if (unlikely(data->ocd_cksum_types == 0)) {
CERROR("%s: Connect with checksum support but no "
@@ -1136,60 +1136,39 @@ 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 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);
}

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++;
}

bufsize = 4;
err = cfs_crypto_hash_final(hdesc, (unsigned char *)&cksum, &bufsize);
struct brw_page **pga, int opc,
cksum_type_t cksum_type)
{
__u32 cksum;
int i = 0;

if (err)
cfs_crypto_hash_final(hdesc, NULL, NULL);
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);

/* 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++;
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++;

return cksum;
return fini_checksum(cksum, cksum_type);
}

static int osc_brw_prep_request(int cmd, struct client_obd *cli,struct obdo *oa,
@@ -521,57 +521,36 @@ 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)
{
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);
}
}
__u32 cksum;
int i;

bufsize = 4;
err = cfs_crypto_hash_final(hdesc, (unsigned char *)&cksum, &bufsize);
if (err)
cfs_crypto_hash_final(hdesc, NULL, NULL);
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);
}

return cksum;
return fini_checksum(cksum, cksum_type);
}

static int ost_brw_lock_get(int mode, struct obd_export *exp,
@@ -1024,29 +1024,28 @@ static int ptlrpc_connect_interpret(const struct lu_env *env,
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_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;
}
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;
}
cli->cl_cksum_type =cksum_type_select(cli->cl_supp_cksum_types);

if (ocd->ocd_connect_flags & OBD_CONNECT_BRW_SIZE)
@@ -1298,33 +1298,24 @@ __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 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;
__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);
#else
# warning "remove checksum compatibility support for b1_8"
__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;
return crc32_le(~(__u32)0, (unsigned char *)pb,
lustre_msg_buflen(msg, MSG_PTLRPC_BODY_OFF));
#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)
@@ -803,25 +803,55 @@ void sptlrpc_enc_pool_fini(void)
}
#endif

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,
/****************************************
* 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 },
};

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)
{
return cfs_crypto_hash_name(cfs_hash_alg_id[hash_alg]);
const struct sptlrpc_hash_type *ht;

ht = sptlrpc_get_hash_type(hash_alg);
if (ht)
return ht->sht_name;
else
return "unknown";
}
EXPORT_SYMBOL(sptlrpc_get_hash_name);

__u8 sptlrpc_get_hash_alg(const char *algname)
{
return cfs_crypto_hash_alg(algname);
int i;

for (i = 0; i < BULK_HASH_ALG_MAX; i++)
if (!strcmp(hash_types[i].sht_name, algname))
break;
return i;
}
EXPORT_SYMBOL(sptlrpc_get_hash_alg);

@@ -863,52 +893,149 @@ int bulk_sec_desc_unpack(struct lustre_msg *msg, int offset, int swabbed)
}
EXPORT_SYMBOL(bulk_sec_desc_unpack);

int sptlrpc_get_bulk_checksum(struct ptlrpc_bulk_desc *desc, __u8 alg,
void *buf, int buflen)
#ifdef __KERNEL__

#ifdef HAVE_ADLER
static int do_bulk_checksum_adler32(struct ptlrpc_bulk_desc *desc, void *buf)
{
struct cfs_crypto_hash_desc *hdesc;
int hashsize;
char hashbuf[64];
unsigned int bufsize;
int i, err;
struct page *page;
int off;
char *ptr;
__u32 adler32 = 1;
int len, i;

LASSERT(alg > BULK_HASH_ALG_NULL && alg < BULK_HASH_ALG_MAX);
LASSERT(buflen >= 4);
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;

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);
}
adler32 = adler32(adler32, ptr, len);

hashsize = cfs_crypto_hash_digestsize(cfs_hash_alg_id[alg]);
cfs_kunmap(page);
}

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);
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)
{
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;

crc32 = crc32_le(crc32, ptr, len);

cfs_kunmap(page);
}

crc32 = cpu_to_le32(crc32);
memcpy(buf, &crc32, sizeof(crc32));
return 0;
}

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);
#else
cfs_crypto_hash_update(hdesc, desc->bd_iov[i].iov_base,
desc->bd_iov[i].iov_len);
CERROR("Adler32 not supported\n");
return -EINVAL;
#endif
}
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;
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;
}
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__ */
@@ -270,18 +270,15 @@ int plain_ctx_verify(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
}

if (unlikely(req->rq_early)) {
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);
}
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);
}
} else {
/* whether we sent with bulk or not, we expect the same
* in reply, except for early reply */
@@ -895,13 +892,10 @@ int plain_authorize(struct ptlrpc_request *req)
else
req->rq_reply_off = 0;
} else {
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;
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;
}

RETURN(0);
@@ -4696,7 +4696,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" = "adler" ] || error "algo set to $algo instead of adler"
[ "$algo" = "crc32" ] || error "algo set to $algo instead of crc32"
done
remount_client $MOUNT
}