libceph: add start en/decoding block helpers
authorIlya Dryomov <idryomov@gmail.com>
Thu, 2 Jun 2016 12:23:32 +0000 (14:23 +0200)
committerIlya Dryomov <idryomov@gmail.com>
Thu, 28 Jul 2016 00:55:36 +0000 (02:55 +0200)
Add ceph_start_encoding() and ceph_start_decoding(), the equivalent of
ENCODE_START and DECODE_START in the userspace ceph code.

This is based on a patch from Mike Christie <michaelc@cs.wisc.edu>.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
include/linux/ceph/decode.h

index e83f3c8..f990f2c 100644 (file)
@@ -218,6 +218,60 @@ static inline void ceph_encode_string(void **p, void *end,
        *p += len;
 }
 
+/*
+ * version and length starting block encoders/decoders
+ */
+
+/* current code version (u8) + compat code version (u8) + len of struct (u32) */
+#define CEPH_ENCODING_START_BLK_LEN 6
+
+/**
+ * ceph_start_encoding - start encoding block
+ * @struct_v: current (code) version of the encoding
+ * @struct_compat: oldest code version that can decode it
+ * @struct_len: length of struct encoding
+ */
+static inline void ceph_start_encoding(void **p, u8 struct_v, u8 struct_compat,
+                                      u32 struct_len)
+{
+       ceph_encode_8(p, struct_v);
+       ceph_encode_8(p, struct_compat);
+       ceph_encode_32(p, struct_len);
+}
+
+/**
+ * ceph_start_decoding - start decoding block
+ * @v: current version of the encoding that the code supports
+ * @name: name of the struct (free-form)
+ * @struct_v: out param for the encoding version
+ * @struct_len: out param for the length of struct encoding
+ *
+ * Validates the length of struct encoding, so unsafe ceph_decode_*
+ * variants can be used for decoding.
+ */
+static inline int ceph_start_decoding(void **p, void *end, u8 v,
+                                     const char *name, u8 *struct_v,
+                                     u32 *struct_len)
+{
+       u8 struct_compat;
+
+       ceph_decode_need(p, end, CEPH_ENCODING_START_BLK_LEN, bad);
+       *struct_v = ceph_decode_8(p);
+       struct_compat = ceph_decode_8(p);
+       if (v < struct_compat) {
+               pr_warn("got struct_v %d struct_compat %d > %d of %s\n",
+                       *struct_v, struct_compat, v, name);
+               return -EINVAL;
+       }
+
+       *struct_len = ceph_decode_32(p);
+       ceph_decode_need(p, end, *struct_len, bad);
+       return 0;
+
+bad:
+       return -ERANGE;
+}
+
 #define ceph_encode_need(p, end, n, bad)                       \
        do {                                                    \
                if (!likely(ceph_has_room(p, end, n)))          \