1 /*****************************************************************************\
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.
6 * For details, see <http://github.com/behlendorf/spl/>.
8 * The SPL is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
13 * The SPL is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * You should have received a copy of the GNU General Public License along
19 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
20 *****************************************************************************
21 * Solaris Porting Layer (SPL) XDR Implementation.
22 \*****************************************************************************/
24 #include <linux/string.h>
26 #include <sys/debug.h>
27 #include <sys/types.h>
28 #include <rpc/types.h>
30 #include <spl-debug.h>
33 * SPL's XDR mem implementation.
35 * This is used by libnvpair to serialize/deserialize the name-value pair data
36 * structures into byte arrays in a well-defined and portable manner.
38 * These data structures are used by the DMU/ZFS to flexibly manipulate various
39 * information in memory and later serialize it/deserialize it to disk.
40 * Examples of usages include the pool configuration, lists of pool and dataset
43 * Reference documentation for the XDR representation and XDR operations can be
44 * found in RFC 1832 and xdr(3), respectively.
46 * === Implementation shortcomings ===
48 * It is assumed that the following C types have the following sizes:
50 * char/unsigned char: 1 byte
51 * short/unsigned short: 2 bytes
52 * int/unsigned int: 4 bytes
53 * longlong_t/u_longlong_t: 8 bytes
55 * The C standard allows these types to be larger (and in the case of ints,
56 * shorter), so if that is the case on some compiler/architecture, the build
57 * will fail (on purpose).
59 * If someone wants to fix the code to work properly on such environments, then:
61 * 1) Preconditions should be added to xdrmem_enc functions to make sure the
62 * caller doesn't pass arguments which exceed the expected range.
63 * 2) Functions which take signed integers should be changed to properly do
65 * 3) For ints with less than 32 bits, well.. I suspect you'll have bigger
66 * problems than this implementation.
68 * It is also assumed that:
70 * 1) Chars have 8 bits.
71 * 2) We can always do 32-bit-aligned int memory accesses and byte-aligned
72 * memcpy, memset and memcmp.
73 * 3) Arrays passed to xdr_array() are packed and the compiler/architecture
74 * supports element-sized-aligned memory accesses.
75 * 4) Negative integers are natively stored in two's complement binary
78 * No checks are done for the 4 assumptions above, though.
80 * === Caller expectations ===
82 * Existing documentation does not describe the semantics of XDR operations very
83 * well. Therefore, some assumptions about failure semantics will be made and
84 * will be described below:
86 * 1) If any encoding operation fails (e.g., due to lack of buffer space), the
87 * the stream should be considered valid only up to the encoding operation
88 * previous to the one that first failed. However, the stream size as returned
89 * by xdr_control() cannot be considered to be strictly correct (it may be
92 * Putting it another way, if there is an encoding failure it's undefined
93 * whether anything is added to the stream in that operation and therefore
94 * neither xdr_control() nor future encoding operations on the same stream can
95 * be relied upon to produce correct results.
97 * 2) If a decoding operation fails, it's undefined whether anything will be
98 * decoded into passed buffers/pointers during that operation, or what the
99 * values on those buffers will look like.
101 * Future decoding operations on the same stream will also have similar
102 * undefined behavior.
104 * 3) When the first decoding operation fails it is OK to trust the results of
105 * previous decoding operations on the same stream, as long as the caller
106 * expects a failure to be possible (e.g. due to end-of-stream).
108 * However, this is highly discouraged because the caller should know the
109 * stream size and should be coded to expect any decoding failure to be data
110 * corruption due to hardware, accidental or even malicious causes, which should
111 * be handled gracefully in all cases.
113 * In very rare situations where there are strong reasons to believe the data
114 * can be trusted to be valid and non-tampered with, then the caller may assume
115 * a decoding failure to be a bug (e.g. due to mismatched data types) and may
116 * fail non-gracefully.
118 * 4) Non-zero padding bytes will cause the decoding operation to fail.
120 * 5) Zero bytes on string types will also cause the decoding operation to fail.
122 * 6) It is assumed that either the pointer to the stream buffer given by the
123 * caller is 32-bit aligned or the architecture supports non-32-bit-aligned int
126 * 7) The stream buffer and encoding/decoding buffers/ptrs should not overlap.
128 * 8) If a caller passes pointers to non-kernel memory (e.g., pointers to user
129 * space or MMIO space), the computer may explode.
132 static struct xdr_ops xdrmem_encode_ops
;
133 static struct xdr_ops xdrmem_decode_ops
;
136 xdrmem_create(XDR
*xdrs
, const caddr_t addr
, const uint_t size
,
137 const enum xdr_op op
)
141 xdrs
->x_ops
= &xdrmem_encode_ops
;
144 xdrs
->x_ops
= &xdrmem_decode_ops
;
147 CWARN("Invalid op value: %d\n", op
);
148 xdrs
->x_ops
= NULL
; /* Let the caller know we failed */
154 xdrs
->x_addr_end
= addr
+ size
;
156 if (xdrs
->x_addr_end
< xdrs
->x_addr
) {
157 CWARN("Overflow while creating xdrmem: %p, %u\n", addr
, size
);
161 EXPORT_SYMBOL(xdrmem_create
);
164 xdrmem_control(XDR
*xdrs
, int req
, void *info
)
166 struct xdr_bytesrec
*rec
= (struct xdr_bytesrec
*) info
;
168 if (req
!= XDR_GET_BYTES_AVAIL
) {
169 CWARN("Called with unknown request: %d\n", req
);
173 rec
->xc_is_last_record
= TRUE
; /* always TRUE in xdrmem streams */
174 rec
->xc_num_avail
= xdrs
->x_addr_end
- xdrs
->x_addr
;
180 xdrmem_enc_bytes(XDR
*xdrs
, caddr_t cp
, const uint_t cnt
)
182 uint_t size
= roundup(cnt
, 4);
186 return FALSE
; /* Integer overflow */
188 if (xdrs
->x_addr
> xdrs
->x_addr_end
)
191 if (xdrs
->x_addr_end
- xdrs
->x_addr
< size
)
194 memcpy(xdrs
->x_addr
, cp
, cnt
);
200 memset(xdrs
->x_addr
, 0, pad
);
208 xdrmem_dec_bytes(XDR
*xdrs
, caddr_t cp
, const uint_t cnt
)
210 static uint32_t zero
= 0;
211 uint_t size
= roundup(cnt
, 4);
215 return FALSE
; /* Integer overflow */
217 if (xdrs
->x_addr
> xdrs
->x_addr_end
)
220 if (xdrs
->x_addr_end
- xdrs
->x_addr
< size
)
223 memcpy(cp
, xdrs
->x_addr
, cnt
);
228 /* An inverted memchr() would be useful here... */
229 if (memcmp(&zero
, xdrs
->x_addr
, pad
) != 0)
239 xdrmem_enc_uint32(XDR
*xdrs
, uint32_t val
)
241 if (xdrs
->x_addr
+ sizeof(uint32_t) > xdrs
->x_addr_end
)
244 *((uint32_t *) xdrs
->x_addr
) = cpu_to_be32(val
);
246 xdrs
->x_addr
+= sizeof(uint32_t);
252 xdrmem_dec_uint32(XDR
*xdrs
, uint32_t *val
)
254 if (xdrs
->x_addr
+ sizeof(uint32_t) > xdrs
->x_addr_end
)
257 *val
= be32_to_cpu(*((uint32_t *) xdrs
->x_addr
));
259 xdrs
->x_addr
+= sizeof(uint32_t);
265 xdrmem_enc_char(XDR
*xdrs
, char *cp
)
269 BUILD_BUG_ON(sizeof(char) != 1);
270 val
= *((unsigned char *) cp
);
272 return xdrmem_enc_uint32(xdrs
, val
);
276 xdrmem_dec_char(XDR
*xdrs
, char *cp
)
280 BUILD_BUG_ON(sizeof(char) != 1);
282 if (!xdrmem_dec_uint32(xdrs
, &val
))
286 * If any of the 3 other bytes are non-zero then val will be greater
287 * than 0xff and we fail because according to the RFC, this block does
288 * not have a char encoded in it.
293 *((unsigned char *) cp
) = val
;
299 xdrmem_enc_ushort(XDR
*xdrs
, unsigned short *usp
)
301 BUILD_BUG_ON(sizeof(unsigned short) != 2);
303 return xdrmem_enc_uint32(xdrs
, *usp
);
307 xdrmem_dec_ushort(XDR
*xdrs
, unsigned short *usp
)
311 BUILD_BUG_ON(sizeof(unsigned short) != 2);
313 if (!xdrmem_dec_uint32(xdrs
, &val
))
317 * Short ints are not in the RFC, but we assume similar logic as in
329 xdrmem_enc_uint(XDR
*xdrs
, unsigned *up
)
331 BUILD_BUG_ON(sizeof(unsigned) != 4);
333 return xdrmem_enc_uint32(xdrs
, *up
);
337 xdrmem_dec_uint(XDR
*xdrs
, unsigned *up
)
339 BUILD_BUG_ON(sizeof(unsigned) != 4);
341 return xdrmem_dec_uint32(xdrs
, (uint32_t *) up
);
345 xdrmem_enc_ulonglong(XDR
*xdrs
, u_longlong_t
*ullp
)
347 BUILD_BUG_ON(sizeof(u_longlong_t
) != 8);
349 if (!xdrmem_enc_uint32(xdrs
, *ullp
>> 32))
352 return xdrmem_enc_uint32(xdrs
, *ullp
& 0xffffffff);
356 xdrmem_dec_ulonglong(XDR
*xdrs
, u_longlong_t
*ullp
)
360 BUILD_BUG_ON(sizeof(u_longlong_t
) != 8);
362 if (!xdrmem_dec_uint32(xdrs
, &high
))
364 if (!xdrmem_dec_uint32(xdrs
, &low
))
367 *ullp
= ((u_longlong_t
) high
<< 32) | low
;
373 xdr_enc_array(XDR
*xdrs
, caddr_t
*arrp
, uint_t
*sizep
, const uint_t maxsize
,
374 const uint_t elsize
, const xdrproc_t elproc
)
377 caddr_t addr
= *arrp
;
379 if (*sizep
> maxsize
|| *sizep
> UINT_MAX
/ elsize
)
382 if (!xdrmem_enc_uint(xdrs
, sizep
))
385 for (i
= 0; i
< *sizep
; i
++) {
386 if (!elproc(xdrs
, addr
))
395 xdr_dec_array(XDR
*xdrs
, caddr_t
*arrp
, uint_t
*sizep
, const uint_t maxsize
,
396 const uint_t elsize
, const xdrproc_t elproc
)
399 bool_t alloc
= FALSE
;
402 if (!xdrmem_dec_uint(xdrs
, sizep
))
407 if (size
> maxsize
|| size
> UINT_MAX
/ elsize
)
411 * The Solaris man page says: "If *arrp is NULL when decoding,
412 * xdr_array() allocates memory and *arrp points to it".
415 BUILD_BUG_ON(sizeof(uint_t
) > sizeof(size_t));
417 *arrp
= kmem_alloc(size
* elsize
, KM_NOSLEEP
);
426 for (i
= 0; i
< size
; i
++) {
427 if (!elproc(xdrs
, addr
)) {
429 kmem_free(*arrp
, size
* elsize
);
439 xdr_enc_string(XDR
*xdrs
, char **sp
, const uint_t maxsize
)
441 size_t slen
= strlen(*sp
);
449 if (!xdrmem_enc_uint(xdrs
, &len
))
452 return xdrmem_enc_bytes(xdrs
, *sp
, len
);
456 xdr_dec_string(XDR
*xdrs
, char **sp
, const uint_t maxsize
)
459 bool_t alloc
= FALSE
;
461 if (!xdrmem_dec_uint(xdrs
, &size
))
464 if (size
> maxsize
|| size
> UINT_MAX
- 1)
468 * Solaris man page: "If *sp is NULL when decoding, xdr_string()
469 * allocates memory and *sp points to it".
472 BUILD_BUG_ON(sizeof(uint_t
) > sizeof(size_t));
474 *sp
= kmem_alloc(size
+ 1, KM_NOSLEEP
);
481 if (!xdrmem_dec_bytes(xdrs
, *sp
, size
))
484 if (memchr(*sp
, 0, size
) != NULL
)
493 kmem_free(*sp
, size
+ 1);
498 static struct xdr_ops xdrmem_encode_ops
= {
499 .xdr_control
= xdrmem_control
,
500 .xdr_char
= xdrmem_enc_char
,
501 .xdr_u_short
= xdrmem_enc_ushort
,
502 .xdr_u_int
= xdrmem_enc_uint
,
503 .xdr_u_longlong_t
= xdrmem_enc_ulonglong
,
504 .xdr_opaque
= xdrmem_enc_bytes
,
505 .xdr_string
= xdr_enc_string
,
506 .xdr_array
= xdr_enc_array
509 static struct xdr_ops xdrmem_decode_ops
= {
510 .xdr_control
= xdrmem_control
,
511 .xdr_char
= xdrmem_dec_char
,
512 .xdr_u_short
= xdrmem_dec_ushort
,
513 .xdr_u_int
= xdrmem_dec_uint
,
514 .xdr_u_longlong_t
= xdrmem_dec_ulonglong
,
515 .xdr_opaque
= xdrmem_dec_bytes
,
516 .xdr_string
= xdr_dec_string
,
517 .xdr_array
= xdr_dec_array