summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
38fde8c)
cpg_mcast_joined (and transitively, cpg_join/leave) are not thread-safe.
pmxcfs triggers such operations via FUSE and CPG dispatch callbacks,
which are running in concurrent threads.
accordingly, we need to protect these operations with a mutex, otherwise
they might return CS_OK without actually doing what they were supposed
to do (which in turn can lead to the dfsm taking a wrong turn and
getting stuck in a supposedly short-lived state, blocking access via
FUSE and getting whole clusters fenced).
huge thanks to Alexandre Derumier for providing the initial bug report
and quite a lot of test runs while debugging this issue.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
cpg_callbacks_t *cpg_callbacks;
dfsm_callbacks_t *dfsm_callbacks;
cpg_handle_t cpg_handle;
cpg_callbacks_t *cpg_callbacks;
dfsm_callbacks_t *dfsm_callbacks;
cpg_handle_t cpg_handle;
struct cpg_name cpg_group_name;
uint32_t nodeid;
uint32_t pid;
struct cpg_name cpg_group_name;
uint32_t nodeid;
uint32_t pid;
cs_error_t result;
int retries = 0;
loop:
cs_error_t result;
int retries = 0;
loop:
+ g_mutex_lock (&dfsm->cpg_mutex);
result = cpg_mcast_joined(dfsm->cpg_handle, CPG_TYPE_AGREED, iov, len);
result = cpg_mcast_joined(dfsm->cpg_handle, CPG_TYPE_AGREED, iov, len);
+ g_mutex_unlock (&dfsm->cpg_mutex);
if (retry && result == CS_ERR_TRY_AGAIN) {
nanosleep(&tvreq, NULL);
++retries;
if (retry && result == CS_ERR_TRY_AGAIN) {
nanosleep(&tvreq, NULL);
++retries;
if (!(dfsm->msg_queue = g_sequence_new(NULL)))
goto err;
if (!(dfsm->msg_queue = g_sequence_new(NULL)))
goto err;
+
+ g_mutex_init(&dfsm->cpg_mutex);
+
dfsm->log_domain = log_domain;
dfsm->data = data;
dfsm->mode = DFSM_MODE_START;
dfsm->log_domain = log_domain;
dfsm->data = data;
dfsm->mode = DFSM_MODE_START;
struct timespec tvreq = { .tv_sec = 0, .tv_nsec = 100000000 };
int retries = 0;
loop:
struct timespec tvreq = { .tv_sec = 0, .tv_nsec = 100000000 };
int retries = 0;
loop:
+ g_mutex_lock (&dfsm->cpg_mutex);
result = cpg_join(dfsm->cpg_handle, &dfsm->cpg_group_name);
result = cpg_join(dfsm->cpg_handle, &dfsm->cpg_group_name);
+ g_mutex_unlock (&dfsm->cpg_mutex);
if (result == CS_ERR_TRY_AGAIN) {
nanosleep(&tvreq, NULL);
++retries;
if (result == CS_ERR_TRY_AGAIN) {
nanosleep(&tvreq, NULL);
++retries;
struct timespec tvreq = { .tv_sec = 0, .tv_nsec = 100000000 };
int retries = 0;
loop:
struct timespec tvreq = { .tv_sec = 0, .tv_nsec = 100000000 };
int retries = 0;
loop:
+ g_mutex_lock (&dfsm->cpg_mutex);
result = cpg_leave(dfsm->cpg_handle, &dfsm->cpg_group_name);
result = cpg_leave(dfsm->cpg_handle, &dfsm->cpg_group_name);
+ g_mutex_unlock (&dfsm->cpg_mutex);
if (result == CS_ERR_TRY_AGAIN) {
nanosleep(&tvreq, NULL);
++retries;
if (result == CS_ERR_TRY_AGAIN) {
nanosleep(&tvreq, NULL);
++retries;
g_mutex_clear (&dfsm->sync_mutex);
g_cond_clear (&dfsm->sync_cond);
g_mutex_clear (&dfsm->sync_mutex);
g_cond_clear (&dfsm->sync_cond);
+
+ g_mutex_clear (&dfsm->cpg_mutex);
if (dfsm->results)
g_hash_table_destroy(dfsm->results);
if (dfsm->results)
g_hash_table_destroy(dfsm->results);