Gitweb:
http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: cecd340f67bda6d65465b13a018dd1a1fe5692a5
Parent: e1e194a8337d0ced672e9b6fd08f4ca0d02fb52e
Author: Jonathan Brassow <jbrassow(a)redhat.com>
AuthorDate: Tue Dec 22 10:39:57 2009 -0600
Committer: Jonathan Brassow <jbrassow(a)redhat.com>
CommitterDate: Tue Dec 22 10:40:50 2009 -0600
dm-log-clustered/clogd: Fix mixed arch and rolling upgrade issues (bs488102)
Fields used in the communication structure were not explicitly stated
to be 32 or 64-bit. They could then change depending on the arch.
Additionally, the endian issues were not accounted for.
This patch appends the upstream structure to the original communication
structure, making it forwards compatable with upstream and upstream
backwards compatable with the rhel versions. It also will make mixed
architecture clusters possible.
There may be follow-on work to this patch to bring compatibility between
all rhel releases and architectures, but this puts all the necessary
data on the wire so that can happen.
---
cmirror-kernel/src/dm-clog-tfr.c | 5 +-
cmirror-kernel/src/dm-clog-tfr.h | 2 +
cmirror/src/Makefile | 2 +-
cmirror/src/cluster.c | 23 ++-
cmirror/src/compat.c | 483 ++++++++++++++++++++++++++++++++++++++
cmirror/src/compat.h | 80 +++++++
cmirror/src/local.c | 10 +
7 files changed, 600 insertions(+), 5 deletions(-)
diff --git a/cmirror-kernel/src/dm-clog-tfr.c b/cmirror-kernel/src/dm-clog-tfr.c
index ddcf359..5047e08 100644
--- a/cmirror-kernel/src/dm-clog-tfr.c
+++ b/cmirror-kernel/src/dm-clog-tfr.c
@@ -166,7 +166,7 @@ int dm_clog_consult_server(const char *uuid, uint32_t uuid_instance,
{
int r = 0;
int dummy = 0;
- int overhead_size = sizeof(struct clog_tfr *) + sizeof(struct cn_msg);
+ int overhead_size = sizeof(struct clog_tfr) + sizeof(struct cn_msg);
struct clog_tfr *tfr = prealloced_clog_tfr;
struct receiving_pkg pkg;
@@ -188,7 +188,8 @@ resend:
*/
mutex_lock(&_lock);
- memset(tfr, 0, DM_CLOG_PREALLOCED_SIZE - overhead_size);
+ memset(tfr, 0, DM_CLOG_PREALLOCED_SIZE - sizeof(struct cn_msg));
+ tfr->private[0] = CLOG_TFR_VERSION;
memcpy(tfr->uuid, uuid, DM_UUID_LEN);
tfr->uuid_instance = uuid_instance;
tfr->seq = seq++;
diff --git a/cmirror-kernel/src/dm-clog-tfr.h b/cmirror-kernel/src/dm-clog-tfr.h
index 802db8b..5a48575 100644
--- a/cmirror-kernel/src/dm-clog-tfr.h
+++ b/cmirror-kernel/src/dm-clog-tfr.h
@@ -49,6 +49,8 @@
((x) == DM_CLOG_IS_REMOTE_RECOVERING) ? \
"DM_CLOG_IS_REMOTE_RECOVERING" : NULL
+#define CLOG_TFR_VERSION 4
+
struct clog_tfr {
uint64_t private[2];
char uuid[DM_UUID_LEN]; /* Ties a request to a specific mirror log */
diff --git a/cmirror/src/Makefile b/cmirror/src/Makefile
index 67ee0d5..53f0703 100644
--- a/cmirror/src/Makefile
+++ b/cmirror/src/Makefile
@@ -23,7 +23,7 @@ TMP_INCLUDE = $(shell if [ -e ${KERNEL_SRC}/include/linux/dm-clog-tfr.h
]; then
echo '-I${incdir}'; else \
echo ''; fi)
-SOURCES = clogd.c cluster.c functions.c link_mon.c local.c logging.c
+SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c
ifneq (${TMP_INCLUDE}, )
INCLUDE += ${TMP_INCLUDE} -I.
diff --git a/cmirror/src/cluster.c b/cmirror/src/cluster.c
index 9c84f1d..c04051a 100644
--- a/cmirror/src/cluster.c
+++ b/cmirror/src/cluster.c
@@ -22,6 +22,7 @@
#include "logging.h"
#include "link_mon.h"
#include "cluster.h"
+#include "compat.h"
/* Open AIS error codes */
#define str_ais_error(x) \
@@ -96,6 +97,7 @@ struct checkpoint_data {
#define LEAVING 2
#define MAX_CHECKPOINT_REQUESTERS 10
+
struct clog_cpg {
struct list_head list;
@@ -152,8 +154,18 @@ int cluster_send(struct clog_tfr *tfr)
*/
tfr->uuid_instance = 0;
- iov.iov_base = tfr;
- iov.iov_len = sizeof(struct clog_tfr) + tfr->data_size;
+ /*
+ * All fields will be translated to little endian in the
+ * compatibility layer. We can skip various translation
+ * if the following two fields are the same.
+ */
+ tfr->private[0] = cpu_to_le64(CLOG_TFR_VERSION);
+ tfr->private[1] = CLOG_TFR_VERSION;
+
+ iov.iov_len = add_compatibility_layer(tfr, &(iov.iov_base),
+ CLOG_TFR_VERSION);
+ if (iov.iov_len < 0)
+ return iov.iov_len;
if (entry->cpg_state != VALID)
return -EINVAL;
@@ -948,6 +960,13 @@ static void cpg_message_callback(cpg_handle_t handle, struct cpg_name
*gname,
struct clog_tfr *tmp_tfr = NULL;
struct clog_cpg *match;
+ r = strip_compatibility_layer(msg, &msg, CLOG_TFR_VERSION);
+ if (r < 0) {
+ LOG_ERROR("Failed to strip compatibility layer");
+ return;
+ }
+ r = 0;
+
match = find_clog_cpg(handle);
if (!match) {
LOG_ERROR("Unable to find clog_cpg for cluster message");
diff --git a/cmirror/src/compat.c b/cmirror/src/compat.c
new file mode 100644
index 0000000..3639d99
--- /dev/null
+++ b/cmirror/src/compat.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This file is released under the GPL.
+ */
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include "linux/dm-clog-tfr.h"
+#include "logging.h"
+#include "compat.h"
+
+#define DM_CLOG_RESPONSE 0x1000 /* in last byte of 32-bit value */
+#define DM_CLOG_CHECKPOINT_READY 21
+#define DM_CLOG_MEMBER_JOIN 22
+
+/* Version 1 structures never were public */
+
+/*************************************************************************
+ ** RHEL5.2 STRUCTURES
+ ************************************************************************/
+struct clog_tfr_v2 {
+ uint64_t private[2];
+ char uuid[DM_UUID_LEN]; /* Ties a request to a specific mirror log */
+
+ int error; /* Used by server to inform of errors */
+ uint32_t originator; /* Cluster ID of this machine */
+
+ uint64_t seq; /* Sequence number for request */
+ uint32_t request_type; /* DM_CLOG_* */
+ uint32_t data_size; /* How much data (not including this struct) */
+ char data[0];
+};
+
+
+/*************************************************************************
+ ** RHEL5.3 STRUCTURES
+ ************************************************************************/
+struct clog_tfr_v3 {
+ uint64_t private[2];
+ char uuid[DM_UUID_LEN]; /* Ties a request to a specific mirror log */
+
+ int error; /* Used by server to inform of errors */
+ uint32_t originator; /* Cluster ID of this machine */
+
+ uint32_t seq; /* Sequence number for request */
+ uint32_t request_type; /* DM_CLOG_* */
+ uint32_t data_size; /* How much data (not including this struct) */
+ char data[0];
+};
+
+
+/*************************************************************************
+ ** RHEL5.4+ STRUCTURES
+ ************************************************************************/
+struct clog_tfr_v4 {
+ uint64_t private[2];
+ char uuid[DM_UUID_LEN]; /* Ties a request to a specific mirror log */
+ char uuid_padding[3]; /* DM_UUID_LEN == 129 */
+ uint32_t uuid_instance; /* Allows more than one instance w/ same uuid */
+
+ int32_t error; /* Used by server to inform of errors */
+ uint32_t originator; /* Cluster ID of this machine */
+
+ uint32_t seq; /* Sequence number for request */
+ uint32_t request_type; /* DM_CLOG_* */
+ uint64_t data_size; /* How much data (not including this struct) */
+ char data[0];
+};
+
+
+/*************************************************************************
+ ** UPSTREAM STRUCTURES
+ ************************************************************************/
+
+/*
+ * The upstream machine <-> machine communication structure
+ */
+struct clog_version {
+ uint64_t version;
+ uint64_t flags;
+};
+
+struct compat_list {
+ struct compat_list *a, *b;
+};
+
+/*
+ * The upstream (2.6.32) kernel <-> user communication structure
+ */
+struct dm_ulog_request {
+ uint64_t luid;
+ char uuid[DM_UUID_LEN];
+ char padding[7]; /* Padding because DM_UUID_LEN = 129 */
+
+ int32_t error; /* Used to report back processing errors */
+
+ uint32_t seq; /* Sequence number for request */
+ uint32_t request_type; /* DM_ULOG_* defined above */
+ uint32_t data_size; /* How much data (not including this struct) */
+
+ char data[0];
+};
+
+struct clog_request {
+ union {
+ struct compat_list list;
+ struct clog_version v;
+ } u;
+
+ /*
+ * 'originator' is the machine from which the requests
+ * was made.
+ */
+ uint32_t originator;
+
+ /*
+ * 'pit_server' is the "point-in-time" server for the
+ * request. (I.e. The machine that was the server at
+ * the time the request was issued - only important during
+ * startup.
+ */
+ uint32_t pit_server;
+
+ /*
+ * The request from the kernel that is being processed
+ */
+ struct dm_ulog_request u_rq;
+};
+
+#define COMPAT_SIZE 512
+#define COMPAT_OFFSET 256
+unsigned char buffer[COMPAT_SIZE];
+
+static int v2_to_v5(struct clog_tfr_v2 *v2, struct clog_request *rq)
+{
+ LOG_ERROR("Unable to add compat layer v2->v5");
+ return -EINVAL;
+}
+
+static int v3_to_v5(struct clog_tfr_v3 *v3, struct clog_request *rq)
+{
+ LOG_ERROR("Unable to add compat layer v3->v5");
+ return -EINVAL;
+}
+
+static int v4_to_v5_copy_data(struct clog_tfr_v4 *v4, struct clog_request *rq)
+{
+ int data_size = 0;
+ uint32_t rq_type = v4->request_type & ~DM_CLOG_RESPONSE;
+
+ if (v4->request_type & DM_CLOG_RESPONSE) {
+ switch (rq_type) {
+ case DM_CLOG_CTR:
+ case DM_CLOG_DTR:
+ case DM_CLOG_PRESUSPEND:
+ case DM_CLOG_POSTSUSPEND:
+ case DM_CLOG_RESUME:
+ case DM_CLOG_FLUSH:
+ case DM_CLOG_MARK_REGION:
+ case DM_CLOG_CLEAR_REGION:
+ case DM_CLOG_SET_REGION_SYNC:
+ case DM_CLOG_CHECKPOINT_READY:
+ case DM_CLOG_MEMBER_JOIN:
+ /* No outbound data */
+ break;
+
+ case DM_CLOG_GET_REGION_SIZE:
+ data_size = sizeof(uint64_t);
+ if (rq) {
+ uint64_t *a64, *b64;
+
+ a64 = (uint64_t *)v4->data;
+ b64 = (uint64_t *)rq->u_rq.data;
+ *b64 = cpu_to_le64(*a64);
+ }
+ break;
+ case DM_CLOG_IS_CLEAN:
+ case DM_CLOG_IN_SYNC:
+ data_size = sizeof(int64_t);
+ if (rq) {
+ int i;
+ int64_t *p64;
+
+ i = *((int *)v4->data);
+ p64 = (int64_t *)rq->u_rq.data;
+ *p64 = cpu_to_le64((int64_t)i);
+ }
+ break;
+ case DM_CLOG_GET_RESYNC_WORK:
+ data_size = sizeof(uint64_t) * 2;
+ if (rq) {
+ int32_t i;
+ int64_t *pi64;
+ uint64_t *pu64, u64;
+
+ i = *((int32_t *)v4->data);
+ u64 = ((uint64_t *)v4->data)[1];
+ pi64 = (int64_t *)rq->u_rq.data;
+ pu64 = (uint64_t *)rq->u_rq.data;
+ pu64++;
+ *pi64 = cpu_to_le64((int64_t )i);
+ *pu64 = cpu_to_le64(u64);
+ }
+ break;
+ case DM_CLOG_GET_SYNC_COUNT:
+ data_size = sizeof(uint64_t);
+ if (rq) {
+ uint64_t *a64, *b64;
+
+ a64 = (uint64_t *)v4->data;
+ b64 = (uint64_t *)rq->u_rq.data;
+ *b64 = cpu_to_le64(*a64);
+ }
+ break;
+ case DM_CLOG_STATUS_INFO:
+ case DM_CLOG_STATUS_TABLE:
+ data_size = v4->data_size;
+ if (rq)
+ memcpy(rq->u_rq.data, v4->data, v4->data_size);
+ break;
+ case DM_CLOG_IS_REMOTE_RECOVERING:
+ data_size = sizeof(int32_t) +
+ sizeof(uint32_t) + sizeof(uint64_t);
+ if (rq) {
+ int32_t is_recovering;
+ uint64_t in_sync_hint, *pu64;
+ int64_t *pi64;
+
+ is_recovering = *((int32_t *)v4->data);
+ in_sync_hint = ((uint64_t *)v4->data)[1];
+ pi64 = (int64_t *)rq->u_rq.data;
+ pu64 = ((uint64_t *)rq->u_rq.data) + 1;
+ *pi64 = cpu_to_le64((int64_t)is_recovering);
+ *pu64 = cpu_to_le64(in_sync_hint);
+ }
+ break;
+ default:
+ LOG_ERROR("Unknown request type, %u", rq_type);
+ return -EINVAL;
+ }
+ } else {
+ switch (rq_type) {
+ case DM_CLOG_CTR:
+ case DM_CLOG_DTR:
+ case DM_CLOG_PRESUSPEND:
+ case DM_CLOG_POSTSUSPEND:
+ case DM_CLOG_RESUME:
+ case DM_CLOG_GET_REGION_SIZE:
+ case DM_CLOG_FLUSH:
+ case DM_CLOG_GET_RESYNC_WORK:
+ case DM_CLOG_GET_SYNC_COUNT:
+ case DM_CLOG_STATUS_INFO:
+ case DM_CLOG_STATUS_TABLE:
+ case DM_CLOG_CHECKPOINT_READY:
+ case DM_CLOG_MEMBER_JOIN:
+ /* No incoming data */
+ break;
+ case DM_CLOG_IS_CLEAN:
+ case DM_CLOG_IN_SYNC:
+ data_size = sizeof(uint64_t);
+ if (rq) {
+ uint64_t *a64, *b64;
+
+ a64 = (uint64_t *)v4->data;
+ b64 = (uint64_t *)rq->u_rq.data;
+ *b64 = cpu_to_le64(*a64);
+ }
+ break;
+ case DM_CLOG_MARK_REGION:
+ case DM_CLOG_CLEAR_REGION:
+ data_size = v4->data_size;
+ if (rq) {
+ int i, end = data_size/sizeof(uint64_t);
+ uint64_t *a64, *b64;
+
+ a64 = (uint64_t *)v4->data;
+ b64 = (uint64_t *)rq->u_rq.data;
+ for (i = 0; i < end; i++)
+ b64[i] = cpu_to_le64(a64[i]);
+ }
+ break;
+ case DM_CLOG_SET_REGION_SYNC:
+ data_size = sizeof(uint64_t) * 2;
+ if (rq) {
+ uint64_t r, *pu64;
+ int64_t *pi64;
+ int32_t in_sync;
+
+ r = *((uint64_t *)v4->data);
+ in_sync = ((int32_t *)v4->data)[3];
+ pu64 = (uint64_t *)rq->u_rq.data;
+ pi64 = ((int64_t *)rq->u_rq.data) + 1;
+ *pu64 = cpu_to_le64(r);
+ *pi64 = cpu_to_le64((int64_t)in_sync);
+ }
+ break;
+ case DM_CLOG_IS_REMOTE_RECOVERING:
+ data_size = sizeof(uint64_t);
+ if (rq) {
+ uint64_t *a64, *b64;
+
+ a64 = (uint64_t *)v4->data;
+ b64 = (uint64_t *)rq->u_rq.data;
+ *b64 = cpu_to_le64(*a64);
+ }
+ break;
+ default:
+ LOG_ERROR("Unknown request type, %u", rq_type);
+ return -EINVAL;
+ }
+ }
+
+ return data_size;
+}
+
+static int v4_to_v5(struct clog_tfr_v4 *v4, struct clog_request *rq)
+{
+ int size;
+ struct dm_ulog_request *u_rq = &rq->u_rq;
+
+ size = sizeof(*rq) + v4_to_v5_copy_data(v4, NULL);
+
+ if (size > (COMPAT_SIZE - COMPAT_OFFSET)) {
+ LOG_ERROR("Not enough space for compatibility layer (v4->v5)");
+ return -EINVAL;
+ }
+
+ memcpy(u_rq->uuid, v4->uuid, DM_UUID_LEN);
+ u_rq->error = cpu_to_le32(v4->error);
+ u_rq->seq = cpu_to_le32(v4->seq);
+ u_rq->request_type = cpu_to_le32(v4->request_type);
+ u_rq->data_size = cpu_to_le64(v4->data_size);
+
+ rq->originator = cpu_to_le32(v4->originator);
+
+ v4_to_v5_copy_data(v4, rq);
+
+ return COMPAT_OFFSET + sizeof(*rq) + u_rq->data_size;
+}
+
+int add_compatibility_layer(void *from, void **compat_version,
+ unsigned from_version)
+{
+ int from_size = COMPAT_SIZE;
+ struct clog_tfr_v2 *v2 = from;
+ struct clog_tfr_v3 *v3 = from;
+ struct clog_tfr_v4 *v4 = from;
+
+ switch (from_version) {
+ case 2:
+ from_size = sizeof(*v2) + v2->data_size;
+ break;
+ case 3:
+ from_size = sizeof(*v3) + v3->data_size;
+ break;
+ case 4:
+ from_size = sizeof(*v4) + v4->data_size;
+ break;
+ default:
+ LOG_ERROR("Invalid 'from_version'");
+ return -EINVAL;
+ }
+
+ if (from_size > COMPAT_OFFSET) {
+ LOG_ERROR("Not enough space for request (v%d:%d)",
+ from_version, from_size);
+ return -EINVAL;
+ }
+
+ memset(buffer, 0, COMPAT_SIZE);
+ memcpy(buffer, from, from_size);
+ *compat_version = buffer;
+
+ switch (from_version) {
+ case 2:
+ return v2_to_v5((void *)buffer, (void *)buffer + COMPAT_OFFSET);
+ case 3:
+ return v3_to_v5((void *)buffer, (void *)buffer + COMPAT_OFFSET);
+ case 4:
+ return v4_to_v5((void *)buffer, (void *)buffer + COMPAT_OFFSET);
+ }
+
+ return -EINVAL;
+}
+
+static int v5_to_v2(struct clog_request *rq, struct clog_tfr_v2 *v2)
+{
+ LOG_ERROR("Unable to convert v5->v2");
+ return -EINVAL;
+}
+
+static int v5_to_v3(struct clog_request *rq, struct clog_tfr_v3 *v3)
+{
+ LOG_ERROR("Unable to convert v5->v3");
+ return -EINVAL;
+}
+
+static int v5_to_v4(struct clog_request *rq, struct clog_tfr_v4 *v4)
+{
+ struct dm_ulog_request *u_rq = &rq->u_rq;
+
+ if ((sizeof(*v4) + u_rq->data_size) > (COMPAT_SIZE - COMPAT_OFFSET)) {
+ LOG_ERROR("Not enough space for compatibility data (v5->v4)");
+ return -EINVAL;
+ }
+
+ LOG_ERROR("Stripping compatibility layer (v5->v4)");
+ v4->uuid_instance = (uint32_t)u_rq->luid;
+
+ memcpy(v4->uuid, u_rq->uuid, DM_UUID_LEN);
+ v4->error = u_rq->error;
+ v4->seq = u_rq->seq;
+ v4->request_type = u_rq->request_type;
+ v4->data_size = u_rq->data_size;
+
+ v4->originator = rq->originator;
+
+ memcpy(v4->data, u_rq->data, u_rq->data_size);
+
+ return 0;
+}
+
+int strip_compatibility_layer(void *from, void **to,
+ unsigned to_version)
+{
+ static int report = 1;
+ uint64_t *vp = from;
+ uint64_t version = le64_to_cpu(*vp);
+ uint64_t unconverted_version = vp[1];
+
+ /* We will modify the front of the area in place */
+ *to = from;
+
+ /* Already the version we need and same byte-order? */
+ if ((version == to_version) && (unconverted_version == version))
+ return 0;
+
+ /* A different acceptable version? */
+ if ((version > 1) && (version < 5)) {
+ /* We can use the compatibility layer to convert */
+ switch (to_version) {
+ case 2:
+ return v5_to_v2(from + COMPAT_OFFSET, from);
+ case 3:
+ return v5_to_v3(from + COMPAT_OFFSET, from);
+ case 4:
+ return v5_to_v4(from + COMPAT_OFFSET, from);
+ case 5:
+ *to = from + COMPAT_OFFSET;
+ return 0;
+ }
+ }
+
+ /* Is it upstream format? */
+ if (version == 5) {
+ *to = buffer;
+ switch (to_version) {
+ case 2:
+ return v5_to_v2(from, (void *)buffer);
+ case 3:
+ return v5_to_v3(from, (void *)buffer);
+ case 4:
+ return v5_to_v4(from, (void *)buffer);
+ }
+ return -EINVAL;
+ }
+
+ /*
+ * Is version unknown? (From a release that didn't specify?)
+ * We must assume it is the same version - that the user is
+ * z-stream updating first.
+ *
+ * IOW, assume (version == to_version)
+ */
+
+ if (report) {
+ LOG_ERROR("Unknown version for communication struct - forced to assume version
%d", to_version);
+ report = 0;
+ }
+
+ return 0;
+}
diff --git a/cmirror/src/compat.h b/cmirror/src/compat.h
new file mode 100644
index 0000000..f6d373b
--- /dev/null
+++ b/cmirror/src/compat.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This file is released under the GPL.
+ */
+#ifndef __COMPAT_DOT_H__
+#define __COMPAT_DOT_H__
+
+/*
+ * THE BYTE SWAPPING CODE IS LIFTED DIRECTLY FROM:
+ * cluster/group/include/linux_endian.h - a GPL v.2 file.
+ */
+
+#include <endian.h>
+#include <byteswap.h>
+
+/* I'm not sure which versions of alpha glibc/gcc are broken,
+ so fix all of them. */
+#ifdef __alpha__
+#undef bswap_64
+static __inline__ unsigned long bswap_64(unsigned long x)
+{
+ unsigned int h = x >> 32;
+ unsigned int l = x;
+
+ h = bswap_32(h);
+ l = bswap_32(l);
+
+ return ((unsigned long)l << 32) | h;
+}
+#endif /* __alpha__ */
+
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+
+#define be16_to_cpu(x) (x)
+#define be32_to_cpu(x) (x)
+#define be64_to_cpu(x) (x)
+
+#define cpu_to_be16(x) (x)
+#define cpu_to_be32(x) (x)
+#define cpu_to_be64(x) (x)
+
+#define le16_to_cpu(x) (bswap_16((x)))
+#define le32_to_cpu(x) (bswap_32((x)))
+#define le64_to_cpu(x) (bswap_64((x)))
+
+#define cpu_to_le16(x) (bswap_16((x)))
+#define cpu_to_le32(x) (bswap_32((x)))
+#define cpu_to_le64(x) (bswap_64((x)))
+
+#endif /* __BYTE_ORDER == __BIG_ENDIAN */
+
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+#define be16_to_cpu(x) (bswap_16((x)))
+#define be32_to_cpu(x) (bswap_32((x)))
+#define be64_to_cpu(x) (bswap_64((x)))
+
+#define cpu_to_be16(x) (bswap_16((x)))
+#define cpu_to_be32(x) (bswap_32((x)))
+#define cpu_to_be64(x) (bswap_64((x)))
+
+#define le16_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#define le64_to_cpu(x) (x)
+
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le64(x) (x)
+
+#endif /* __BYTE_ORDER == __LITTLE_ENDIAN */
+
+
+int add_compatibility_layer(void *from, void **compat_version,
+ unsigned from_version);
+int strip_compatibility_layer(void *from, void **to,
+ unsigned to_version);
+#endif /* __COMPAT_DOT_H__ */
diff --git a/cmirror/src/local.c b/cmirror/src/local.c
index cf64855..4d4800b 100644
--- a/cmirror/src/local.c
+++ b/cmirror/src/local.c
@@ -15,6 +15,7 @@
#include "logging.h"
#include "link_mon.h"
#include "local.h"
+#include "compat.h"
static int cn_fd; /* Connector (netlink) socket fd */
static char recv_buf[2048];
@@ -193,6 +194,15 @@ static int do_local_work(void *data)
if (!tfr)
return 0;
+ if (tfr->private[0] != CLOG_TFR_VERSION) {
+ LOG_ERROR("Kernel/Userspace version mismatch!");
+ tfr->data_size = 0;
+ tfr->error = -EINVAL;
+ kernel_send(tfr);
+
+ return tfr->error;
+ }
+
LOG_DBG("[%s] Request from kernel received: [%s/%u]",
SHORT_UUID(tfr->uuid), RQ_TYPE(tfr->request_type),
tfr->seq);