1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
40 #if defined(__linux__)
41 #include <linux/obd_cksum.h>
42 #elif defined(__APPLE__)
43 #include <darwin/obd_chksum.h>
44 #elif defined(__WINNT__)
45 #include <winnt/obd_cksum.h>
47 #error Unsupported operating system.
50 #include <lustre/lustre_idl.h>
56 #ifndef HAVE_ARCH_CRC32
57 /* crc32_le lifted from the Linux kernel, which had the following to say:
59 * This code is in the public domain; copyright abandoned.
60 * Liability for non-performance of this code is limited to the amount
61 * you paid for it. Since it is distributed for free, your refund will
62 * be very very small. If it breaks, you get to keep both pieces.
64 #define CRCPOLY_LE 0xedb88320
66 * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
67 * \param crc seed value for computation. ~0 for Ethernet, sometimes 0 for
68 * other uses, or the previous crc32 value if computing incrementally.
69 * \param p - pointer to buffer over which CRC is run
70 * \param len- length of buffer \a p
72 static inline __u32 crc32_le(__u32 crc, unsigned char const *p, size_t len)
77 for (i = 0; i < 8; i++)
78 crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
85 /* Adler-32 is supported */
86 #define CHECKSUM_ADLER OBD_CKSUM_ADLER
88 #define CHECKSUM_ADLER 0
91 #ifdef X86_FEATURE_XMM4_2
92 /* Call Nehalem+ CRC32C harware acceleration instruction on individual bytes. */
93 static inline __u32 crc32c_hw_byte(__u32 crc, unsigned char const *p,
97 __asm__ __volatile__ (
98 ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
108 #if BITS_PER_LONG > 32
118 /* Do we need to worry about unaligned input data here? */
119 static inline __u32 crc32c_hw(__u32 crc, unsigned char const *p, size_t len)
121 unsigned int words = len >> WORD_SHIFT;
122 unsigned int bytes = len & WORD_MASK;
123 long *ptmp = (long *)p;
126 __asm__ __volatile__(
127 ".byte 0xf2, " REX "0xf, 0x38, 0xf1, 0xf1;"
129 : "0"(crc), "c"(*ptmp)
135 crc = crc32c_hw_byte(crc, (unsigned char *)ptmp, bytes);
140 /* We should never call this unless the CPU has previously been detected to
141 * support this instruction in the SSE4.2 feature set. b=23549 */
142 static inline __u32 crc32c_hw(__u32 crc, unsigned char const *p,size_t len)
148 static inline __u32 init_checksum(cksum_type_t cksum_type)
151 case OBD_CKSUM_CRC32C:
154 case OBD_CKSUM_ADLER:
157 case OBD_CKSUM_CRC32:
160 CERROR("Unknown checksum type (%x)!!!\n", cksum_type);
166 static inline __u32 fini_checksum(__u32 cksum, cksum_type_t cksum_type)
168 if (cksum_type == OBD_CKSUM_CRC32C)
173 static inline __u32 compute_checksum(__u32 cksum, unsigned char const *p,
174 size_t len, cksum_type_t cksum_type)
177 case OBD_CKSUM_CRC32C:
178 return crc32c_hw(cksum, p, len);
180 case OBD_CKSUM_ADLER:
181 return adler32(cksum, p, len);
183 case OBD_CKSUM_CRC32:
184 return crc32_le(cksum, p, len);
186 CERROR("Unknown checksum type (%x)!!!\n", cksum_type);
192 /* The OBD_FL_CKSUM_* flags is packed into 5 bits of o_flags, since there can
193 * only be a single checksum type per RPC.
195 * The OBD_CHECKSUM_* type bits passed in ocd_cksum_types are a 32-bit bitmask
196 * since they need to represent the full range of checksum algorithms that
197 * both the client and server can understand.
199 * In case of an unsupported types/flags we fall back to CRC32 (even though
200 * it isn't very fast) because that is supported by all clients
201 * checksums, since 1.6.5 (or earlier via patches).
203 * These flags should be listed in order of descending performance, so that
204 * in case multiple algorithms are supported the best one is used. */
205 static inline obd_flag cksum_type_pack(cksum_type_t cksum_type)
207 if (cksum_type & OBD_CKSUM_CRC32C)
208 return OBD_FL_CKSUM_CRC32C;
210 if (cksum_type & OBD_CKSUM_ADLER)
211 return OBD_FL_CKSUM_ADLER;
213 if (unlikely(cksum_type && !(cksum_type & OBD_CKSUM_CRC32)))
214 CWARN("unknown cksum type %x\n", cksum_type);
216 return OBD_FL_CKSUM_CRC32;
219 static inline cksum_type_t cksum_type_unpack(obd_flag o_flags)
221 switch (o_flags & OBD_FL_CKSUM_ALL) {
222 case OBD_FL_CKSUM_CRC32C:
223 return OBD_CKSUM_CRC32C;
224 case OBD_FL_CKSUM_ADLER:
226 return OBD_CKSUM_ADLER;
228 CWARN("checksum type is set to adler32, but adler32 is not "
229 "supported (%x)\n", o_flags);
236 /* 1.6.4- only supported CRC32 and didn't set o_flags */
237 return OBD_CKSUM_CRC32;
240 /* Return a bitmask of the checksum types supported on this system.
242 * CRC32 is a required for compatibility (starting with 1.6.5),
243 * after which we could move to Adler as the base checksum type.
245 * If hardware crc32c support is not available, it is slower than Adler,
246 * so don't include it, even if it could be emulated in software. b=23549 */
247 static inline cksum_type_t cksum_types_supported(void)
249 cksum_type_t ret = OBD_CKSUM_CRC32;
251 #ifdef X86_FEATURE_XMM4_2
253 ret |= OBD_CKSUM_CRC32C;
256 ret |= OBD_CKSUM_ADLER;
261 /* Select the best checksum algorithm among those supplied in the cksum_types
264 * Currently, calling cksum_type_pack() with a mask will return the fastest
265 * checksum type due to its ordering, but in the future we might want to
266 * determine this based on benchmarking the different algorithms quickly.
267 * Caution is advised, however, since what is fastest on a single client may
268 * not be the fastest or most efficient algorithm on the server. */
269 static inline cksum_type_t cksum_type_select(cksum_type_t cksum_types)
271 return cksum_type_unpack(cksum_type_pack(cksum_types));
274 /* Checksum algorithm names. Must be defined in the same order as the
275 * OBD_CKSUM_* flags. */
276 #define DECLARE_CKSUM_NAME char *cksum_name[] = {"crc32", "adler", "crc32c"}