1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/param.h>
30
31 static uint_t *mddb_crctab = NULL;
32
33 #ifndef _KERNEL
34 #include <meta.h>
35 #include <assert.h>
36 #define MD_ZALLOC(x) Zalloc(x)
37 #define MD_FREE(x, y) Free(x)
38 #else /* _KERNEL */
39 #define MD_ZALLOC(x) kmem_zalloc(x, KM_SLEEP)
40 #define MD_FREE(x, y) kmem_free(x, y)
41 #include <sys/thread.h>
42 #include <sys/types.h>
43 #include <sys/kmem.h>
44 #include <sys/debug.h>
45 #endif /* ! _KERNEL */
46 #include <sys/lvm/md_crc.h>
47
48 #define MDDB_CRCMAGIC 987654
49
50 static uint_t *
crcgentab(void)51 crcgentab(void)
52 {
53 int b, i;
54 uint_t v;
55 uint_t *crctab;
56 uint_t poly = 0x04c11db7;
57
58 crctab = (uint_t *)MD_ZALLOC(256 * sizeof (int));
59 for (b = 0; b < 256; b++) {
60 for (v = b << (24), i = 0; i < 8; i++) {
61 if (v & ((unsigned int)1 << 31)) {
62 v = (v << 1) ^ poly;
63 } else {
64 v = v << 1;
65 }
66 }
67 crctab[b] = v;
68 }
69 return (crctab);
70 }
71
72 /*
73 * crc function that allows a number of areas to be skipped (ignored)
74 * during the crc computation. The result area of the record is also ignored
75 * during the crc computation. Ignored areas are used for data that may
76 * be changed after record has been crcgen'd, but before the data has been
77 * written to disk or for when a multi-owner diskset may have multiple
78 * nodes writing the same record data with the exception of the timestamp field.
79 * The list of skip areas must be in ascending order of offset and if any
80 * areas overlap, the list will be modified.
81 */
82 uint_t
crcfunc(uint_t check,uchar_t * record,uint_t * result,size_t size,crc_skip_t * skip)83 crcfunc(
84 uint_t check,
85 uchar_t *record, /* record to be check-summed */
86 uint_t *result, /* put check-sum here(really u_long) */
87 size_t size, /* size of record in bytes */
88 crc_skip_t *skip /* list of areas to skip */
89 )
90 {
91 uint_t newcrc;
92 uint_t *crctab;
93 uchar_t *recaddr;
94 crc_skip_t *s, *p;
95
96 /*
97 * Check skip areas to see if they overlap (this should never happen,
98 * but is handled just in case something changes in the future).
99 * Also the skip list must be in ascending order of offset, assert
100 * error if this is not the case.
101 * If any 2 adjacent skip areas overlap, then the skip areas will
102 * be merged into 1 skip area and the other skip area is freed.
103 * If any 2 adjacent skip areas abut (border) each other, then skip
104 * areas are not merged, but are left as 2 independent skip areas.
105 * If the skip areas are identical, no change is made to either skip
106 * area since this is handled later.
107 */
108 if (skip) {
109 p = NULL;
110 for (s = skip; s != NULL; s = s->skip_next) {
111 if (p == NULL) {
112 p = s;
113 continue;
114 }
115 #ifdef _KERNEL
116 ASSERT(s->skip_offset > p->skip_offset);
117 #else
118 assert(s->skip_offset > p->skip_offset);
119 #endif
120 if ((p->skip_offset + p->skip_size) > s->skip_offset) {
121 /*
122 * Current area overlaps previous, modify
123 * previous area and release current
124 */
125 p->skip_size += s->skip_size - (p->skip_offset
126 + p->skip_size - s->skip_offset);
127 p->skip_next = s->skip_next;
128 MD_FREE(s, sizeof (crc_skip_t));
129 s = p;
130 }
131 p = s;
132 }
133 }
134
135 if (! mddb_crctab)
136 mddb_crctab = crcgentab();
137
138 crctab = mddb_crctab;
139 newcrc = MDDB_CRCMAGIC;
140
141 recaddr = record;
142 s = skip;
143 while (size--) {
144 /* Skip the result pointer */
145 if (record == (uchar_t *)result) {
146 record += sizeof (uint_t);
147 size -= (sizeof (uint_t) - 1);
148 continue;
149 }
150
151 /*
152 * Skip over next skip area if non-null
153 */
154 if ((s) && (record == (recaddr + (s->skip_offset)))) {
155 record += s->skip_size;
156 size -= (s->skip_size - 1);
157 s = s->skip_next;
158 continue;
159 }
160
161 newcrc = (newcrc << 8) ^ crctab[(newcrc >> 24) ^ *record++];
162 }
163
164 /* If we are checking, we either get a 0 - OK, or 1 - Not OK result */
165 if (check) {
166 if (*((uint_t *)result) == newcrc)
167 return (0);
168 return (1);
169 }
170
171 /*
172 * If we are generating, we stuff the result, if we have a result
173 * pointer, and return the value.
174 */
175 if (result != NULL)
176 *((uint_t *)result) = newcrc;
177 return (newcrc);
178 }
179
180 void
crcfreetab(void)181 crcfreetab(void)
182 {
183 if (mddb_crctab) {
184 MD_FREE((caddr_t)mddb_crctab, 256 * sizeof (int));
185 mddb_crctab = NULL;
186 }
187 }
188