]> git.proxmox.com Git - mirror_spl-debian.git/blob - module/spl/spl-xdr.c
Mutex tests updated to use task queues instead of work queues.
[mirror_spl-debian.git] / module / spl / spl-xdr.c
1 /*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2008 Sun Microsystems, Inc.
5 *
6 * This is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <linux/string.h>
22
23 #include <sys/kmem.h>
24 #include <sys/debug.h>
25 #include <sys/types.h>
26
27 #include <rpc/types.h>
28 #include <rpc/xdr.h>
29
30 /*
31 * SPL's XDR mem implementation.
32 *
33 * This is used by libnvpair to serialize/deserialize the name-value pair data
34 * structures into byte arrays in a well-defined and portable manner.
35 *
36 * These data structures are used by the DMU/ZFS to flexibly manipulate various
37 * information in memory and later serialize it/deserialize it to disk.
38 * Examples of usages include the pool configuration, lists of pool and dataset
39 * properties, etc.
40 *
41 * Reference documentation for the XDR representation and XDR operations can be
42 * found in RFC 1832 and xdr(3), respectively.
43 *
44 * === Implementation shortcomings ===
45 *
46 * It is assumed that the following C types have the following sizes:
47 *
48 * char/unsigned char: 1 byte
49 * short/unsigned short: 2 bytes
50 * int/unsigned int: 4 bytes
51 * longlong_t/u_longlong_t: 8 bytes
52 *
53 * The C standard allows these types to be larger (and in the case of ints,
54 * shorter), so if that is the case on some compiler/architecture, the build
55 * will fail (on purpose).
56 *
57 * If someone wants to fix the code to work properly on such environments, then:
58 *
59 * 1) Preconditions should be added to xdrmem_enc functions to make sure the
60 * caller doesn't pass arguments which exceed the expected range.
61 * 2) Functions which take signed integers should be changed to properly do
62 * sign extension.
63 * 3) For ints with less than 32 bits, well.. I suspect you'll have bigger
64 * problems than this implementation.
65 *
66 * It is also assumed that:
67 *
68 * 1) Chars have 8 bits.
69 * 2) We can always do 32-bit-aligned int memory accesses and byte-aligned
70 * memcpy, memset and memcmp.
71 * 3) Arrays passed to xdr_array() are packed and the compiler/architecture
72 * supports element-sized-aligned memory accesses.
73 * 4) Negative integers are natively stored in two's complement binary
74 * representation.
75 *
76 * No checks are done for the 4 assumptions above, though.
77 *
78 * === Caller expectations ===
79 *
80 * Existing documentation does not describe the semantics of XDR operations very
81 * well. Therefore, some assumptions about failure semantics will be made and
82 * will be described below:
83 *
84 * 1) If any encoding operation fails (e.g., due to lack of buffer space), the
85 * the stream should be considered valid only up to the encoding operation
86 * previous to the one that first failed. However, the stream size as returned
87 * by xdr_control() cannot be considered to be strictly correct (it may be
88 * bigger).
89 *
90 * Putting it another way, if there is an encoding failure it's undefined
91 * whether anything is added to the stream in that operation and therefore
92 * neither xdr_control() nor future encoding operations on the same stream can
93 * be relied upon to produce correct results.
94 *
95 * 2) If a decoding operation fails, it's undefined whether anything will be
96 * decoded into passed buffers/pointers during that operation, or what the
97 * values on those buffers will look like.
98 *
99 * Future decoding operations on the same stream will also have similar
100 * undefined behavior.
101 *
102 * 3) When the first decoding operation fails it is OK to trust the results of
103 * previous decoding operations on the same stream, as long as the caller
104 * expects a failure to be possible (e.g. due to end-of-stream).
105 *
106 * However, this is highly discouraged because the caller should know the
107 * stream size and should be coded to expect any decoding failure to be data
108 * corruption due to hardware, accidental or even malicious causes, which should
109 * be handled gracefully in all cases.
110 *
111 * In very rare situations where there are strong reasons to believe the data
112 * can be trusted to be valid and non-tampered with, then the caller may assume
113 * a decoding failure to be a bug (e.g. due to mismatched data types) and may
114 * fail non-gracefully.
115 *
116 * 4) Non-zero padding bytes will cause the decoding operation to fail.
117 *
118 * 5) Zero bytes on string types will also cause the decoding operation to fail.
119 *
120 * 6) It is assumed that either the pointer to the stream buffer given by the
121 * caller is 32-bit aligned or the architecture supports non-32-bit-aligned int
122 * memory accesses.
123 *
124 * 7) The stream buffer and encoding/decoding buffers/ptrs should not overlap.
125 *
126 * 8) If a caller passes pointers to non-kernel memory (e.g., pointers to user
127 * space or MMIO space), the computer may explode.
128 */
129
130 static struct xdr_ops xdrmem_encode_ops;
131 static struct xdr_ops xdrmem_decode_ops;
132
133 void
134 xdrmem_create(XDR *xdrs, const caddr_t addr, const uint_t size,
135 const enum xdr_op op)
136 {
137 switch (op) {
138 case XDR_ENCODE:
139 xdrs->x_ops = &xdrmem_encode_ops;
140 break;
141 case XDR_DECODE:
142 xdrs->x_ops = &xdrmem_decode_ops;
143 break;
144 default:
145 CWARN("Invalid op value: %d\n", op);
146 xdrs->x_ops = NULL; /* Let the caller know we failed */
147 return;
148 }
149
150 xdrs->x_op = op;
151 xdrs->x_addr = addr;
152 xdrs->x_addr_end = addr + size;
153
154 if (xdrs->x_addr_end < xdrs->x_addr) {
155 CWARN("Overflow while creating xdrmem: %p, %u\n", addr, size);
156 xdrs->x_ops = NULL;
157 }
158 }
159 EXPORT_SYMBOL(xdrmem_create);
160
161 static bool_t
162 xdrmem_control(XDR *xdrs, int req, void *info)
163 {
164 struct xdr_bytesrec *rec = (struct xdr_bytesrec *) info;
165
166 if (req != XDR_GET_BYTES_AVAIL) {
167 CWARN("Called with unknown request: %d\n", req);
168 return FALSE;
169 }
170
171 rec->xc_is_last_record = TRUE; /* always TRUE in xdrmem streams */
172 rec->xc_num_avail = xdrs->x_addr_end - xdrs->x_addr;
173
174 return TRUE;
175 }
176
177 static bool_t
178 xdrmem_enc_bytes(XDR *xdrs, caddr_t cp, const uint_t cnt)
179 {
180 uint_t size = roundup(cnt, 4);
181 uint_t pad;
182
183 if (size < cnt)
184 return FALSE; /* Integer overflow */
185
186 if (xdrs->x_addr > xdrs->x_addr_end)
187 return FALSE;
188
189 if (xdrs->x_addr_end - xdrs->x_addr < size)
190 return FALSE;
191
192 memcpy(xdrs->x_addr, cp, cnt);
193
194 xdrs->x_addr += cnt;
195
196 pad = size - cnt;
197 if (pad > 0) {
198 memset(xdrs->x_addr, 0, pad);
199 xdrs->x_addr += pad;
200 }
201
202 return TRUE;
203 }
204
205 static bool_t
206 xdrmem_dec_bytes(XDR *xdrs, caddr_t cp, const uint_t cnt)
207 {
208 static uint32_t zero = 0;
209 uint_t size = roundup(cnt, 4);
210 uint_t pad;
211
212 if (size < cnt)
213 return FALSE; /* Integer overflow */
214
215 if (xdrs->x_addr > xdrs->x_addr_end)
216 return FALSE;
217
218 if (xdrs->x_addr_end - xdrs->x_addr < size)
219 return FALSE;
220
221 memcpy(cp, xdrs->x_addr, cnt);
222 xdrs->x_addr += cnt;
223
224 pad = size - cnt;
225 if (pad > 0) {
226 /* An inverted memchr() would be useful here... */
227 if (memcmp(&zero, xdrs->x_addr, pad) != 0)
228 return FALSE;
229
230 xdrs->x_addr += pad;
231 }
232
233 return TRUE;
234 }
235
236 static bool_t
237 xdrmem_enc_uint32(XDR *xdrs, uint32_t val)
238 {
239 if (xdrs->x_addr + sizeof(uint32_t) > xdrs->x_addr_end)
240 return FALSE;
241
242 *((uint32_t *) xdrs->x_addr) = cpu_to_be32(val);
243
244 xdrs->x_addr += sizeof(uint32_t);
245
246 return TRUE;
247 }
248
249 static bool_t
250 xdrmem_dec_uint32(XDR *xdrs, uint32_t *val)
251 {
252 if (xdrs->x_addr + sizeof(uint32_t) > xdrs->x_addr_end)
253 return FALSE;
254
255 *val = be32_to_cpu(*((uint32_t *) xdrs->x_addr));
256
257 xdrs->x_addr += sizeof(uint32_t);
258
259 return TRUE;
260 }
261
262 static bool_t
263 xdrmem_enc_char(XDR *xdrs, char *cp)
264 {
265 uint32_t val;
266
267 BUILD_BUG_ON(sizeof(char) != 1);
268 val = *((unsigned char *) cp);
269
270 return xdrmem_enc_uint32(xdrs, val);
271 }
272
273 static bool_t
274 xdrmem_dec_char(XDR *xdrs, char *cp)
275 {
276 uint32_t val;
277
278 BUILD_BUG_ON(sizeof(char) != 1);
279
280 if (!xdrmem_dec_uint32(xdrs, &val))
281 return FALSE;
282
283 /*
284 * If any of the 3 other bytes are non-zero then val will be greater
285 * than 0xff and we fail because according to the RFC, this block does
286 * not have a char encoded in it.
287 */
288 if (val > 0xff)
289 return FALSE;
290
291 *((unsigned char *) cp) = val;
292
293 return TRUE;
294 }
295
296 static bool_t
297 xdrmem_enc_ushort(XDR *xdrs, unsigned short *usp)
298 {
299 BUILD_BUG_ON(sizeof(unsigned short) != 2);
300
301 return xdrmem_enc_uint32(xdrs, *usp);
302 }
303
304 static bool_t
305 xdrmem_dec_ushort(XDR *xdrs, unsigned short *usp)
306 {
307 uint32_t val;
308
309 BUILD_BUG_ON(sizeof(unsigned short) != 2);
310
311 if (!xdrmem_dec_uint32(xdrs, &val))
312 return FALSE;
313
314 /*
315 * Short ints are not in the RFC, but we assume similar logic as in
316 * xdrmem_dec_char().
317 */
318 if (val > 0xffff)
319 return FALSE;
320
321 *usp = val;
322
323 return TRUE;
324 }
325
326 static bool_t
327 xdrmem_enc_uint(XDR *xdrs, unsigned *up)
328 {
329 BUILD_BUG_ON(sizeof(unsigned) != 4);
330
331 return xdrmem_enc_uint32(xdrs, *up);
332 }
333
334 static bool_t
335 xdrmem_dec_uint(XDR *xdrs, unsigned *up)
336 {
337 BUILD_BUG_ON(sizeof(unsigned) != 4);
338
339 return xdrmem_dec_uint32(xdrs, (uint32_t *) up);
340 }
341
342 static bool_t
343 xdrmem_enc_ulonglong(XDR *xdrs, u_longlong_t *ullp)
344 {
345 BUILD_BUG_ON(sizeof(u_longlong_t) != 8);
346
347 if (!xdrmem_enc_uint32(xdrs, *ullp >> 32))
348 return FALSE;
349
350 return xdrmem_enc_uint32(xdrs, *ullp & 0xffffffff);
351 }
352
353 static bool_t
354 xdrmem_dec_ulonglong(XDR *xdrs, u_longlong_t *ullp)
355 {
356 uint32_t low, high;
357
358 BUILD_BUG_ON(sizeof(u_longlong_t) != 8);
359
360 if (!xdrmem_dec_uint32(xdrs, &high))
361 return FALSE;
362 if (!xdrmem_dec_uint32(xdrs, &low))
363 return FALSE;
364
365 *ullp = ((u_longlong_t) high << 32) | low;
366
367 return TRUE;
368 }
369
370 static bool_t
371 xdr_enc_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep, const uint_t maxsize,
372 const uint_t elsize, const xdrproc_t elproc)
373 {
374 uint_t i;
375 caddr_t addr = *arrp;
376
377 if (*sizep > maxsize || *sizep > UINT_MAX / elsize)
378 return FALSE;
379
380 if (!xdrmem_enc_uint(xdrs, sizep))
381 return FALSE;
382
383 for (i = 0; i < *sizep; i++) {
384 if (!elproc(xdrs, addr))
385 return FALSE;
386 addr += elsize;
387 }
388
389 return TRUE;
390 }
391
392 static bool_t
393 xdr_dec_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep, const uint_t maxsize,
394 const uint_t elsize, const xdrproc_t elproc)
395 {
396 uint_t i, size;
397 bool_t alloc = FALSE;
398 caddr_t addr;
399
400 if (!xdrmem_dec_uint(xdrs, sizep))
401 return FALSE;
402
403 size = *sizep;
404
405 if (size > maxsize || size > UINT_MAX / elsize)
406 return FALSE;
407
408 /*
409 * The Solaris man page says: "If *arrp is NULL when decoding,
410 * xdr_array() allocates memory and *arrp points to it".
411 */
412 if (*arrp == NULL) {
413 BUILD_BUG_ON(sizeof(uint_t) > sizeof(size_t));
414
415 *arrp = kmem_alloc(size * elsize, KM_NOSLEEP);
416 if (*arrp == NULL)
417 return FALSE;
418
419 alloc = TRUE;
420 }
421
422 addr = *arrp;
423
424 for (i = 0; i < size; i++) {
425 if (!elproc(xdrs, addr)) {
426 if (alloc)
427 kmem_free(*arrp, size * elsize);
428 return FALSE;
429 }
430 addr += elsize;
431 }
432
433 return TRUE;
434 }
435
436 static bool_t
437 xdr_enc_string(XDR *xdrs, char **sp, const uint_t maxsize)
438 {
439 size_t slen = strlen(*sp);
440 uint_t len;
441
442 if (slen > maxsize)
443 return FALSE;
444
445 len = slen;
446
447 if (!xdrmem_enc_uint(xdrs, &len))
448 return FALSE;
449
450 return xdrmem_enc_bytes(xdrs, *sp, len);
451 }
452
453 static bool_t
454 xdr_dec_string(XDR *xdrs, char **sp, const uint_t maxsize)
455 {
456 uint_t size;
457 bool_t alloc = FALSE;
458
459 if (!xdrmem_dec_uint(xdrs, &size))
460 return FALSE;
461
462 if (size > maxsize || size > UINT_MAX - 1)
463 return FALSE;
464
465 /*
466 * Solaris man page: "If *sp is NULL when decoding, xdr_string()
467 * allocates memory and *sp points to it".
468 */
469 if (*sp == NULL) {
470 BUILD_BUG_ON(sizeof(uint_t) > sizeof(size_t));
471
472 *sp = kmem_alloc(size + 1, KM_NOSLEEP);
473 if (*sp == NULL)
474 return FALSE;
475
476 alloc = TRUE;
477 }
478
479 if (!xdrmem_dec_bytes(xdrs, *sp, size))
480 goto fail;
481
482 if (memchr(*sp, 0, size) != NULL)
483 goto fail;
484
485 (*sp)[size] = '\0';
486
487 return TRUE;
488
489 fail:
490 if (alloc)
491 kmem_free(*sp, size + 1);
492
493 return FALSE;
494 }
495
496 static struct xdr_ops xdrmem_encode_ops = {
497 .xdr_control = xdrmem_control,
498 .xdr_char = xdrmem_enc_char,
499 .xdr_u_short = xdrmem_enc_ushort,
500 .xdr_u_int = xdrmem_enc_uint,
501 .xdr_u_longlong_t = xdrmem_enc_ulonglong,
502 .xdr_opaque = xdrmem_enc_bytes,
503 .xdr_string = xdr_enc_string,
504 .xdr_array = xdr_enc_array
505 };
506
507 static struct xdr_ops xdrmem_decode_ops = {
508 .xdr_control = xdrmem_control,
509 .xdr_char = xdrmem_dec_char,
510 .xdr_u_short = xdrmem_dec_ushort,
511 .xdr_u_int = xdrmem_dec_uint,
512 .xdr_u_longlong_t = xdrmem_dec_ulonglong,
513 .xdr_opaque = xdrmem_dec_bytes,
514 .xdr_string = xdr_dec_string,
515 .xdr_array = xdr_dec_array
516 };
517