blob: 3a63462aa943845c754ec53ef79d3dc72a22456c [file] [log] [blame]
/*
* 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.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
* Lustre is a trademark of Sun Microsystems, Inc.
*/
#ifndef __OBD_CKSUM
#define __OBD_CKSUM
#include "../../include/linux/libcfs/libcfs.h"
#include "lustre/lustre_idl.h"
static inline unsigned char cksum_obd2cfs(cksum_type_t cksum_type)
{
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
* only be a single checksum type per RPC.
*
* The OBD_CHECKSUM_* type bits passed in ocd_cksum_types are a 32-bit bitmask
* 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 multiple algorithms are supported the best one is used. */
static inline u32 cksum_type_pack(cksum_type_t cksum_type)
{
unsigned int performance = 0, tmp;
u32 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(u32 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 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)
{
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;
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 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));
}
/* Checksum algorithm names. Must be defined in the same order as the
* OBD_CKSUM_* flags. */
#define DECLARE_CKSUM_NAME char *cksum_name[] = {"crc32", "adler", "crc32c"}
#endif /* __OBD_H */