Whamcloud - gitweb
LU-1198 idl: move FID VER to DLM resource name[1]
[fs/lustre-release.git] / lustre / include / obd_cksum.h
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
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.
11  *
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).
17  *
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
21  *
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
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #ifndef __OBD_CKSUM
38 #define __OBD_CKSUM
39
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>
46 #else
47 #error Unsupported operating system.
48 #endif
49
50 #include <lustre/lustre_idl.h>
51
52 /*
53  * Checksums
54  */
55
56 #ifndef HAVE_ARCH_CRC32
57 /* crc32_le lifted from the Linux kernel, which had the following to say:
58  *
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.
63  */
64 #define CRCPOLY_LE 0xedb88320
65 /**
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
71  */
72 static inline __u32 crc32_le(__u32 crc, unsigned char const *p, size_t len)
73 {
74         int i;
75         while (len--) {
76                 crc ^= *p++;
77                 for (i = 0; i < 8; i++)
78                         crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
79         }
80         return crc;
81 }
82 #endif
83  
84 #ifdef HAVE_ADLER
85 /* Adler-32 is supported */
86 #define CHECKSUM_ADLER OBD_CKSUM_ADLER
87 #else
88 #define CHECKSUM_ADLER 0
89 #endif
90
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,
94                                    size_t bytes)
95 {
96         while (bytes--) {
97                 __asm__ __volatile__ (
98                         ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
99                         : "=S"(crc)
100                         : "0"(crc), "c"(*p)
101                 );
102                 p++;
103         }
104
105         return crc;
106 }
107
108 #if BITS_PER_LONG > 32
109 #define WORD_SHIFT 3
110 #define WORD_MASK  7
111 #define REX "0x48, "
112 #else
113 #define WORD_SHIFT 2
114 #define WORD_MASK  3
115 #define REX ""
116 #endif
117
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)
120 {
121         unsigned int words = len >> WORD_SHIFT;
122         unsigned int bytes = len &  WORD_MASK;
123         long *ptmp = (long *)p;
124
125         while (words--) {
126                 __asm__ __volatile__(
127                         ".byte 0xf2, " REX "0xf, 0x38, 0xf1, 0xf1;"
128                         : "=S"(crc)
129                         : "0"(crc), "c"(*ptmp)
130                 );
131                 ptmp++;
132         }
133
134         if (bytes)
135                 crc = crc32c_hw_byte(crc, (unsigned char *)ptmp, bytes);
136
137         return crc;
138 }
139 #else
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)
143 {
144         LBUG();
145 }
146 #endif
147
148 static inline __u32 init_checksum(cksum_type_t cksum_type)
149 {
150         switch(cksum_type) {
151         case OBD_CKSUM_CRC32C:
152                 return ~0U;
153 #ifdef HAVE_ADLER
154         case OBD_CKSUM_ADLER:
155                 return 1U;
156 #endif
157         case OBD_CKSUM_CRC32:
158                 return ~0U;
159         default:
160                 CERROR("Unknown checksum type (%x)!!!\n", cksum_type);
161                 LBUG();
162         }
163         return 0;
164 }
165
166 static inline __u32 fini_checksum(__u32 cksum, cksum_type_t cksum_type)
167 {
168         if (cksum_type == OBD_CKSUM_CRC32C)
169                 return ~cksum;
170         return cksum;
171 }
172
173 static inline __u32 compute_checksum(__u32 cksum, unsigned char const *p,
174                                      size_t len, cksum_type_t cksum_type)
175 {
176         switch(cksum_type) {
177         case OBD_CKSUM_CRC32C:
178                 return crc32c_hw(cksum, p, len);
179 #ifdef HAVE_ADLER
180         case OBD_CKSUM_ADLER:
181                 return adler32(cksum, p, len);
182 #endif
183         case OBD_CKSUM_CRC32:
184                 return crc32_le(cksum, p, len);
185         default:
186                 CERROR("Unknown checksum type (%x)!!!\n", cksum_type);
187                 LBUG();
188         }
189         return 0;
190 }
191
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.
194  *
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.
198  *
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).
202  *
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)
206 {
207         if (cksum_type & OBD_CKSUM_CRC32C)
208                 return OBD_FL_CKSUM_CRC32C;
209 #ifdef HAVE_ADLER
210         if (cksum_type & OBD_CKSUM_ADLER)
211                 return OBD_FL_CKSUM_ADLER;
212 #endif
213         if (unlikely(cksum_type && !(cksum_type & OBD_CKSUM_CRC32)))
214                 CWARN("unknown cksum type %x\n", cksum_type);
215
216         return OBD_FL_CKSUM_CRC32;
217 }
218
219 static inline cksum_type_t cksum_type_unpack(obd_flag o_flags)
220 {
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:
225 #ifdef HAVE_ADLER
226                 return OBD_CKSUM_ADLER;
227 #else
228                 CWARN("checksum type is set to adler32, but adler32 is not "
229                       "supported (%x)\n", o_flags);
230                 break;
231 #endif
232         default:
233                 break;
234         }
235
236         /* 1.6.4- only supported CRC32 and didn't set o_flags */
237         return OBD_CKSUM_CRC32;
238 }
239
240 /* Return a bitmask of the checksum types supported on this system.
241  *
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.
244  *
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)
248 {
249         cksum_type_t ret = OBD_CKSUM_CRC32;
250
251 #ifdef X86_FEATURE_XMM4_2
252         if (cpu_has_xmm4_2)
253                 ret |= OBD_CKSUM_CRC32C;
254 #endif
255 #ifdef HAVE_ADLER
256         ret |= OBD_CKSUM_ADLER;
257 #endif
258         return ret;
259 }
260
261 /* Select the best checksum algorithm among those supplied in the cksum_types
262  * input.
263  *
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)
270 {
271         return cksum_type_unpack(cksum_type_pack(cksum_types));
272 }
273
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"}
277
278 #endif /* __OBD_H */