mirror of
git://sourceware.org/git/lvm2.git
synced 2024-10-30 06:26:11 +03:00
211 lines
5.0 KiB
C
211 lines
5.0 KiB
C
/*
|
|
* 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 "logging.h"
|
|
#include "cluster.h"
|
|
#include "compat.h"
|
|
#include "xlate.h"
|
|
|
|
#include <errno.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 __attribute__((unused)))
|
|
{
|
|
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);
|
|
|
|
rq->originator = xlate32(rq->originator);
|
|
|
|
v5_data_endian_switch(rq, 1);
|
|
|
|
u_rq->request_type = xlate32(u_rq->request_type);
|
|
u_rq->data_size = xlate32(u_rq->data_size);
|
|
|
|
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 = xlate32(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]);
|
|
struct clog_request *rq = data;
|
|
|
|
switch (version) {
|
|
case 5: /* Upstream */
|
|
if (version == vp[0])
|
|
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 = (struct clog_request *)((char *)data + COMPAT_OFFSET);
|
|
break;
|
|
default:
|
|
LOG_ERROR("Unable to process cluster message: "
|
|
"Incompatible version");
|
|
return -EINVAL;
|
|
}
|
|
|
|
v5_endian_from_network(rq);
|
|
return 0;
|
|
}
|