Tizen 2.1 base
[external/device-mapper.git] / daemons / cmirrord / compat.c
1 /*
2  * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
3  *
4  * This copyrighted material is made available to anyone wishing to use,
5  * modify, copy, or redistribute it subject to the terms and conditions
6  * of the GNU Lesser General Public License v.2.1.
7  */
8 #include "logging.h"
9 #include "cluster.h"
10 #include "compat.h"
11 #include "xlate.h"
12
13 #include <errno.h>
14
15 /*
16  * Older versions of the log daemon communicate with different
17  * versions of the inter-machine communication structure, which
18  * varies in size and fields.  The older versions append the
19  * standard upstream version of the structure to every request.
20  * COMPAT_OFFSET is where the upstream structure starts.
21  */
22 #define COMPAT_OFFSET 256
23
24 static void v5_data_endian_switch(struct clog_request *rq, int to_network __attribute__((unused)))
25 {
26         int i, end;
27         int64_t *pi64;
28         uint64_t *pu64;
29         uint32_t rq_type = rq->u_rq.request_type & ~DM_ULOG_RESPONSE;
30
31         if (rq->u_rq.request_type & DM_ULOG_RESPONSE) {
32                 switch (rq_type) {
33                 case DM_ULOG_CTR:
34                 case DM_ULOG_DTR:
35                         LOG_ERROR("Invalid response type in endian switch");
36                         exit(EXIT_FAILURE);
37
38                 case DM_ULOG_PRESUSPEND:
39                 case DM_ULOG_POSTSUSPEND:
40                 case DM_ULOG_RESUME:
41                 case DM_ULOG_FLUSH:
42                 case DM_ULOG_MARK_REGION:
43                 case DM_ULOG_CLEAR_REGION:
44                 case DM_ULOG_SET_REGION_SYNC:
45                 case DM_ULOG_CHECKPOINT_READY:
46                 case DM_ULOG_MEMBER_JOIN:
47                 case DM_ULOG_STATUS_INFO:
48                 case DM_ULOG_STATUS_TABLE:
49                         /* No outbound data */
50                         break;
51
52                 case DM_ULOG_GET_REGION_SIZE:
53                 case DM_ULOG_GET_SYNC_COUNT:
54                         pu64 = (uint64_t *)rq->u_rq.data;
55                         *pu64 = xlate64(*pu64);
56                         break;
57                 case DM_ULOG_IS_CLEAN:
58                 case DM_ULOG_IN_SYNC:
59                         pi64 = (int64_t *)rq->u_rq.data;
60                         *pi64 = xlate64(*pi64);
61                         break;
62                 case DM_ULOG_GET_RESYNC_WORK:
63                 case DM_ULOG_IS_REMOTE_RECOVERING:
64                         pi64 = (int64_t *)rq->u_rq.data;
65                         pu64 = ((uint64_t *)rq->u_rq.data) + 1;
66                         *pi64 = xlate64(*pi64);
67                         *pu64 = xlate64(*pu64);
68                         break;
69                 default:
70                         LOG_ERROR("Unknown request type, %u", rq_type);
71                         return;
72                 }
73         } else {
74                 switch (rq_type) {
75                 case DM_ULOG_CTR:
76                 case DM_ULOG_DTR:
77                         LOG_ERROR("Invalid request type in endian switch");
78                         exit(EXIT_FAILURE);
79
80                 case DM_ULOG_PRESUSPEND:
81                 case DM_ULOG_POSTSUSPEND:
82                 case DM_ULOG_RESUME:
83                 case DM_ULOG_GET_REGION_SIZE:
84                 case DM_ULOG_FLUSH:
85                 case DM_ULOG_GET_RESYNC_WORK:
86                 case DM_ULOG_GET_SYNC_COUNT:
87                 case DM_ULOG_STATUS_INFO:
88                 case DM_ULOG_STATUS_TABLE:
89                 case DM_ULOG_CHECKPOINT_READY:
90                 case DM_ULOG_MEMBER_JOIN:
91                         /* No incoming data */
92                         break;
93                 case DM_ULOG_IS_CLEAN:
94                 case DM_ULOG_IN_SYNC:
95                 case DM_ULOG_IS_REMOTE_RECOVERING:
96                         pu64 = (uint64_t *)rq->u_rq.data;
97                         *pu64 = xlate64(*pu64);
98                         break;
99                 case DM_ULOG_MARK_REGION:
100                 case DM_ULOG_CLEAR_REGION:
101                         end = rq->u_rq.data_size/sizeof(uint64_t);
102
103                         pu64 = (uint64_t *)rq->u_rq.data;
104                         for (i = 0; i < end; i++)
105                                 pu64[i] = xlate64(pu64[i]);
106                         break;
107                 case DM_ULOG_SET_REGION_SYNC:
108                         pu64 = (uint64_t *)rq->u_rq.data;
109                         pi64 = ((int64_t *)rq->u_rq.data) + 1;
110                         *pu64 = xlate64(*pu64);
111                         *pi64 = xlate64(*pi64);
112                         break;
113                 default:
114                         LOG_ERROR("Unknown request type, %u", rq_type);
115                         exit(EXIT_FAILURE);
116                 }
117         }
118 }
119
120 static int v5_endian_to_network(struct clog_request *rq)
121 {
122         int size;
123         struct dm_ulog_request *u_rq = &rq->u_rq;
124
125         size = sizeof(*rq) + u_rq->data_size;
126
127         u_rq->error = xlate32(u_rq->error);
128         u_rq->seq = xlate32(u_rq->seq);
129         u_rq->request_type = xlate32(u_rq->request_type);
130         u_rq->data_size = xlate64(u_rq->data_size);
131
132         rq->originator = xlate32(rq->originator);
133
134         v5_data_endian_switch(rq, 1);
135
136         return size;
137 }
138
139 int clog_request_to_network(struct clog_request *rq)
140 {
141         int r;
142
143         /* FIXME: Remove this safety check */
144         if (rq->u.version[0] != xlate64(rq->u.version[1])) {
145                 LOG_ERROR("Programmer error:  version[0] must be LE");
146                 exit(EXIT_FAILURE);
147         }
148
149         /*
150          * Are we already running in the endian mode we send
151          * over the wire?
152          */
153         if (rq->u.version[0] == rq->u.version[1])
154                 return 0;
155
156         r = v5_endian_to_network(rq);
157         if (r < 0)
158                 return r;
159         return 0;
160 }
161
162 static int v5_endian_from_network(struct clog_request *rq)
163 {
164         int size;
165         struct dm_ulog_request *u_rq = &rq->u_rq;
166
167         u_rq->error = xlate32(u_rq->error);
168         u_rq->seq = xlate32(u_rq->seq);
169         u_rq->request_type = xlate32(u_rq->request_type);
170         u_rq->data_size = xlate64(u_rq->data_size);
171
172         rq->originator = xlate32(rq->originator);
173
174         size = sizeof(*rq) + u_rq->data_size;
175
176         v5_data_endian_switch(rq, 0);
177
178         return size;
179 }
180
181 int clog_request_from_network(void *data, size_t data_len)
182 {
183         uint64_t *vp = data;
184         uint64_t version = xlate64(vp[0]);
185         uint64_t unconverted_version = vp[1];
186         struct clog_request *rq = data;
187
188         switch (version) {
189         case 5: /* Upstream */
190                 if (version == unconverted_version)
191                         return 0;
192                 break;
193         case 4: /* RHEL 5.[45] */
194         case 3: /* RHEL 5.3 */
195         case 2: /* RHEL 5.2 */
196                 /* FIXME: still need to account for payload */
197                 if (data_len < (COMPAT_OFFSET + sizeof(*rq)))
198                         return -ENOSPC;
199
200                 rq = (struct clog_request *)((char *)data + COMPAT_OFFSET);
201                 break;
202         default:
203                 LOG_ERROR("Unable to process cluster message: "
204                           "Incompatible version");
205                 return -EINVAL;
206         }
207
208         v5_endian_from_network(rq);
209         return 0;
210 }