xref: /titanic_41/usr/src/common/lvm/md_crc.c (revision cde2885fdf538266ee2a3b08dee2d5075ce8fa2b)
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 *
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
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
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