]> git.proxmox.com Git - pve-cluster.git/blob - data/src/quorum.c
3de54b33b1027a66e81b16cd41d632f9575c9660
[pve-cluster.git] / data / src / quorum.c
1 /*
2 Copyright (C) 2010 Proxmox Server Solutions GmbH
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Affero General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Affero General Public License for more details.
13
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 Author: Dietmar Maurer <dietmar@proxmox.com>
18
19 */
20
21 #define G_LOG_DOMAIN "quorum"
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif /* HAVE_CONFIG_H */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <glib.h>
32
33 #include <corosync/quorum.h>
34
35 #include "cfs-utils.h"
36 #include "loop.h"
37 #include "status.h"
38
39 typedef struct {
40 quorum_handle_t handle;
41 } qs_private_t;
42
43 static void quorum_notification_fn(
44 quorum_handle_t handle,
45 uint32_t quorate,
46 uint64_t ring_id,
47 uint32_t view_list_entries,
48 uint32_t *view_list)
49 {
50 cs_error_t result;
51
52 cfs_debug("quorum notification called, quorate = %d, "
53 "number of nodes = %d", quorate, view_list_entries);
54
55 qs_private_t *private = NULL;
56
57 result = quorum_context_get(handle, (gconstpointer *)&private);
58 if (result != CS_OK || !private) {
59 cfs_critical("quorum_context_get error: %d (%p)", result, (void *) private);
60 return;
61 }
62
63 cfs_set_quorate(quorate, FALSE);
64 }
65
66 static quorum_callbacks_t quorum_callbacks = {
67 .quorum_notify_fn = quorum_notification_fn,
68 };
69
70 static gboolean service_quorum_finalize(
71 cfs_service_t *service,
72 gpointer context)
73 {
74 g_return_val_if_fail(service != NULL, FALSE);
75 g_return_val_if_fail(context != NULL, FALSE);
76
77 qs_private_t *private = (qs_private_t *)context;
78 quorum_handle_t handle = private->handle;
79
80 cs_error_t result;
81
82 cfs_set_quorate(0, TRUE);
83
84 result = quorum_finalize(handle);
85 private->handle = 0;
86 if (result != CS_OK) {
87 cfs_critical("quorum_finalize failed: %d", result);
88 return FALSE;
89 }
90
91 return TRUE;
92 }
93
94 static int service_quorum_initialize(
95 cfs_service_t *service,
96 gpointer context)
97 {
98 g_return_val_if_fail(service != NULL, FALSE);
99 g_return_val_if_fail(context != NULL, FALSE);
100
101 qs_private_t *private = (qs_private_t *)context;
102
103 quorum_handle_t handle = private->handle;
104 cs_error_t result;
105
106 if (!private->handle) {
107
108 uint32_t quorum_type;
109
110 result = quorum_initialize(&handle, &quorum_callbacks, &quorum_type);
111 if (result != CS_OK) {
112 cfs_critical("quorum_initialize failed: %d", result);
113 goto err_reset_handle;
114 }
115
116 if (quorum_type != QUORUM_SET) {
117 cfs_critical("quorum_initialize returned wrong quorum_type: %d", quorum_type);
118 goto err_finalize;
119 }
120
121 result = quorum_context_set(handle, private);
122 if (result != CS_OK) {
123 cfs_critical("quorum_context_set failed: %d", result);
124 goto err_finalize;
125 }
126
127 private->handle = handle;
128 }
129
130
131 result = quorum_trackstart(handle, CS_TRACK_CHANGES);
132 if (result == CS_ERR_LIBRARY || result == CS_ERR_BAD_HANDLE) {
133 cfs_critical("quorum_trackstart failed: %d - closing handle", result);
134 goto err_finalize;
135 } else if (result != CS_OK) {
136 cfs_critical("quorum_trackstart failed: %d - trying again", result);
137 return -1;
138 }
139
140 int quorum_fd = -1;
141 if ((result = quorum_fd_get(handle, &quorum_fd)) != CS_OK) {
142 cfs_critical("quorum_fd_get failed %d - trying again", result);
143 return -1;
144 }
145
146 return quorum_fd;
147
148 err_finalize:
149 cfs_set_quorate(0, FALSE);
150 quorum_finalize(handle);
151 err_reset_handle:
152 private->handle = 0;
153 return -1;
154 }
155
156 static gboolean service_quorum_dispatch(
157 cfs_service_t *service,
158 gpointer context)
159 {
160 g_return_val_if_fail(service != NULL, FALSE);
161 g_return_val_if_fail(context != NULL, FALSE);
162
163 qs_private_t *private = (qs_private_t *)context;
164 quorum_handle_t handle = private->handle;
165
166 cs_error_t result;
167
168 int retries = 0;
169 loop:
170 result = quorum_dispatch(handle, CS_DISPATCH_ALL);
171 if (result == CS_ERR_TRY_AGAIN) {
172 usleep(100000);
173 ++retries;
174 if ((retries % 100) == 0)
175 cfs_message("quorum_dispatch retry %d", retries);
176 goto loop;
177 }
178
179
180 if (result == CS_OK || result == CS_ERR_TRY_AGAIN)
181 return TRUE;
182
183 cfs_critical("quorum_dispatch failed: %d", result);
184
185 cfs_set_quorate(0, FALSE);
186 quorum_finalize(handle);
187 private->handle = 0;
188 return FALSE;
189 }
190
191 static cfs_service_callbacks_t cfs_quorum_callbacks = {
192 .cfs_service_initialize_fn = service_quorum_initialize,
193 .cfs_service_finalize_fn = service_quorum_finalize,
194 .cfs_service_dispatch_fn = service_quorum_dispatch,
195 };
196
197 cfs_service_t *service_quorum_new(void)
198 {
199 cfs_service_t *service;
200
201 qs_private_t *private = g_new0(qs_private_t, 1);
202 if (!private)
203 return NULL;
204
205 service = cfs_service_new(&cfs_quorum_callbacks, G_LOG_DOMAIN, private);
206
207 return service;
208 }
209
210 void service_quorum_destroy(cfs_service_t *service)
211 {
212 g_return_if_fail(service != NULL);
213
214 qs_private_t *private =
215 (qs_private_t *)cfs_service_get_context(service);
216
217 g_free(private);
218 g_free(service);
219 }