diff options
Diffstat (limited to 'include/linux/ceph/decode.h')
| -rw-r--r-- | include/linux/ceph/decode.h | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/include/linux/ceph/decode.h b/include/linux/ceph/decode.h index d8615dee5808..4bbf2db45f46 100644 --- a/include/linux/ceph/decode.h +++ b/include/linux/ceph/decode.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #ifndef __CEPH_DECODE_H | 1 | #ifndef __CEPH_DECODE_H |
| 2 | #define __CEPH_DECODE_H | 2 | #define __CEPH_DECODE_H |
| 3 | 3 | ||
| 4 | #include <linux/err.h> | ||
| 4 | #include <linux/bug.h> | 5 | #include <linux/bug.h> |
| 5 | #include <linux/time.h> | 6 | #include <linux/time.h> |
| 6 | #include <asm/unaligned.h> | 7 | #include <asm/unaligned.h> |
| @@ -85,6 +86,52 @@ static inline int ceph_has_room(void **p, void *end, size_t n) | |||
| 85 | } while (0) | 86 | } while (0) |
| 86 | 87 | ||
| 87 | /* | 88 | /* |
| 89 | * Allocate a buffer big enough to hold the wire-encoded string, and | ||
| 90 | * decode the string into it. The resulting string will always be | ||
| 91 | * terminated with '\0'. If successful, *p will be advanced | ||
| 92 | * past the decoded data. Also, if lenp is not a null pointer, the | ||
| 93 | * length (not including the terminating '\0') will be recorded in | ||
| 94 | * *lenp. Note that a zero-length string is a valid return value. | ||
| 95 | * | ||
| 96 | * Returns a pointer to the newly-allocated string buffer, or a | ||
| 97 | * pointer-coded errno if an error occurs. Neither *p nor *lenp | ||
| 98 | * will have been updated if an error is returned. | ||
| 99 | * | ||
| 100 | * There are two possible failures: | ||
| 101 | * - converting the string would require accessing memory at or | ||
| 102 | * beyond the "end" pointer provided (-E | ||
| 103 | * - memory could not be allocated for the result | ||
| 104 | */ | ||
| 105 | static inline char *ceph_extract_encoded_string(void **p, void *end, | ||
| 106 | size_t *lenp, gfp_t gfp) | ||
| 107 | { | ||
| 108 | u32 len; | ||
| 109 | void *sp = *p; | ||
| 110 | char *buf; | ||
| 111 | |||
| 112 | ceph_decode_32_safe(&sp, end, len, bad); | ||
| 113 | if (!ceph_has_room(&sp, end, len)) | ||
| 114 | goto bad; | ||
| 115 | |||
| 116 | buf = kmalloc(len + 1, gfp); | ||
| 117 | if (!buf) | ||
| 118 | return ERR_PTR(-ENOMEM); | ||
| 119 | |||
| 120 | if (len) | ||
| 121 | memcpy(buf, sp, len); | ||
| 122 | buf[len] = '\0'; | ||
| 123 | |||
| 124 | *p = (char *) *p + sizeof (u32) + len; | ||
| 125 | if (lenp) | ||
| 126 | *lenp = (size_t) len; | ||
| 127 | |||
| 128 | return buf; | ||
| 129 | |||
| 130 | bad: | ||
| 131 | return ERR_PTR(-ERANGE); | ||
| 132 | } | ||
| 133 | |||
| 134 | /* | ||
| 88 | * struct ceph_timespec <-> struct timespec | 135 | * struct ceph_timespec <-> struct timespec |
| 89 | */ | 136 | */ |
| 90 | static inline void ceph_decode_timespec(struct timespec *ts, | 137 | static inline void ceph_decode_timespec(struct timespec *ts, |
| @@ -151,7 +198,7 @@ static inline void ceph_encode_filepath(void **p, void *end, | |||
| 151 | u64 ino, const char *path) | 198 | u64 ino, const char *path) |
| 152 | { | 199 | { |
| 153 | u32 len = path ? strlen(path) : 0; | 200 | u32 len = path ? strlen(path) : 0; |
| 154 | BUG_ON(*p + sizeof(ino) + sizeof(len) + len > end); | 201 | BUG_ON(*p + 1 + sizeof(ino) + sizeof(len) + len > end); |
| 155 | ceph_encode_8(p, 1); | 202 | ceph_encode_8(p, 1); |
| 156 | ceph_encode_64(p, ino); | 203 | ceph_encode_64(p, ino); |
| 157 | ceph_encode_32(p, len); | 204 | ceph_encode_32(p, len); |
