2 * This file is part of the SPL: Solaris Porting Layer.
4 * Copyright (c) 2008 Sun Microsystems, Inc.
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.
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
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.
21 #include <linux/string.h>
24 #include <sys/debug.h>
25 #include <sys/types.h>
27 #include <rpc/types.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 CWARN("Invalid op value: %d\n", op
);
146 xdrs
->x_ops
= NULL
; /* Let the caller know we failed */
152 xdrs
->x_addr_end
= addr
+ size
;
154 if (xdrs
->x_addr_end
< xdrs
->x_addr
) {
155 CWARN("Overflow while creating xdrmem: %p, %u\n", addr
, size
);
159 EXPORT_SYMBOL(xdrmem_create
);
162 xdrmem_control(XDR
*xdrs
, int req
, void *info
)
164 struct xdr_bytesrec
*rec
= (struct xdr_bytesrec
*) info
;
166 if (req
!= XDR_GET_BYTES_AVAIL
) {
167 CWARN("Called with unknown request: %d\n", req
);
171 rec
->xc_is_last_record
= TRUE
; /* always TRUE in xdrmem streams */
172 rec
->xc_num_avail
= xdrs
->x_addr_end
- xdrs
->x_addr
;
178 xdrmem_enc_bytes(XDR
*xdrs
, caddr_t cp
, const uint_t cnt
)
180 uint_t size
= roundup(cnt
, 4);
184 return FALSE
; /* Integer overflow */
186 if (xdrs
->x_addr
> xdrs
->x_addr_end
)
189 if (xdrs
->x_addr_end
- xdrs
->x_addr
< size
)
192 memcpy(xdrs
->x_addr
, cp
, cnt
);
198 memset(xdrs
->x_addr
, 0, pad
);
206 xdrmem_dec_bytes(XDR
*xdrs
, caddr_t cp
, const uint_t cnt
)
208 static uint32_t zero
= 0;
209 uint_t size
= roundup(cnt
, 4);
213 return FALSE
; /* Integer overflow */
215 if (xdrs
->x_addr
> xdrs
->x_addr_end
)
218 if (xdrs
->x_addr_end
- xdrs
->x_addr
< size
)
221 memcpy(cp
, xdrs
->x_addr
, cnt
);
226 /* An inverted memchr() would be useful here... */
227 if (memcmp(&zero
, xdrs
->x_addr
, pad
) != 0)
237 xdrmem_enc_uint32(XDR
*xdrs
, uint32_t val
)
239 if (xdrs
->x_addr
+ sizeof(uint32_t) > xdrs
->x_addr_end
)
242 *((uint32_t *) xdrs
->x_addr
) = cpu_to_be32(val
);
244 xdrs
->x_addr
+= sizeof(uint32_t);
250 xdrmem_dec_uint32(XDR
*xdrs
, uint32_t *val
)
252 if (xdrs
->x_addr
+ sizeof(uint32_t) > xdrs
->x_addr_end
)
255 *val
= be32_to_cpu(*((uint32_t *) xdrs
->x_addr
));
257 xdrs
->x_addr
+= sizeof(uint32_t);
263 xdrmem_enc_char(XDR
*xdrs
, char *cp
)
267 BUILD_BUG_ON(sizeof(char) != 1);
268 val
= *((unsigned char *) cp
);
270 return xdrmem_enc_uint32(xdrs
, val
);
274 xdrmem_dec_char(XDR
*xdrs
, char *cp
)
278 BUILD_BUG_ON(sizeof(char) != 1);
280 if (!xdrmem_dec_uint32(xdrs
, &val
))
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.
291 *((unsigned char *) cp
) = val
;
297 xdrmem_enc_ushort(XDR
*xdrs
, unsigned short *usp
)
299 BUILD_BUG_ON(sizeof(unsigned short) != 2);
301 return xdrmem_enc_uint32(xdrs
, *usp
);
305 xdrmem_dec_ushort(XDR
*xdrs
, unsigned short *usp
)
309 BUILD_BUG_ON(sizeof(unsigned short) != 2);
311 if (!xdrmem_dec_uint32(xdrs
, &val
))
315 * Short ints are not in the RFC, but we assume similar logic as in
327 xdrmem_enc_uint(XDR
*xdrs
, unsigned *up
)
329 BUILD_BUG_ON(sizeof(unsigned) != 4);
331 return xdrmem_enc_uint32(xdrs
, *up
);
335 xdrmem_dec_uint(XDR
*xdrs
, unsigned *up
)
337 BUILD_BUG_ON(sizeof(unsigned) != 4);
339 return xdrmem_dec_uint32(xdrs
, (uint32_t *) up
);
343 xdrmem_enc_ulonglong(XDR
*xdrs
, u_longlong_t
*ullp
)
345 BUILD_BUG_ON(sizeof(u_longlong_t
) != 8);
347 if (!xdrmem_enc_uint32(xdrs
, *ullp
>> 32))
350 return xdrmem_enc_uint32(xdrs
, *ullp
& 0xffffffff);
354 xdrmem_dec_ulonglong(XDR
*xdrs
, u_longlong_t
*ullp
)
358 BUILD_BUG_ON(sizeof(u_longlong_t
) != 8);
360 if (!xdrmem_dec_uint32(xdrs
, &high
))
362 if (!xdrmem_dec_uint32(xdrs
, &low
))
365 *ullp
= ((u_longlong_t
) high
<< 32) | low
;
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
)
375 caddr_t addr
= *arrp
;
377 if (*sizep
> maxsize
|| *sizep
> UINT_MAX
/ elsize
)
380 if (!xdrmem_enc_uint(xdrs
, sizep
))
383 for (i
= 0; i
< *sizep
; i
++) {
384 if (!elproc(xdrs
, addr
))
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
)
397 bool_t alloc
= FALSE
;
400 if (!xdrmem_dec_uint(xdrs
, sizep
))
405 if (size
> maxsize
|| size
> UINT_MAX
/ elsize
)
409 * The Solaris man page says: "If *arrp is NULL when decoding,
410 * xdr_array() allocates memory and *arrp points to it".
413 BUILD_BUG_ON(sizeof(uint_t
) > sizeof(size_t));
415 *arrp
= kmem_alloc(size
* elsize
, KM_NOSLEEP
);
424 for (i
= 0; i
< size
; i
++) {
425 if (!elproc(xdrs
, addr
)) {
427 kmem_free(*arrp
, size
* elsize
);
437 xdr_enc_string(XDR
*xdrs
, char **sp
, const uint_t maxsize
)
439 size_t slen
= strlen(*sp
);
447 if (!xdrmem_enc_uint(xdrs
, &len
))
450 return xdrmem_enc_bytes(xdrs
, *sp
, len
);
454 xdr_dec_string(XDR
*xdrs
, char **sp
, const uint_t maxsize
)
457 bool_t alloc
= FALSE
;
459 if (!xdrmem_dec_uint(xdrs
, &size
))
462 if (size
> maxsize
|| size
> UINT_MAX
- 1)
466 * Solaris man page: "If *sp is NULL when decoding, xdr_string()
467 * allocates memory and *sp points to it".
470 BUILD_BUG_ON(sizeof(uint_t
) > sizeof(size_t));
472 *sp
= kmem_alloc(size
+ 1, KM_NOSLEEP
);
479 if (!xdrmem_dec_bytes(xdrs
, *sp
, size
))
482 if (memchr(*sp
, 0, size
) != NULL
)
491 kmem_free(*sp
, size
+ 1);
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
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