2 * Copyright (c) 2008-2010 Sun Microsystems, Inc.
3 * Written by Ricardo Correia <Ricardo.M.Correia@Sun.COM>
5 * This file is part of the SPL, Solaris Porting Layer.
7 * The SPL is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
12 * The SPL is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * You should have received a copy of the GNU General Public License along
18 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
20 * Solaris Porting Layer (SPL) XDR Implementation.
23 #include <linux/string.h>
25 #include <sys/debug.h>
26 #include <sys/types.h>
27 #include <sys/sysmacros.h>
31 * SPL's XDR mem implementation.
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.
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
41 * Reference documentation for the XDR representation and XDR operations can be
42 * found in RFC 1832 and xdr(3), respectively.
44 * === Implementation shortcomings ===
46 * It is assumed that the following C types have the following sizes:
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
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).
57 * If someone wants to fix the code to work properly on such environments, then:
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
63 * 3) For ints with less than 32 bits, well.. I suspect you'll have bigger
64 * problems than this implementation.
66 * It is also assumed that:
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
76 * No checks are done for the 4 assumptions above, though.
78 * === Caller expectations ===
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:
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
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.
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.
99 * Future decoding operations on the same stream will also have similar
100 * undefined behavior.
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).
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.
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.
116 * 4) Non-zero padding bytes will cause the decoding operation to fail.
118 * 5) Zero bytes on string types will also cause the decoding operation to fail.
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
124 * 7) The stream buffer and encoding/decoding buffers/ptrs should not overlap.
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.
130 static struct xdr_ops xdrmem_encode_ops
;
131 static struct xdr_ops xdrmem_decode_ops
;
134 xdrmem_create(XDR
*xdrs
, const caddr_t addr
, const uint_t size
,
135 const enum xdr_op op
)
139 xdrs
->x_ops
= &xdrmem_encode_ops
;
142 xdrs
->x_ops
= &xdrmem_decode_ops
;
145 xdrs
->x_ops
= NULL
; /* Let the caller know we failed */
151 xdrs
->x_addr_end
= addr
+ size
;
153 if (xdrs
->x_addr_end
< xdrs
->x_addr
) {
157 EXPORT_SYMBOL(xdrmem_create
);
160 xdrmem_control(XDR
*xdrs
, int req
, void *info
)
162 struct xdr_bytesrec
*rec
= (struct xdr_bytesrec
*)info
;
164 if (req
!= XDR_GET_BYTES_AVAIL
)
167 rec
->xc_is_last_record
= TRUE
; /* always TRUE in xdrmem streams */
168 rec
->xc_num_avail
= xdrs
->x_addr_end
- xdrs
->x_addr
;
174 xdrmem_enc_bytes(XDR
*xdrs
, caddr_t cp
, const uint_t cnt
)
176 uint_t size
= roundup(cnt
, 4);
180 return (FALSE
); /* Integer overflow */
182 if (xdrs
->x_addr
> xdrs
->x_addr_end
)
185 if (xdrs
->x_addr_end
- xdrs
->x_addr
< size
)
188 memcpy(xdrs
->x_addr
, cp
, cnt
);
194 memset(xdrs
->x_addr
, 0, pad
);
202 xdrmem_dec_bytes(XDR
*xdrs
, caddr_t cp
, const uint_t cnt
)
204 static uint32_t zero
= 0;
205 uint_t size
= roundup(cnt
, 4);
209 return (FALSE
); /* Integer overflow */
211 if (xdrs
->x_addr
> xdrs
->x_addr_end
)
214 if (xdrs
->x_addr_end
- xdrs
->x_addr
< size
)
217 memcpy(cp
, xdrs
->x_addr
, cnt
);
222 /* An inverted memchr() would be useful here... */
223 if (memcmp(&zero
, xdrs
->x_addr
, pad
) != 0)
233 xdrmem_enc_uint32(XDR
*xdrs
, uint32_t val
)
235 if (xdrs
->x_addr
+ sizeof (uint32_t) > xdrs
->x_addr_end
)
238 *((uint32_t *)xdrs
->x_addr
) = cpu_to_be32(val
);
240 xdrs
->x_addr
+= sizeof (uint32_t);
246 xdrmem_dec_uint32(XDR
*xdrs
, uint32_t *val
)
248 if (xdrs
->x_addr
+ sizeof (uint32_t) > xdrs
->x_addr_end
)
251 *val
= be32_to_cpu(*((uint32_t *)xdrs
->x_addr
));
253 xdrs
->x_addr
+= sizeof (uint32_t);
259 xdrmem_enc_char(XDR
*xdrs
, char *cp
)
263 BUILD_BUG_ON(sizeof (char) != 1);
264 val
= *((unsigned char *) cp
);
266 return (xdrmem_enc_uint32(xdrs
, val
));
270 xdrmem_dec_char(XDR
*xdrs
, char *cp
)
274 BUILD_BUG_ON(sizeof (char) != 1);
276 if (!xdrmem_dec_uint32(xdrs
, &val
))
280 * If any of the 3 other bytes are non-zero then val will be greater
281 * than 0xff and we fail because according to the RFC, this block does
282 * not have a char encoded in it.
287 *((unsigned char *) cp
) = val
;
293 xdrmem_enc_ushort(XDR
*xdrs
, unsigned short *usp
)
295 BUILD_BUG_ON(sizeof (unsigned short) != 2);
297 return (xdrmem_enc_uint32(xdrs
, *usp
));
301 xdrmem_dec_ushort(XDR
*xdrs
, unsigned short *usp
)
305 BUILD_BUG_ON(sizeof (unsigned short) != 2);
307 if (!xdrmem_dec_uint32(xdrs
, &val
))
311 * Short ints are not in the RFC, but we assume similar logic as in
323 xdrmem_enc_uint(XDR
*xdrs
, unsigned *up
)
325 BUILD_BUG_ON(sizeof (unsigned) != 4);
327 return (xdrmem_enc_uint32(xdrs
, *up
));
331 xdrmem_dec_uint(XDR
*xdrs
, unsigned *up
)
333 BUILD_BUG_ON(sizeof (unsigned) != 4);
335 return (xdrmem_dec_uint32(xdrs
, (uint32_t *)up
));
339 xdrmem_enc_ulonglong(XDR
*xdrs
, u_longlong_t
*ullp
)
341 BUILD_BUG_ON(sizeof (u_longlong_t
) != 8);
343 if (!xdrmem_enc_uint32(xdrs
, *ullp
>> 32))
346 return (xdrmem_enc_uint32(xdrs
, *ullp
& 0xffffffff));
350 xdrmem_dec_ulonglong(XDR
*xdrs
, u_longlong_t
*ullp
)
354 BUILD_BUG_ON(sizeof (u_longlong_t
) != 8);
356 if (!xdrmem_dec_uint32(xdrs
, &high
))
358 if (!xdrmem_dec_uint32(xdrs
, &low
))
361 *ullp
= ((u_longlong_t
)high
<< 32) | low
;
367 xdr_enc_array(XDR
*xdrs
, caddr_t
*arrp
, uint_t
*sizep
, const uint_t maxsize
,
368 const uint_t elsize
, const xdrproc_t elproc
)
371 caddr_t addr
= *arrp
;
373 if (*sizep
> maxsize
|| *sizep
> UINT_MAX
/ elsize
)
376 if (!xdrmem_enc_uint(xdrs
, sizep
))
379 for (i
= 0; i
< *sizep
; i
++) {
380 if (!elproc(xdrs
, addr
))
389 xdr_dec_array(XDR
*xdrs
, caddr_t
*arrp
, uint_t
*sizep
, const uint_t maxsize
,
390 const uint_t elsize
, const xdrproc_t elproc
)
393 bool_t alloc
= FALSE
;
396 if (!xdrmem_dec_uint(xdrs
, sizep
))
401 if (size
> maxsize
|| size
> UINT_MAX
/ elsize
)
405 * The Solaris man page says: "If *arrp is NULL when decoding,
406 * xdr_array() allocates memory and *arrp points to it".
409 BUILD_BUG_ON(sizeof (uint_t
) > sizeof (size_t));
411 *arrp
= kmem_alloc(size
* elsize
, KM_NOSLEEP
);
420 for (i
= 0; i
< size
; i
++) {
421 if (!elproc(xdrs
, addr
)) {
423 kmem_free(*arrp
, size
* elsize
);
433 xdr_enc_string(XDR
*xdrs
, char **sp
, const uint_t maxsize
)
435 size_t slen
= strlen(*sp
);
443 if (!xdrmem_enc_uint(xdrs
, &len
))
446 return (xdrmem_enc_bytes(xdrs
, *sp
, len
));
450 xdr_dec_string(XDR
*xdrs
, char **sp
, const uint_t maxsize
)
453 bool_t alloc
= FALSE
;
455 if (!xdrmem_dec_uint(xdrs
, &size
))
458 if (size
> maxsize
|| size
> UINT_MAX
- 1)
462 * Solaris man page: "If *sp is NULL when decoding, xdr_string()
463 * allocates memory and *sp points to it".
466 BUILD_BUG_ON(sizeof (uint_t
) > sizeof (size_t));
468 *sp
= kmem_alloc(size
+ 1, KM_NOSLEEP
);
475 if (!xdrmem_dec_bytes(xdrs
, *sp
, size
))
478 if (memchr(*sp
, 0, size
) != NULL
)
487 kmem_free(*sp
, size
+ 1);
492 static struct xdr_ops xdrmem_encode_ops
= {
493 .xdr_control
= xdrmem_control
,
494 .xdr_char
= xdrmem_enc_char
,
495 .xdr_u_short
= xdrmem_enc_ushort
,
496 .xdr_u_int
= xdrmem_enc_uint
,
497 .xdr_u_longlong_t
= xdrmem_enc_ulonglong
,
498 .xdr_opaque
= xdrmem_enc_bytes
,
499 .xdr_string
= xdr_enc_string
,
500 .xdr_array
= xdr_enc_array
503 static struct xdr_ops xdrmem_decode_ops
= {
504 .xdr_control
= xdrmem_control
,
505 .xdr_char
= xdrmem_dec_char
,
506 .xdr_u_short
= xdrmem_dec_ushort
,
507 .xdr_u_int
= xdrmem_dec_uint
,
508 .xdr_u_longlong_t
= xdrmem_dec_ulonglong
,
509 .xdr_opaque
= xdrmem_dec_bytes
,
510 .xdr_string
= xdr_dec_string
,
511 .xdr_array
= xdr_dec_array