corosync  2.4.2-dirty
lib/quorum.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2012 Red Hat, Inc.
3  *
4  * All rights reserved.
5  *
6  * Author: Christine Caulfield (ccaulfie@redhat.com)
7  *
8  * This software licensed under BSD license, the text of which follows:
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * - Redistributions of source code must retain the above copyright notice,
14  * this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  * - Neither the name of the MontaVista Software, Inc. nor the names of its
19  * contributors may be used to endorse or promote products derived from this
20  * software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 /*
35  * Provides a quorum API using the corosync executive
36  */
37 
38 #include <config.h>
39 
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <sys/uio.h>
46 #include <errno.h>
47 
48 #include <qb/qbipcc.h>
49 #include <corosync/corotypes.h>
50 #include <corosync/corodefs.h>
51 #include <corosync/hdb.h>
52 
53 #include <corosync/quorum.h>
54 #include <corosync/ipc_quorum.h>
55 
56 #include "util.h"
57 
58 struct quorum_inst {
59  qb_ipcc_connection_t *c;
60  int finalize;
61  const void *context;
63 };
64 
65 static void quorum_inst_free (void *inst);
66 
67 DECLARE_HDB_DATABASE(quorum_handle_t_db, quorum_inst_free);
68 
70  quorum_handle_t *handle,
72  uint32_t *quorum_type)
73 {
74  cs_error_t error;
75  struct quorum_inst *quorum_inst;
76  struct iovec iov;
77  struct qb_ipc_request_header req;
78  struct res_lib_quorum_gettype res_lib_quorum_gettype;
79 
80  error = hdb_error_to_cs(hdb_handle_create (&quorum_handle_t_db, sizeof (struct quorum_inst), handle));
81  if (error != CS_OK) {
82  goto error_no_destroy;
83  }
84 
85  error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, *handle, (void *)&quorum_inst));
86  if (error != CS_OK) {
87  goto error_destroy;
88  }
89 
90  error = CS_OK;
91  quorum_inst->finalize = 0;
92  quorum_inst->c = qb_ipcc_connect ("quorum", IPC_REQUEST_SIZE);
93  if (quorum_inst->c == NULL) {
94  error = qb_to_cs_error(-errno);
95  goto error_put_destroy;
96  }
97 
98  req.size = sizeof (req);
100 
101  iov.iov_base = (char *)&req;
102  iov.iov_len = sizeof (req);
103 
104  error = qb_to_cs_error(qb_ipcc_sendv_recv (
105  quorum_inst->c,
106  &iov,
107  1,
108  &res_lib_quorum_gettype,
109  sizeof (struct res_lib_quorum_gettype), -1));
110 
111  if (error != CS_OK) {
112  goto error_put_destroy;
113  }
114 
115  error = res_lib_quorum_gettype.header.error;
116 
117  *quorum_type = res_lib_quorum_gettype.quorum_type;
118 
119  if (callbacks)
120  memcpy(&quorum_inst->callbacks, callbacks, sizeof (*callbacks));
121  else
122  memset(&quorum_inst->callbacks, 0, sizeof (*callbacks));
123 
124  (void)hdb_handle_put (&quorum_handle_t_db, *handle);
125 
126  return (CS_OK);
127 
128 error_put_destroy:
129  (void)hdb_handle_put (&quorum_handle_t_db, *handle);
130 error_destroy:
131  (void)hdb_handle_destroy (&quorum_handle_t_db, *handle);
132 error_no_destroy:
133  return (error);
134 }
135 
136 static void quorum_inst_free (void *inst)
137 {
138  struct quorum_inst *quorum_inst = (struct quorum_inst *)inst;
139  qb_ipcc_disconnect(quorum_inst->c);
140 }
141 
143  quorum_handle_t handle)
144 {
145  struct quorum_inst *quorum_inst;
146  cs_error_t error;
147 
148  error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
149  if (error != CS_OK) {
150  return (error);
151  }
152 
153  /*
154  * Another thread has already started finalizing
155  */
156  if (quorum_inst->finalize) {
157  (void)hdb_handle_put (&quorum_handle_t_db, handle);
158  return (CS_ERR_BAD_HANDLE);
159  }
160 
161  quorum_inst->finalize = 1;
162 
163  (void)hdb_handle_destroy (&quorum_handle_t_db, handle);
164 
165  (void)hdb_handle_put (&quorum_handle_t_db, handle);
166 
167  return (CS_OK);
168 }
169 
171  quorum_handle_t handle,
172  int *quorate)
173 {
174  cs_error_t error;
175  struct quorum_inst *quorum_inst;
176  struct iovec iov;
177  struct qb_ipc_request_header req;
178  struct res_lib_quorum_getquorate res_lib_quorum_getquorate;
179 
180  error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
181  if (error != CS_OK) {
182  return (error);
183  }
184 
185  req.size = sizeof (req);
187 
188  iov.iov_base = (char *)&req;
189  iov.iov_len = sizeof (req);
190 
191  error = qb_to_cs_error(qb_ipcc_sendv_recv (
192  quorum_inst->c,
193  &iov,
194  1,
195  &res_lib_quorum_getquorate,
196  sizeof (struct res_lib_quorum_getquorate), CS_IPC_TIMEOUT_MS));
197 
198  if (error != CS_OK) {
199  goto error_exit;
200  }
201 
202  error = res_lib_quorum_getquorate.header.error;
203 
204  *quorate = res_lib_quorum_getquorate.quorate;
205 
206 error_exit:
207  (void)hdb_handle_put (&quorum_handle_t_db, handle);
208 
209  return (error);
210 }
211 
213  quorum_handle_t handle,
214  int *fd)
215 {
216  cs_error_t error;
217  struct quorum_inst *quorum_inst;
218 
219  error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
220  if (error != CS_OK) {
221  return (error);
222  }
223 
224  error = qb_to_cs_error(qb_ipcc_fd_get (quorum_inst->c, fd));
225 
226  (void)hdb_handle_put (&quorum_handle_t_db, handle);
227 
228  return (error);
229 }
230 
231 
233  quorum_handle_t handle,
234  const void **context)
235 {
236  cs_error_t error;
237  struct quorum_inst *quorum_inst;
238 
239  error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
240  if (error != CS_OK) {
241  return (error);
242  }
243 
244  *context = quorum_inst->context;
245 
246  (void)hdb_handle_put (&quorum_handle_t_db, handle);
247 
248  return (CS_OK);
249 }
250 
252  quorum_handle_t handle,
253  const void *context)
254 {
255  cs_error_t error;
256  struct quorum_inst *quorum_inst;
257 
258  error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
259  if (error != CS_OK) {
260  return (error);
261  }
262 
263  quorum_inst->context = context;
264 
265  (void)hdb_handle_put (&quorum_handle_t_db, handle);
266 
267  return (CS_OK);
268 }
269 
270 
272  quorum_handle_t handle,
273  unsigned int flags )
274 {
275  cs_error_t error;
276  struct quorum_inst *quorum_inst;
277  struct iovec iov;
278  struct req_lib_quorum_trackstart req_lib_quorum_trackstart;
279  struct qb_ipc_response_header res;
280 
281  error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
282  if (error != CS_OK) {
283  return (error);
284  }
285 
286  req_lib_quorum_trackstart.header.size = sizeof (struct req_lib_quorum_trackstart);
287  req_lib_quorum_trackstart.header.id = MESSAGE_REQ_QUORUM_TRACKSTART;
288  req_lib_quorum_trackstart.track_flags = flags;
289 
290  iov.iov_base = (char *)&req_lib_quorum_trackstart;
291  iov.iov_len = sizeof (struct req_lib_quorum_trackstart);
292 
293  error = qb_to_cs_error(qb_ipcc_sendv_recv (
294  quorum_inst->c,
295  &iov,
296  1,
297  &res,
298  sizeof (res), CS_IPC_TIMEOUT_MS));
299 
300  if (error != CS_OK) {
301  goto error_exit;
302  }
303 
304  error = res.error;
305 
306 error_exit:
307  (void)hdb_handle_put (&quorum_handle_t_db, handle);
308 
309  return (error);
310 }
311 
313  quorum_handle_t handle)
314 {
315  cs_error_t error;
316  struct quorum_inst *quorum_inst;
317  struct iovec iov;
318  struct qb_ipc_request_header req;
319  struct qb_ipc_response_header res;
320 
321  error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
322  if (error != CS_OK) {
323  return (error);
324  }
325 
326  req.size = sizeof (req);
328 
329  iov.iov_base = (char *)&req;
330  iov.iov_len = sizeof (req);
331 
332  error = qb_to_cs_error(qb_ipcc_sendv_recv (
333  quorum_inst->c,
334  &iov,
335  1,
336  &res,
337  sizeof (res), CS_IPC_TIMEOUT_MS));
338 
339  if (error != CS_OK) {
340  goto error_exit;
341  }
342 
343  error = res.error;
344 
345 error_exit:
346  (void)hdb_handle_put (&quorum_handle_t_db, handle);
347 
348  return (error);
349 }
350 
352  quorum_handle_t handle,
353  cs_dispatch_flags_t dispatch_types)
354 {
355  int timeout = -1;
356  cs_error_t error;
357  int cont = 1; /* always continue do loop except when set to 0 */
358  struct quorum_inst *quorum_inst;
360  struct qb_ipc_response_header *dispatch_data;
361  char dispatch_buf[IPC_DISPATCH_SIZE];
363 
364  if (dispatch_types != CS_DISPATCH_ONE &&
365  dispatch_types != CS_DISPATCH_ALL &&
366  dispatch_types != CS_DISPATCH_BLOCKING &&
367  dispatch_types != CS_DISPATCH_ONE_NONBLOCKING) {
368 
369  return (CS_ERR_INVALID_PARAM);
370  }
371 
372  error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle,
373  (void *)&quorum_inst));
374  if (error != CS_OK) {
375  return (error);
376  }
377 
378  /*
379  * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and
380  * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING
381  */
382  if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
383  timeout = 0;
384  }
385 
386  dispatch_data = (struct qb_ipc_response_header *)dispatch_buf;
387  do {
388  error = qb_to_cs_error (qb_ipcc_event_recv (
389  quorum_inst->c,
390  dispatch_buf,
392  timeout));
393  if (error == CS_ERR_BAD_HANDLE) {
394  error = CS_OK;
395  goto error_put;
396  }
397  if (error == CS_ERR_TRY_AGAIN) {
398  if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
399  /*
400  * Don't mask error
401  */
402  goto error_put;
403  }
404  error = CS_OK;
405  if (dispatch_types == CS_DISPATCH_ALL) {
406  break; /* exit do while cont is 1 loop */
407  } else {
408  continue; /* next poll */
409  }
410  }
411  if (error != CS_OK) {
412  goto error_put;
413  }
414 
415  /*
416  * Make copy of callbacks, message data, unlock instance, and call callback
417  * A risk of this dispatch method is that the callback routines may
418  * operate at the same time that quorum_finalize has been called in another thread.
419  */
420  memcpy (&callbacks, &quorum_inst->callbacks, sizeof (quorum_callbacks_t));
421  /*
422  * Dispatch incoming message
423  */
424  switch (dispatch_data->id) {
425 
427  if (callbacks.quorum_notify_fn == NULL) {
428  break;
429  }
430  res_lib_quorum_notification = (struct res_lib_quorum_notification *)dispatch_data;
431 
432  callbacks.quorum_notify_fn ( handle,
433  res_lib_quorum_notification->quorate,
434  res_lib_quorum_notification->ring_seq,
435  res_lib_quorum_notification->view_list_entries,
436  res_lib_quorum_notification->view_list);
437  break;
438 
439  default:
440  error = CS_ERR_LIBRARY;
441  goto error_put;
442  break;
443  }
444  if (quorum_inst->finalize) {
445  /*
446  * If the finalize has been called then get out of the dispatch.
447  */
448  error = CS_ERR_BAD_HANDLE;
449  goto error_put;
450  }
451 
452  /*
453  * Determine if more messages should be processed
454  */
455  if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
456  cont = 0;
457  }
458  } while (cont);
459 
460 error_put:
461  (void)hdb_handle_put (&quorum_handle_t_db, handle);
462  return (error);
463 }
The res_lib_quorum_getquorate struct.
Definition: ipc_quorum.h:72
quorum_callbacks_t callbacks
Definition: lib/quorum.c:62
cs_error_t hdb_error_to_cs(int res)
int finalize
Definition: lib/quorum.c:60
cs_error_t quorum_dispatch(quorum_handle_t handle, cs_dispatch_flags_t dispatch_types)
Dispatch messages and configuration changes.
Definition: lib/quorum.c:351
The req_lib_quorum_trackstart struct.
Definition: ipc_quorum.h:64
The quorum_callbacks_t struct.
The res_lib_quorum_notification struct.
Definition: ipc_quorum.h:80
cs_error_t quorum_trackstop(quorum_handle_t handle)
quorum_trackstop
Definition: lib/quorum.c:312
cs_error_t quorum_getquorate(quorum_handle_t handle, int *quorate)
Get quorum information.
Definition: lib/quorum.c:170
cs_error_t quorum_context_get(quorum_handle_t handle, const void **context)
quorum_context_get
Definition: lib/quorum.c:232
#define IPC_DISPATCH_SIZE
Definition: lib/util.h:51
cs_error_t quorum_context_set(quorum_handle_t handle, const void *context)
quorum_context_set
Definition: lib/quorum.c:251
mar_uint32_t view_list[]
Definition: ipc_quorum.h:85
uint32_t flags
#define IPC_REQUEST_SIZE
Definition: lib/util.h:49
cs_error_t
The cs_error_t enum.
Definition: corotypes.h:94
cs_dispatch_flags_t
The cs_dispatch_flags_t enum.
Definition: corotypes.h:80
uint32_t quorate
Definition: sam.c:134
uint64_t quorum_handle_t
quorum_handle_t
The res_lib_quorum_gettype struct.
Definition: ipc_quorum.h:91
unsigned int track_flags
Definition: ipc_quorum.h:66
cs_error_t quorum_fd_get(quorum_handle_t handle, int *fd)
Get a file descriptor on which to poll.
Definition: lib/quorum.c:212
DECLARE_HDB_DATABASE(quorum_handle_t_db, quorum_inst_free)
quorum_notification_fn_t quorum_notify_fn
mar_uint32_t quorum_type
Definition: ipc_quorum.h:93
cs_error_t quorum_trackstart(quorum_handle_t handle, unsigned int flags)
Track node and quorum changes.
Definition: lib/quorum.c:271
const void * context
Definition: lib/quorum.c:61
qb_ipcc_connection_t * c
Definition: lib/quorum.c:59
#define CS_IPC_TIMEOUT_MS
Definition: corotypes.h:127
cs_error_t qb_to_cs_error(int result)
qb_to_cs_error
cs_error_t quorum_finalize(quorum_handle_t handle)
Close the quorum handle.
Definition: lib/quorum.c:142
cs_error_t quorum_initialize(quorum_handle_t *handle, quorum_callbacks_t *callbacks, uint32_t *quorum_type)
Create a new quorum connection.
Definition: lib/quorum.c:69