summaryrefslogtreecommitdiffstats
path: root/daemons/cmirrord/compat.c
diff options
context:
space:
mode:
authorJonathan Earl Brassow <jbrassow@redhat.com>2010-01-15 19:49:35 +0000
committerJonathan Earl Brassow <jbrassow@redhat.com>2010-01-15 19:49:35 +0000
commit27318b98a10b2ba57bf8ad129f56f710cd7e38b9 (patch)
tree4bcb7d6d803f3a1e1c4c314e7a57997552c235ee /daemons/cmirrord/compat.c
parent3579eeb2b03b03ae435aefba6f90484b650be6bc (diff)
downloadlvm2-27318b98a10b2ba57bf8ad129f56f710cd7e38b9.tar.gz
lvm2-27318b98a10b2ba57bf8ad129f56f710cd7e38b9.tar.xz
lvm2-27318b98a10b2ba57bf8ad129f56f710cd7e38b9.zip
Make the intermachine communication structures architecture independant
to allow for mixed architecture clusters. Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
Diffstat (limited to 'daemons/cmirrord/compat.c')
-rw-r--r--daemons/cmirrord/compat.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/daemons/cmirrord/compat.c b/daemons/cmirrord/compat.c
new file mode 100644
index 00000000..0653e38b
--- /dev/null
+++ b/daemons/cmirrord/compat.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ */
+#include <stdlib.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include "dm-log-userspace.h"
+#include "logging.h"
+#include "cluster.h"
+#include "xlate.h"
+
+#include "compat.h"
+
+/*
+ * Older versions of the log daemon communicate with different
+ * versions of the inter-machine communication structure, which
+ * varies in size and fields. The older versions append the
+ * standard upstream version of the structure to every request.
+ * COMPAT_OFFSET is where the upstream structure starts.
+ */
+#define COMPAT_OFFSET 256
+
+static void v5_data_endian_switch(struct clog_request *rq, int to_network)
+{
+ int i, end;
+ int64_t *pi64;
+ uint64_t *pu64;
+ uint32_t rq_type = rq->u_rq.request_type & ~DM_ULOG_RESPONSE;
+
+ if (rq->u_rq.request_type & DM_ULOG_RESPONSE) {
+ switch (rq_type) {
+ case DM_ULOG_CTR:
+ case DM_ULOG_DTR:
+ LOG_ERROR("Invalid response type in endian switch");
+ exit(EXIT_FAILURE);
+
+ case DM_ULOG_PRESUSPEND:
+ case DM_ULOG_POSTSUSPEND:
+ case DM_ULOG_RESUME:
+ case DM_ULOG_FLUSH:
+ case DM_ULOG_MARK_REGION:
+ case DM_ULOG_CLEAR_REGION:
+ case DM_ULOG_SET_REGION_SYNC:
+ case DM_ULOG_CHECKPOINT_READY:
+ case DM_ULOG_MEMBER_JOIN:
+ case DM_ULOG_STATUS_INFO:
+ case DM_ULOG_STATUS_TABLE:
+ /* No outbound data */
+ break;
+
+ case DM_ULOG_GET_REGION_SIZE:
+ case DM_ULOG_GET_SYNC_COUNT:
+ pu64 = (uint64_t *)rq->u_rq.data;
+ *pu64 = xlate64(*pu64);
+ break;
+ case DM_ULOG_IS_CLEAN:
+ case DM_ULOG_IN_SYNC:
+ pi64 = (int64_t *)rq->u_rq.data;
+ *pi64 = xlate64(*pi64);
+ break;
+ case DM_ULOG_GET_RESYNC_WORK:
+ case DM_ULOG_IS_REMOTE_RECOVERING:
+ pi64 = (int64_t *)rq->u_rq.data;
+ pu64 = ((uint64_t *)rq->u_rq.data) + 1;
+ *pi64 = xlate64(*pi64);
+ *pu64 = xlate64(*pu64);
+ break;
+ default:
+ LOG_ERROR("Unknown request type, %u", rq_type);
+ return;
+ }
+ } else {
+ switch (rq_type) {
+ case DM_ULOG_CTR:
+ case DM_ULOG_DTR:
+ LOG_ERROR("Invalid request type in endian switch");
+ exit(EXIT_FAILURE);
+
+ case DM_ULOG_PRESUSPEND:
+ case DM_ULOG_POSTSUSPEND:
+ case DM_ULOG_RESUME:
+ case DM_ULOG_GET_REGION_SIZE:
+ case DM_ULOG_FLUSH:
+ case DM_ULOG_GET_RESYNC_WORK:
+ case DM_ULOG_GET_SYNC_COUNT:
+ case DM_ULOG_STATUS_INFO:
+ case DM_ULOG_STATUS_TABLE:
+ case DM_ULOG_CHECKPOINT_READY:
+ case DM_ULOG_MEMBER_JOIN:
+ /* No incoming data */
+ break;
+ case DM_ULOG_IS_CLEAN:
+ case DM_ULOG_IN_SYNC:
+ case DM_ULOG_IS_REMOTE_RECOVERING:
+ pu64 = (uint64_t *)rq->u_rq.data;
+ *pu64 = xlate64(*pu64);
+ break;
+ case DM_ULOG_MARK_REGION:
+ case DM_ULOG_CLEAR_REGION:
+ end = rq->u_rq.data_size/sizeof(uint64_t);
+
+ pu64 = (uint64_t *)rq->u_rq.data;
+ for (i = 0; i < end; i++)
+ pu64[i] = xlate64(pu64[i]);
+ break;
+ case DM_ULOG_SET_REGION_SYNC:
+ pu64 = (uint64_t *)rq->u_rq.data;
+ pi64 = ((int64_t *)rq->u_rq.data) + 1;
+ *pu64 = xlate64(*pu64);
+ *pi64 = xlate64(*pi64);
+ break;
+ default:
+ LOG_ERROR("Unknown request type, %u", rq_type);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+static int v5_endian_to_network(struct clog_request *rq)
+{
+ int size;
+ struct dm_ulog_request *u_rq = &rq->u_rq;
+
+ size = sizeof(*rq) + u_rq->data_size;
+
+ u_rq->error = xlate32(u_rq->error);
+ u_rq->seq = xlate32(u_rq->seq);
+ u_rq->request_type = xlate32(u_rq->request_type);
+ u_rq->data_size = xlate64(u_rq->data_size);
+
+ rq->originator = xlate32(rq->originator);
+
+ v5_data_endian_switch(rq, 1);
+
+ return size;
+}
+
+int clog_request_to_network(struct clog_request *rq)
+{
+ int r;
+
+ /* FIXME: Remove this safety check */
+ if (rq->u.version[0] != xlate64(rq->u.version[1])) {
+ LOG_ERROR("Programmer error: version[0] must be LE");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Are we already running in the endian mode we send
+ * over the wire?
+ */
+ if (rq->u.version[0] == rq->u.version[1])
+ return 0;
+
+ r = v5_endian_to_network(rq);
+ if (r < 0)
+ return r;
+ return 0;
+}
+
+static int v5_endian_from_network(struct clog_request *rq)
+{
+ int size;
+ struct dm_ulog_request *u_rq = &rq->u_rq;
+
+ u_rq->error = xlate32(u_rq->error);
+ u_rq->seq = xlate32(u_rq->seq);
+ u_rq->request_type = xlate32(u_rq->request_type);
+ u_rq->data_size = xlate64(u_rq->data_size);
+
+ rq->originator = xlate32(rq->originator);
+
+ size = sizeof(*rq) + u_rq->data_size;
+
+ v5_data_endian_switch(rq, 0);
+
+ return size;
+}
+
+int clog_request_from_network(void *data, size_t data_len)
+{
+ uint64_t *vp = data;
+ uint64_t version = xlate64(vp[0]);
+ uint64_t unconverted_version = vp[1];
+ struct clog_request *rq = data;
+
+ switch (version) {
+ case 5: /* Upstream */
+ if (version == unconverted_version)
+ return 0;
+ break;
+ case 4: /* RHEL 5.[45] */
+ case 3: /* RHEL 5.3 */
+ case 2: /* RHEL 5.2 */
+ /* FIXME: still need to account for payload */
+ if (data_len < (COMPAT_OFFSET + sizeof(*rq)))
+ return -ENOSPC;
+
+ rq = data + COMPAT_OFFSET;
+ break;
+ default:
+ LOG_ERROR("Unable to process cluster message: "
+ "Incompatible version");
+ return -EINVAL;
+ }
+
+ v5_endian_from_network(rq);
+ return 0;
+}