blob: 689f1df37bff5104687e31cee573133d748f39db [file] [log] [blame]
Sage Weil31b80062009-10-06 11:31:13 -07001#ifndef __CEPH_DECODE_H
2#define __CEPH_DECODE_H
3
Alex Elderf8c36c52012-07-11 08:24:45 -05004#include <linux/err.h>
Paul Gortmaker187f1882011-11-23 20:12:59 -05005#include <linux/bug.h>
Sage Weilc7e337d2010-02-02 16:11:19 -08006#include <linux/time.h>
Paul Gortmaker187f1882011-11-23 20:12:59 -05007#include <asm/unaligned.h>
Sage Weil31b80062009-10-06 11:31:13 -07008
David Howellsa1ce3922012-10-02 18:01:25 +01009#include <linux/ceph/types.h>
Sage Weilc89136e2009-10-14 09:59:09 -070010
Alex Elderadfe6952013-03-13 20:50:00 -050011/* This seemed to be the easiest place to define these */
12
13#define U8_MAX ((u8) (~0U))
14#define U16_MAX ((u16) (~0U))
15#define U32_MAX ((u32) (~0U))
16#define U64_MAX ((u64) (~0ULL))
17
Sage Weil31b80062009-10-06 11:31:13 -070018/*
19 * in all cases,
20 * void **p pointer to position pointer
21 * void *end pointer to end of buffer (last byte + 1)
22 */
23
Sage Weilc89136e2009-10-14 09:59:09 -070024static inline u64 ceph_decode_64(void **p)
25{
26 u64 v = get_unaligned_le64(*p);
27 *p += sizeof(u64);
28 return v;
29}
30static inline u32 ceph_decode_32(void **p)
31{
32 u32 v = get_unaligned_le32(*p);
33 *p += sizeof(u32);
34 return v;
35}
36static inline u16 ceph_decode_16(void **p)
37{
38 u16 v = get_unaligned_le16(*p);
39 *p += sizeof(u16);
40 return v;
41}
42static inline u8 ceph_decode_8(void **p)
43{
44 u8 v = *(u8 *)*p;
45 (*p)++;
46 return v;
47}
48static inline void ceph_decode_copy(void **p, void *pv, size_t n)
49{
50 memcpy(pv, *p, n);
51 *p += n;
52}
53
Sage Weil31b80062009-10-06 11:31:13 -070054/*
55 * bounds check input.
56 */
Xi Wang76aa5422012-04-20 15:49:44 -050057static inline int ceph_has_room(void **p, void *end, size_t n)
58{
59 return end >= *p && n <= end - *p;
60}
61
Alex Elderdd5f0492012-11-01 08:39:27 -050062#define ceph_decode_need(p, end, n, bad) \
63 do { \
64 if (!likely(ceph_has_room(p, end, n))) \
65 goto bad; \
Sage Weil31b80062009-10-06 11:31:13 -070066 } while (0)
67
Sage Weil31b80062009-10-06 11:31:13 -070068#define ceph_decode_64_safe(p, end, v, bad) \
69 do { \
70 ceph_decode_need(p, end, sizeof(u64), bad); \
Sage Weilc89136e2009-10-14 09:59:09 -070071 v = ceph_decode_64(p); \
Sage Weil31b80062009-10-06 11:31:13 -070072 } while (0)
73#define ceph_decode_32_safe(p, end, v, bad) \
74 do { \
75 ceph_decode_need(p, end, sizeof(u32), bad); \
Sage Weilc89136e2009-10-14 09:59:09 -070076 v = ceph_decode_32(p); \
Sage Weil31b80062009-10-06 11:31:13 -070077 } while (0)
78#define ceph_decode_16_safe(p, end, v, bad) \
79 do { \
80 ceph_decode_need(p, end, sizeof(u16), bad); \
Sage Weilc89136e2009-10-14 09:59:09 -070081 v = ceph_decode_16(p); \
Sage Weil31b80062009-10-06 11:31:13 -070082 } while (0)
Sage Weilc7e337d2010-02-02 16:11:19 -080083#define ceph_decode_8_safe(p, end, v, bad) \
84 do { \
85 ceph_decode_need(p, end, sizeof(u8), bad); \
86 v = ceph_decode_8(p); \
87 } while (0)
Sage Weil31b80062009-10-06 11:31:13 -070088
89#define ceph_decode_copy_safe(p, end, pv, n, bad) \
90 do { \
91 ceph_decode_need(p, end, n, bad); \
92 ceph_decode_copy(p, pv, n); \
93 } while (0)
94
95/*
Alex Elderf8c36c52012-07-11 08:24:45 -050096 * Allocate a buffer big enough to hold the wire-encoded string, and
97 * decode the string into it. The resulting string will always be
98 * terminated with '\0'. If successful, *p will be advanced
99 * past the decoded data. Also, if lenp is not a null pointer, the
100 * length (not including the terminating '\0') will be recorded in
101 * *lenp. Note that a zero-length string is a valid return value.
102 *
103 * Returns a pointer to the newly-allocated string buffer, or a
104 * pointer-coded errno if an error occurs. Neither *p nor *lenp
105 * will have been updated if an error is returned.
106 *
107 * There are two possible failures:
108 * - converting the string would require accessing memory at or
Alex Elderdd5f0492012-11-01 08:39:27 -0500109 * beyond the "end" pointer provided (-ERANGE)
110 * - memory could not be allocated for the result (-ENOMEM)
Alex Elderf8c36c52012-07-11 08:24:45 -0500111 */
112static inline char *ceph_extract_encoded_string(void **p, void *end,
113 size_t *lenp, gfp_t gfp)
114{
115 u32 len;
116 void *sp = *p;
117 char *buf;
118
119 ceph_decode_32_safe(&sp, end, len, bad);
120 if (!ceph_has_room(&sp, end, len))
121 goto bad;
122
123 buf = kmalloc(len + 1, gfp);
124 if (!buf)
125 return ERR_PTR(-ENOMEM);
126
127 if (len)
128 memcpy(buf, sp, len);
129 buf[len] = '\0';
130
131 *p = (char *) *p + sizeof (u32) + len;
132 if (lenp)
133 *lenp = (size_t) len;
134
135 return buf;
136
137bad:
138 return ERR_PTR(-ERANGE);
139}
140
141/*
Sage Weil31b80062009-10-06 11:31:13 -0700142 * struct ceph_timespec <-> struct timespec
143 */
Sage Weilc89136e2009-10-14 09:59:09 -0700144static inline void ceph_decode_timespec(struct timespec *ts,
Sage Weil63f2d212009-11-03 15:17:56 -0800145 const struct ceph_timespec *tv)
Sage Weilc89136e2009-10-14 09:59:09 -0700146{
147 ts->tv_sec = le32_to_cpu(tv->tv_sec);
148 ts->tv_nsec = le32_to_cpu(tv->tv_nsec);
149}
150static inline void ceph_encode_timespec(struct ceph_timespec *tv,
Sage Weil63f2d212009-11-03 15:17:56 -0800151 const struct timespec *ts)
Sage Weilc89136e2009-10-14 09:59:09 -0700152{
153 tv->tv_sec = cpu_to_le32(ts->tv_sec);
154 tv->tv_nsec = cpu_to_le32(ts->tv_nsec);
155}
Sage Weil31b80062009-10-06 11:31:13 -0700156
157/*
Sage Weil63f2d212009-11-03 15:17:56 -0800158 * sockaddr_storage <-> ceph_sockaddr
159 */
160static inline void ceph_encode_addr(struct ceph_entity_addr *a)
161{
Yehuda Sadehcd84db62010-06-11 16:58:48 -0700162 __be16 ss_family = htons(a->in_addr.ss_family);
163 a->in_addr.ss_family = *(__u16 *)&ss_family;
Sage Weil63f2d212009-11-03 15:17:56 -0800164}
165static inline void ceph_decode_addr(struct ceph_entity_addr *a)
166{
Yehuda Sadehcd84db62010-06-11 16:58:48 -0700167 __be16 ss_family = *(__be16 *)&a->in_addr.ss_family;
168 a->in_addr.ss_family = ntohs(ss_family);
Sage Weil4e7a5dc2009-11-18 16:19:57 -0800169 WARN_ON(a->in_addr.ss_family == 512);
Sage Weil63f2d212009-11-03 15:17:56 -0800170}
171
172/*
Sage Weil31b80062009-10-06 11:31:13 -0700173 * encoders
174 */
Sage Weilc89136e2009-10-14 09:59:09 -0700175static inline void ceph_encode_64(void **p, u64 v)
176{
177 put_unaligned_le64(v, (__le64 *)*p);
178 *p += sizeof(u64);
179}
180static inline void ceph_encode_32(void **p, u32 v)
181{
182 put_unaligned_le32(v, (__le32 *)*p);
183 *p += sizeof(u32);
184}
185static inline void ceph_encode_16(void **p, u16 v)
186{
187 put_unaligned_le16(v, (__le16 *)*p);
188 *p += sizeof(u16);
189}
190static inline void ceph_encode_8(void **p, u8 v)
191{
192 *(u8 *)*p = v;
193 (*p)++;
194}
Sage Weil4e7a5dc2009-11-18 16:19:57 -0800195static inline void ceph_encode_copy(void **p, const void *s, int len)
196{
197 memcpy(*p, s, len);
198 *p += len;
199}
Sage Weil31b80062009-10-06 11:31:13 -0700200
201/*
202 * filepath, string encoders
203 */
204static inline void ceph_encode_filepath(void **p, void *end,
205 u64 ino, const char *path)
206{
207 u32 len = path ? strlen(path) : 0;
Alex Elderc61a1ab2012-07-03 16:01:18 -0500208 BUG_ON(*p + 1 + sizeof(ino) + sizeof(len) + len > end);
Sage Weilac8839d2010-01-27 14:28:10 -0800209 ceph_encode_8(p, 1);
Sage Weil31b80062009-10-06 11:31:13 -0700210 ceph_encode_64(p, ino);
211 ceph_encode_32(p, len);
212 if (len)
213 memcpy(*p, path, len);
214 *p += len;
215}
216
217static inline void ceph_encode_string(void **p, void *end,
218 const char *s, u32 len)
219{
220 BUG_ON(*p + sizeof(len) + len > end);
221 ceph_encode_32(p, len);
222 if (len)
223 memcpy(*p, s, len);
224 *p += len;
225}
226
Alex Elderdd5f0492012-11-01 08:39:27 -0500227#define ceph_encode_need(p, end, n, bad) \
228 do { \
229 if (!likely(ceph_has_room(p, end, n))) \
230 goto bad; \
Sage Weilc7e337d2010-02-02 16:11:19 -0800231 } while (0)
232
233#define ceph_encode_64_safe(p, end, v, bad) \
234 do { \
235 ceph_encode_need(p, end, sizeof(u64), bad); \
236 ceph_encode_64(p, v); \
237 } while (0)
238#define ceph_encode_32_safe(p, end, v, bad) \
239 do { \
240 ceph_encode_need(p, end, sizeof(u32), bad); \
Alex Elderdd5f0492012-11-01 08:39:27 -0500241 ceph_encode_32(p, v); \
Sage Weilc7e337d2010-02-02 16:11:19 -0800242 } while (0)
243#define ceph_encode_16_safe(p, end, v, bad) \
244 do { \
245 ceph_encode_need(p, end, sizeof(u16), bad); \
Alex Elderdd5f0492012-11-01 08:39:27 -0500246 ceph_encode_16(p, v); \
247 } while (0)
248#define ceph_encode_8_safe(p, end, v, bad) \
249 do { \
250 ceph_encode_need(p, end, sizeof(u8), bad); \
251 ceph_encode_8(p, v); \
Sage Weilc7e337d2010-02-02 16:11:19 -0800252 } while (0)
253
254#define ceph_encode_copy_safe(p, end, pv, n, bad) \
255 do { \
256 ceph_encode_need(p, end, n, bad); \
257 ceph_encode_copy(p, pv, n); \
258 } while (0)
Yehuda Sadehae1533b2010-05-18 16:38:08 -0700259#define ceph_encode_string_safe(p, end, s, n, bad) \
260 do { \
261 ceph_encode_need(p, end, n, bad); \
262 ceph_encode_string(p, end, s, n); \
263 } while (0)
Sage Weilc7e337d2010-02-02 16:11:19 -0800264
Sage Weil31b80062009-10-06 11:31:13 -0700265
266#endif