10
#include <glusterfs/common-utils.h>
11
#include "glusterd-utils.h"
12
#include "glusterd-messages.h"
13
#include "glusterd-server-quorum.h"
14
#include "glusterd-store.h"
15
#include "glusterd-syncop.h"
16
#include "glusterd-op-sm.h"
18
#define CEILING_POS(X) (((X) - (int)(X)) > 0 ? (int)((X) + 1) : (int)(X))
21
glusterd_is_get_op(xlator_t *this, glusterd_op_t op, dict_t *dict)
27
if (op == GD_OP_STATUS_VOLUME)
30
if (op == GD_OP_SET_VOLUME) {
32
ret = dict_get_str(dict, "volname", &volname);
33
if (volname && ((strcmp(volname, "help") == 0) ||
34
(strcmp(volname, "help-xml") == 0))) {
35
ret = dict_get_str(dict, "key1", &key);
44
glusterd_is_quorum_validation_required(xlator_t *this, glusterd_op_t op,
47
gf_boolean_t required = _gf_true;
49
char *key_fixed = NULL;
52
if (glusterd_is_get_op(this, op, dict)) {
56
if ((op != GD_OP_SET_VOLUME) && (op != GD_OP_RESET_VOLUME))
58
if (op == GD_OP_SET_VOLUME)
59
ret = dict_get_str(dict, "key1", &key);
60
else if (op == GD_OP_RESET_VOLUME)
61
ret = dict_get_str(dict, "key", &key);
64
ret = glusterd_check_option_exists(key, &key_fixed);
69
if (glusterd_is_quorum_option(key))
77
glusterd_validate_quorum(xlator_t *this, glusterd_op_t op, dict_t *dict,
82
glusterd_volinfo_t *volinfo = NULL;
85
errstr = "Quorum not met. Volume operation not allowed.";
86
if (!glusterd_is_quorum_validation_required(this, op, dict))
89
ret = dict_get_str(dict, "volname", &volname);
91
gf_smsg(this->name, GF_LOG_ERROR, -ret, GD_MSG_DICT_GET_FAILED,
97
ret = glusterd_volinfo_find(volname, &volinfo);
103
if (!glusterd_is_volume_in_server_quorum(volinfo)) {
108
if (does_gd_meet_server_quorum(this)) {
114
*op_errstr = gf_strdup(errstr);
121
glusterd_is_quorum_option(char *option)
123
gf_boolean_t res = _gf_false;
125
static const char *const keys[] = {GLUSTERD_QUORUM_TYPE_KEY,
126
GLUSTERD_QUORUM_RATIO_KEY, NULL};
128
for (i = 0; keys[i]; i++) {
129
if (strcmp(option, keys[i]) == 0) {
138
glusterd_is_quorum_changed(dict_t *options, char *option, char *value)
141
gf_boolean_t reconfigured = _gf_false;
142
gf_boolean_t all = _gf_false;
143
char *oldquorum = NULL;
144
char *newquorum = NULL;
145
char *oldratio = NULL;
146
char *newratio = NULL;
147
xlator_t *this = THIS;
149
if ((strcmp("all", option) != 0) && !glusterd_is_quorum_option(option))
152
if (strcmp("all", option) == 0)
155
if (all || (strcmp(GLUSTERD_QUORUM_TYPE_KEY, option) == 0)) {
157
ret = dict_get_str(options, GLUSTERD_QUORUM_TYPE_KEY, &oldquorum);
159
gf_msg(this->name, GF_LOG_DEBUG, 0, GD_MSG_DICT_GET_FAILED,
160
"dict_get_str failed on %s", GLUSTERD_QUORUM_TYPE_KEY);
163
if (all || (strcmp(GLUSTERD_QUORUM_RATIO_KEY, option) == 0)) {
165
ret = dict_get_str(options, GLUSTERD_QUORUM_RATIO_KEY, &oldratio);
167
gf_msg(this->name, GF_LOG_DEBUG, 0, GD_MSG_DICT_GET_FAILED,
168
"dict_get_str failed on %s", GLUSTERD_QUORUM_RATIO_KEY);
171
reconfigured = _gf_true;
173
if (oldquorum && newquorum && (strcmp(oldquorum, newquorum) == 0))
174
reconfigured = _gf_false;
175
if (oldratio && newratio && (strcmp(oldratio, newratio) == 0))
176
reconfigured = _gf_false;
178
if ((oldratio == NULL) && (newratio == NULL) && (oldquorum == NULL) &&
180
reconfigured = _gf_false;
186
_is_contributing_to_quorum(gd_quorum_contrib_t contrib)
188
if ((contrib == QUORUM_UP) || (contrib == QUORUM_DOWN))
194
does_quorum_meet(int active_count, int quorum_count)
196
return (active_count >= quorum_count);
200
glusterd_get_quorum_cluster_counts(xlator_t *this, int *active_count,
203
glusterd_peerinfo_t *peerinfo = NULL;
204
glusterd_conf_t *conf = NULL;
206
int inquorum_count = 0;
208
double quorum_percentage = 0.0;
209
gf_boolean_t ratio = _gf_false;
212
conf = this->private;
220
cds_list_for_each_entry_rcu(peerinfo, &conf->peers, uuid_list)
222
if (_is_contributing_to_quorum(peerinfo->quorum_contrib))
223
inquorum_count = inquorum_count + 1;
224
if (active_count && (peerinfo->quorum_contrib == QUORUM_UP))
225
*active_count = *active_count + 1;
229
ret = dict_get_str(conf->opts, GLUSTERD_QUORUM_RATIO_KEY, &val);
231
ret = gf_string2percent(val, &quorum_percentage);
236
count = CEILING_POS(inquorum_count * quorum_percentage / 100.0);
238
count = (inquorum_count * 50 / 100) + 1;
240
*quorum_count = count;
247
glusterd_is_volume_in_server_quorum(glusterd_volinfo_t *volinfo)
249
gf_boolean_t res = _gf_false;
250
char *quorum_type = NULL;
253
ret = dict_get_str(volinfo->dict, GLUSTERD_QUORUM_TYPE_KEY, &quorum_type);
255
gf_smsg(THIS->name, GF_LOG_DEBUG, -ret, GD_MSG_DICT_GET_FAILED,
256
"Key=%s", GLUSTERD_QUORUM_TYPE_KEY, NULL);
260
if (strcmp(quorum_type, GLUSTERD_SERVER_QUORUM) == 0)
267
glusterd_is_any_volume_in_server_quorum(xlator_t *this)
269
glusterd_conf_t *conf = NULL;
270
glusterd_volinfo_t *volinfo = NULL;
272
conf = this->private;
273
list_for_each_entry(volinfo, &conf->volumes, vol_list)
275
if (glusterd_is_volume_in_server_quorum(volinfo)) {
283
does_gd_meet_server_quorum(xlator_t *this)
285
int quorum_count = 0;
286
int active_count = 0;
287
gf_boolean_t in = _gf_false;
290
ret = glusterd_get_quorum_cluster_counts(this, &active_count,
293
gf_smsg(this->name, GF_LOG_ERROR, errno,
294
GD_MSG_QUORUM_CLUSTER_COUNT_GET_FAIL, NULL);
298
if (!does_quorum_meet(active_count, quorum_count)) {
308
glusterd_do_volume_quorum_action(xlator_t *this, glusterd_volinfo_t *volinfo,
309
gf_boolean_t meets_quorum)
312
glusterd_brickinfo_t *brickinfo = NULL;
313
gd_quorum_status_t quorum_status = NOT_APPLICABLE_QUORUM;
314
gf_boolean_t follows_quorum = _gf_false;
315
gf_boolean_t quorum_status_unchanged = _gf_false;
317
if (volinfo->status != GLUSTERD_STATUS_STARTED) {
318
volinfo->quorum_status = NOT_APPLICABLE_QUORUM;
322
follows_quorum = glusterd_is_volume_in_server_quorum(volinfo);
323
if (follows_quorum) {
325
quorum_status = MEETS_QUORUM;
327
quorum_status = DOESNT_MEET_QUORUM;
329
quorum_status = NOT_APPLICABLE_QUORUM;
343
if (volinfo->quorum_status == quorum_status) {
344
quorum_status_unchanged = _gf_true;
348
if (quorum_status == MEETS_QUORUM) {
349
gf_msg(this->name, GF_LOG_CRITICAL, 0,
350
GD_MSG_SERVER_QUORUM_MET_STARTING_BRICKS,
351
"Server quorum regained for volume %s. Starting local "
354
gf_event(EVENT_QUORUM_REGAINED, "volume=%s", volinfo->volname);
355
} else if (quorum_status == DOESNT_MEET_QUORUM) {
356
gf_msg(this->name, GF_LOG_CRITICAL, 0,
357
GD_MSG_SERVER_QUORUM_LOST_STOPPING_BRICKS,
358
"Server quorum lost for volume %s. Stopping local "
361
gf_event(EVENT_QUORUM_LOST, "volume=%s", volinfo->volname);
364
list_for_each_entry(brickinfo, &volinfo->bricks, brick_list)
366
if (!glusterd_is_local_brick(volinfo, brickinfo))
368
if (quorum_status == DOESNT_MEET_QUORUM) {
369
ret = glusterd_brick_stop(volinfo, brickinfo, _gf_false);
371
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_STOP_FAIL,
374
brickinfo->hostname, brickinfo->path);
377
if (!brickinfo->start_triggered) {
378
pthread_mutex_lock(&brickinfo->restart_mutex);
381
ret = glusterd_brick_start(volinfo, brickinfo, _gf_false,
384
pthread_mutex_unlock(&brickinfo->restart_mutex);
386
gf_msg(this->name, GF_LOG_ERROR, 0,
387
GD_MSG_BRICK_DISCONNECTED, "Failed to start %s:%s",
388
brickinfo->hostname, brickinfo->path);
393
volinfo->quorum_status = quorum_status;
394
if (quorum_status == MEETS_QUORUM) {
398
ret = glusterd_store_volinfo(volinfo, GLUSTERD_VOLINFO_VER_AC_NONE);
400
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_STORE_FAIL,
401
"Failed to write volinfo for volume %s", volinfo->volname);
406
if (quorum_status_unchanged) {
407
list_for_each_entry(brickinfo, &volinfo->bricks, brick_list)
409
if (!glusterd_is_local_brick(volinfo, brickinfo))
411
ret = glusterd_brick_start(volinfo, brickinfo, _gf_false, _gf_true);
413
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_DISCONNECTED,
416
brickinfo->hostname, brickinfo->path);
424
glusterd_do_quorum_action(void)
426
xlator_t *this = THIS;
427
glusterd_conf_t *conf = NULL;
428
glusterd_volinfo_t *volinfo = NULL;
430
int active_count = 0;
431
int quorum_count = 0;
432
gf_boolean_t meets = _gf_false;
434
conf = this->private;
436
conf->pending_quorum_action = _gf_true;
437
ret = glusterd_lock(conf->uuid);
442
ret = glusterd_get_quorum_cluster_counts(this, &active_count,
447
if (does_quorum_meet(active_count, quorum_count))
449
list_for_each_entry(volinfo, &conf->volumes, vol_list)
451
glusterd_do_volume_quorum_action(this, volinfo, meets);
455
(void)glusterd_unlock(conf->uuid);
456
conf->pending_quorum_action = _gf_false;
467
check_quorum_for_brick_start(glusterd_volinfo_t *volinfo,
468
gf_boolean_t node_quorum)
470
gf_boolean_t volume_quorum = _gf_false;
473
volume_quorum = glusterd_is_volume_in_server_quorum(volinfo);