1/* 2 * GPL HEADER START 3 * 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 only, 8 * as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License version 2 for more details (a copy is included 14 * in the LICENSE file that accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License 17 * version 2 along with this program; If not, see 18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf 19 * 20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 21 * CA 95054 USA or visit www.sun.com if you need additional information or 22 * have any questions. 23 * 24 * GPL HEADER END 25 */ 26/* 27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 28 * Use is subject to license terms. 29 */ 30/* 31 * This file is part of Lustre, http://www.lustre.org/ 32 * Lustre is a trademark of Sun Microsystems, Inc. 33 */ 34 35#ifndef __OBD_CKSUM 36#define __OBD_CKSUM 37#include "../../include/linux/libcfs/libcfs.h" 38#include "lustre/lustre_idl.h" 39 40static inline unsigned char cksum_obd2cfs(cksum_type_t cksum_type) 41{ 42 switch (cksum_type) { 43 case OBD_CKSUM_CRC32: 44 return CFS_HASH_ALG_CRC32; 45 case OBD_CKSUM_ADLER: 46 return CFS_HASH_ALG_ADLER32; 47 case OBD_CKSUM_CRC32C: 48 return CFS_HASH_ALG_CRC32C; 49 default: 50 CERROR("Unknown checksum type (%x)!!!\n", cksum_type); 51 LBUG(); 52 } 53 return 0; 54} 55 56/* The OBD_FL_CKSUM_* flags is packed into 5 bits of o_flags, since there can 57 * only be a single checksum type per RPC. 58 * 59 * The OBD_CHECKSUM_* type bits passed in ocd_cksum_types are a 32-bit bitmask 60 * since they need to represent the full range of checksum algorithms that 61 * both the client and server can understand. 62 * 63 * In case of an unsupported types/flags we fall back to ADLER 64 * because that is supported by all clients since 1.8 65 * 66 * In case multiple algorithms are supported the best one is used. */ 67static inline u32 cksum_type_pack(cksum_type_t cksum_type) 68{ 69 unsigned int performance = 0, tmp; 70 u32 flag = OBD_FL_CKSUM_ADLER; 71 72 if (cksum_type & OBD_CKSUM_CRC32) { 73 tmp = cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)); 74 if (tmp > performance) { 75 performance = tmp; 76 flag = OBD_FL_CKSUM_CRC32; 77 } 78 } 79 if (cksum_type & OBD_CKSUM_CRC32C) { 80 tmp = cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)); 81 if (tmp > performance) { 82 performance = tmp; 83 flag = OBD_FL_CKSUM_CRC32C; 84 } 85 } 86 if (cksum_type & OBD_CKSUM_ADLER) { 87 tmp = cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_ADLER)); 88 if (tmp > performance) { 89 performance = tmp; 90 flag = OBD_FL_CKSUM_ADLER; 91 } 92 } 93 if (unlikely(cksum_type && !(cksum_type & (OBD_CKSUM_CRC32C | 94 OBD_CKSUM_CRC32 | 95 OBD_CKSUM_ADLER)))) 96 CWARN("unknown cksum type %x\n", cksum_type); 97 98 return flag; 99} 100 101static inline cksum_type_t cksum_type_unpack(u32 o_flags) 102{ 103 switch (o_flags & OBD_FL_CKSUM_ALL) { 104 case OBD_FL_CKSUM_CRC32C: 105 return OBD_CKSUM_CRC32C; 106 case OBD_FL_CKSUM_CRC32: 107 return OBD_CKSUM_CRC32; 108 default: 109 break; 110 } 111 112 return OBD_CKSUM_ADLER; 113} 114 115/* Return a bitmask of the checksum types supported on this system. 116 * 1.8 supported ADLER it is base and not depend on hw 117 * Client uses all available local algos 118 */ 119static inline cksum_type_t cksum_types_supported_client(void) 120{ 121 cksum_type_t ret = OBD_CKSUM_ADLER; 122 123 CDEBUG(D_INFO, "Crypto hash speed: crc %d, crc32c %d, adler %d\n", 124 cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)), 125 cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)), 126 cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_ADLER))); 127 128 if (cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)) > 0) 129 ret |= OBD_CKSUM_CRC32C; 130 if (cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)) > 0) 131 ret |= OBD_CKSUM_CRC32; 132 133 return ret; 134} 135 136/* Server uses algos that perform at 50% or better of the Adler */ 137static inline cksum_type_t cksum_types_supported_server(void) 138{ 139 int base_speed; 140 cksum_type_t ret = OBD_CKSUM_ADLER; 141 142 CDEBUG(D_INFO, "Crypto hash speed: crc %d, crc32c %d, adler %d\n", 143 cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)), 144 cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)), 145 cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_ADLER))); 146 147 base_speed = cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_ADLER)) / 2; 148 149 if (cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)) >= 150 base_speed) 151 ret |= OBD_CKSUM_CRC32C; 152 if (cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)) >= 153 base_speed) 154 ret |= OBD_CKSUM_CRC32; 155 156 return ret; 157} 158 159 160/* Select the best checksum algorithm among those supplied in the cksum_types 161 * input. 162 * 163 * Currently, calling cksum_type_pack() with a mask will return the fastest 164 * checksum type due to its benchmarking at libcfs module load. 165 * Caution is advised, however, since what is fastest on a single client may 166 * not be the fastest or most efficient algorithm on the server. */ 167static inline cksum_type_t cksum_type_select(cksum_type_t cksum_types) 168{ 169 return cksum_type_unpack(cksum_type_pack(cksum_types)); 170} 171 172/* Checksum algorithm names. Must be defined in the same order as the 173 * OBD_CKSUM_* flags. */ 174#define DECLARE_CKSUM_NAME char *cksum_name[] = {"crc32", "adler", "crc32c"} 175 176#endif /* __OBD_H */ 177