Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > media > main-src > by-pkgid > a83160a857a2d32e2b2b3f71cd4279d2 > files > 3

cmirror-1.1.39-13.el5.src.rpm

diff --git a/cmirror/src/compat.c b/cmirror/src/compat.c
index 3639d99..da104a1 100644
--- a/cmirror/src/compat.c
+++ b/cmirror/src/compat.c
@@ -3,6 +3,7 @@
  *
  * This file is released under the GPL.
  */
+#include <stdlib.h>
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
@@ -339,6 +340,124 @@ static int v4_to_v5(struct clog_tfr_v4 *v4, struct clog_request *rq)
 	return COMPAT_OFFSET + sizeof(*rq) + u_rq->data_size;
 }
 
+#define switch_64(x, to_wire) \
+	(to_wire) ? le64_to_cpu(x) : cpu_to_le64(x)
+
+void v5_data_endian_switch(struct clog_request *rq, int to_wire)
+{
+	int i, end;
+	int64_t *pi64;
+	uint64_t *pu64;
+	uint32_t rq_type = rq->u_rq.request_type & ~DM_CLOG_RESPONSE;
+	
+	if (rq->u_rq.request_type & DM_CLOG_RESPONSE) {
+		switch (rq_type) {
+		case DM_CLOG_CTR:
+		case DM_CLOG_DTR:
+			LOG_ERROR("Invalid response type in endian switch");
+			exit(EXIT_FAILURE);
+
+		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:
+		case DM_CLOG_STATUS_INFO:
+		case DM_CLOG_STATUS_TABLE:
+			/* No outbound data */
+			break;
+
+		case DM_CLOG_GET_REGION_SIZE:
+		case DM_CLOG_GET_SYNC_COUNT:
+			pu64 = (uint64_t *)rq->u_rq.data;
+			*pu64 = switch_64(*pu64, to_wire);
+			break;
+		case DM_CLOG_IS_CLEAN:
+		case DM_CLOG_IN_SYNC:
+			pi64 = (int64_t *)rq->u_rq.data;
+			*pi64 = switch_64(*pi64, to_wire);
+			break;
+		case DM_CLOG_GET_RESYNC_WORK:
+		case DM_CLOG_IS_REMOTE_RECOVERING:
+			pi64 = (int64_t *)rq->u_rq.data;
+			pu64 = ((uint64_t *)rq->u_rq.data) + 1;
+			*pi64 = switch_64(*pi64, to_wire);
+			*pu64 = switch_64(*pu64, to_wire);
+			break;
+		default:
+			LOG_ERROR("Unknown request type, %u", rq_type);
+			return;
+		}
+	} else {
+		switch (rq_type) {
+		case DM_CLOG_CTR:
+		case DM_CLOG_DTR:
+			LOG_ERROR("Invalid request type in endian switch");
+			exit(EXIT_FAILURE);
+
+		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:
+		case DM_CLOG_IS_REMOTE_RECOVERING:
+			pu64 = (uint64_t *)rq->u_rq.data;
+			*pu64 = switch_64(*pu64, to_wire);
+			break;
+		case DM_CLOG_MARK_REGION:
+		case DM_CLOG_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] = switch_64(pu64[i], to_wire);
+			break;
+		case DM_CLOG_SET_REGION_SYNC:
+			pu64 = (uint64_t *)rq->u_rq.data;
+			pi64 = ((int64_t *)rq->u_rq.data) + 1;
+			*pu64 = switch_64(*pu64, to_wire);
+			*pi64 = switch_64(*pi64, to_wire);
+			break;
+		default:
+			LOG_ERROR("Unknown request type, %u", rq_type);
+			exit(EXIT_FAILURE);
+		}
+	}
+}
+
+int v5_endian_to_wire(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 = cpu_to_le32(u_rq->error);
+	u_rq->seq = cpu_to_le32(u_rq->seq);
+	u_rq->request_type = cpu_to_le32(u_rq->request_type);
+	u_rq->data_size = cpu_to_le64(u_rq->data_size);
+
+	rq->originator = cpu_to_le32(rq->originator);
+
+	v5_data_endian_switch(rq, 1);
+
+	return size;
+}
+
 int add_compatibility_layer(void *from, void **compat_version,
 			    unsigned from_version)
 {
@@ -357,6 +476,8 @@ int add_compatibility_layer(void *from, void **compat_version,
 	case 4:
 		from_size = sizeof(*v4) + v4->data_size;
 		break;
+	case 5:
+		return v5_endian_to_wire(from);
 	default:
 		LOG_ERROR("Invalid 'from_version'");
 		return -EINVAL;
@@ -396,16 +517,196 @@ static int v5_to_v3(struct clog_request *rq, struct clog_tfr_v3 *v3)
 	return -EINVAL;
 }
 
+static int v5_to_v4_copy_data(struct clog_request *rq, struct clog_tfr_v4 *v4)
+{
+	int data_size = 0;
+	struct dm_ulog_request *u_rq = &rq->u_rq;
+	uint32_t rq_type = le32_to_cpu(u_rq->request_type) & ~DM_CLOG_RESPONSE;
+
+	if (le32_to_cpu(u_rq->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 (v4) {
+				uint64_t *a64, *b64;
+
+				a64 = (uint64_t *)rq->u_rq.data;
+				b64 = (uint64_t *)v4->data;
+				*b64 = le64_to_cpu(*a64);
+			}
+			break;
+		case DM_CLOG_IS_CLEAN:
+		case DM_CLOG_IN_SYNC:
+			data_size = sizeof(int);
+			if (v4) {
+				int *p;
+				int64_t *p64;
+
+				p = (int *)v4->data;
+				p64 = (int64_t *)rq->u_rq.data;
+				*p = (int)(le64_to_cpu(*p64));
+			}
+			break;
+		case DM_CLOG_GET_RESYNC_WORK:
+			data_size = sizeof(int32_t) +
+				sizeof(uint32_t) + sizeof(uint64_t);
+			if (v4) {
+				int32_t *pi32;
+				int64_t *pi64;
+				uint64_t *pu64, u64;
+
+				pi32 = (int32_t *)v4->data;
+				pu64 = ((uint64_t *)v4->data) + 1;
+
+				pi64 = (int64_t *)rq->u_rq.data;
+				u64 = ((uint64_t *)rq->u_rq.data)[1];
+
+				*pi32 = (int32_t)(le64_to_cpu(*pi64));
+				*pu64 = (uint64_t)le64_to_cpu(u64);
+			}
+			break;
+		case DM_CLOG_GET_SYNC_COUNT:
+			data_size = sizeof(uint64_t);
+			if (v4) {
+				uint64_t *a64, *b64;
+
+				a64 = (uint64_t *)rq->u_rq.data;
+				b64 = (uint64_t *)v4->data;
+				*b64 = le64_to_cpu(*a64);
+			}
+			break;			
+		case DM_CLOG_STATUS_INFO:
+		case DM_CLOG_STATUS_TABLE:
+			data_size = u_rq->data_size;
+			if (v4)
+				memcpy(v4->data, rq->u_rq.data, data_size);
+			break;
+		case DM_CLOG_IS_REMOTE_RECOVERING:
+			data_size = sizeof(int32_t) +
+				sizeof(uint32_t) + sizeof(uint64_t);
+			if (v4) {
+				int32_t *pi32;
+				uint64_t *pu64, u64;
+				int64_t i64;
+
+				i64 = ((int64_t *)rq->u_rq.data)[0];
+				u64 = ((uint64_t *)rq->u_rq.data)[1];
+
+				pi32 = (int32_t *)v4->data;
+				pu64 = ((uint64_t *)v4->data) + 1;
+
+				*pi32 = (int32_t)(le64_to_cpu(i64));
+				*pu64 = le64_to_cpu(u64);
+			}
+			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 (v4) {
+				uint64_t *a64, *b64;
+
+				a64 = (uint64_t *)rq->u_rq.data;
+				b64 = (uint64_t *)v4->data;
+				*b64 = le64_to_cpu(*a64);
+			}
+			break;
+		case DM_CLOG_MARK_REGION:
+		case DM_CLOG_CLEAR_REGION:
+			data_size = le32_to_cpu(u_rq->data_size);
+			if (v4) {
+				int i, end = data_size/sizeof(uint64_t);
+				uint64_t *a64, *b64;
+
+				a64 = (uint64_t *)rq->u_rq.data;
+				b64 = (uint64_t *)v4->data;
+				for (i = 0; i < end; i++)
+					b64[i] = le64_to_cpu(a64[i]);
+			}
+			break;
+		case DM_CLOG_SET_REGION_SYNC:
+			data_size = sizeof(uint64_t) +
+				sizeof(uint32_t) + sizeof(int32_t);
+			if (v4) {
+				uint64_t u64, *pu64;
+				int64_t i64;
+				int32_t *pi32;
+
+				pu64 = (uint64_t *)v4->data;
+				pi32 = ((int32_t *)v4->data) + 3;
+
+				u64 = ((uint64_t *)rq->u_rq.data)[0];
+				i64 = ((int64_t *)rq->u_rq.data)[1];
+
+				*pu64 = le64_to_cpu(u64);
+				*pi32 = (uint32_t)(le64_to_cpu(i64));
+			}
+			break;
+		case DM_CLOG_IS_REMOTE_RECOVERING:
+			data_size = sizeof(uint64_t);
+			if (v4) {
+				uint64_t *a64, *b64;
+
+				a64 = (uint64_t *)rq->u_rq.data;
+				b64 = (uint64_t *)v4->data;
+				*b64 = le64_to_cpu(*a64);
+			}
+			break;
+		default:
+			LOG_ERROR("Unknown request type, %u", rq_type);
+			return -EINVAL;
+		}
+	}
+
+	return data_size;
+}
+
 static int v5_to_v4(struct clog_request *rq, struct clog_tfr_v4 *v4)
 {
+	int size;
 	struct dm_ulog_request *u_rq = &rq->u_rq;
 
-	if ((sizeof(*v4) + u_rq->data_size) > (COMPAT_SIZE - COMPAT_OFFSET)) {
+	size = sizeof(*v4) + v5_to_v4_copy_data(rq, NULL);
+
+	if (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);
@@ -416,11 +717,30 @@ static int v5_to_v4(struct clog_request *rq, struct clog_tfr_v4 *v4)
 
 	v4->originator = rq->originator;
 
-	memcpy(v4->data, u_rq->data, u_rq->data_size);
+	v5_to_v4_copy_data(rq, v4);
 
 	return 0;
 }
 
+int v5_endian_from_wire(struct clog_request *rq)
+{
+	int size;
+	struct dm_ulog_request *u_rq = &rq->u_rq;
+
+	u_rq->error = le32_to_cpu(u_rq->error);
+	u_rq->seq = le32_to_cpu(u_rq->seq);
+	u_rq->request_type = le32_to_cpu(u_rq->request_type);
+	u_rq->data_size = le64_to_cpu(u_rq->data_size);
+
+	rq->originator = le32_to_cpu(rq->originator);
+
+	size = sizeof(*rq) + u_rq->data_size;
+
+	v5_data_endian_switch(rq, 0);
+
+	return size;
+}
+
 int strip_compatibility_layer(void *from, void **to,
 			      unsigned to_version)
 {
@@ -462,6 +782,8 @@ int strip_compatibility_layer(void *from, void **to,
 			return v5_to_v3(from, (void *)buffer);
 		case 4:
 			return v5_to_v4(from, (void *)buffer);
+		case 5:
+			return v5_endian_from_wire(from);
 		}
 		return -EINVAL;
 	}		
@@ -473,7 +795,6 @@ int strip_compatibility_layer(void *from, void **to,
 	 *
 	 * IOW, assume (version == to_version)
 	 */
-
 	if (report) {
 		LOG_ERROR("Unknown version for communication struct - forced to assume version %d", to_version);
 		report = 0;