summaryrefslogtreecommitdiff
path: root/daemons/clvmd/clvmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemons/clvmd/clvmd.c')
-rw-r--r--daemons/clvmd/clvmd.c498
1 files changed, 303 insertions, 195 deletions
diff --git a/daemons/clvmd/clvmd.c b/daemons/clvmd/clvmd.c
index 1a35c49..ac465d9 100644
--- a/daemons/clvmd/clvmd.c
+++ b/daemons/clvmd/clvmd.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -20,6 +20,7 @@
#include "clvmd-common.h"
#include <pthread.h>
+#include <getopt.h>
#include "clvmd-comms.h"
#include "clvm.h"
@@ -48,6 +49,7 @@
#endif
#define MAX_RETRIES 4
+#define MAX_MISSING_LEN 8000 /* Max supported clvmd message size ? */
#define ISLOCAL_CSID(c) (memcmp(c, our_csid, max_csid_len) == 0)
@@ -77,15 +79,18 @@ struct lvm_thread_cmd {
};
struct lvm_startup_params {
- int using_gulm;
- char **argv;
+ struct dm_hash_table *excl_uuid;
};
-debug_t debug;
+static debug_t debug = DEBUG_OFF;
+static int foreground_mode = 0;
static pthread_t lvm_thread;
+/* Stack size 128KiB for thread, must be bigger then DEFAULT_RESERVED_STACK */
+static const size_t STACK_SIZE = 128 * 1024;
+static pthread_attr_t stack_attr;
static pthread_mutex_t lvm_thread_mutex;
static pthread_cond_t lvm_thread_cond;
-static pthread_mutex_t lvm_start_mutex;
+static pthread_barrier_t lvm_start_barrier;
static struct dm_list lvm_cmd_head;
static volatile sig_atomic_t quit = 0;
static volatile sig_atomic_t reread_config = 0;
@@ -99,9 +104,7 @@ static int child_pipe[2];
#define DFAIL_TIMEOUT 5
#define SUCCESS 0
-typedef enum {IF_AUTO, IF_CMAN, IF_GULM, IF_OPENAIS, IF_COROSYNC, IF_SINGLENODE} if_type_t;
-
-typedef void *(lvm_pthread_fn_t)(void*);
+typedef enum {IF_AUTO, IF_CMAN, IF_OPENAIS, IF_COROSYNC, IF_SINGLENODE} if_type_t;
/* Prototypes for code further down */
static void sigusr2_handler(int sig);
@@ -132,7 +135,7 @@ static int check_all_clvmds_running(struct local_client *client);
static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
int len, const char *csid,
struct local_client **new_client);
-static void lvm_thread_fn(void *) __attribute__ ((noreturn));
+static void *lvm_thread_fn(void *) __attribute__((noreturn));
static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
int msglen, const char *csid);
static int distribute_command(struct local_client *thisfd);
@@ -145,12 +148,12 @@ static if_type_t get_cluster_type(void);
static void usage(const char *prog, FILE *file)
{
- fprintf(file, "Usage:\n"
- "%s [Vhd]\n\n"
+ fprintf(file, "Usage: %s [options]\n"
" -V Show version of clvmd\n"
" -h Show this help information\n"
- " -d Set debug level\n"
- " If starting clvmd then don't fork, run in the foreground\n"
+ " -d[n] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
+ " -f Don't fork, run in the foreground\n"
+ " -E<lockuuid> Take this lock uuid as exclusively locked resource (for restart)\n"
" -R Tell all running clvmds in the cluster to reload their device cache\n"
" -S Restart clvmd, preserving exclusive locks\n"
" -C Sets debug level (from -d) on all clvmd instances clusterwide\n"
@@ -167,9 +170,6 @@ static void usage(const char *prog, FILE *file)
#ifdef USE_OPENAIS
"openais "
#endif
-#ifdef USE_GULM
- "gulm "
-#endif
#ifdef USE_SINGLENODE
"singlenode "
#endif
@@ -199,7 +199,8 @@ static void safe_close(int *fd)
if (*fd >= 0) {
int to_close = *fd;
*fd = -1;
- close(to_close);
+ if (close(to_close))
+ log_sys_error("close", ""); /* path */
}
}
@@ -209,14 +210,15 @@ void debuglog(const char *fmt, ...)
va_list ap;
static int syslog_init = 0;
- if (debug == DEBUG_STDERR) {
+ switch (clvmd_get_debug()) {
+ case DEBUG_STDERR:
va_start(ap,fmt);
time(&P);
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 );
vfprintf(stderr, fmt, ap);
va_end(ap);
- }
- if (debug == DEBUG_SYSLOG) {
+ break;
+ case DEBUG_SYSLOG:
if (!syslog_init) {
openlog("clvmd", LOG_PID, LOG_DAEMON);
syslog_init = 1;
@@ -225,9 +227,28 @@ void debuglog(const char *fmt, ...)
va_start(ap,fmt);
vsyslog(LOG_DEBUG, fmt, ap);
va_end(ap);
+ break;
+ case DEBUG_OFF:
+ break;
}
}
+void clvmd_set_debug(debug_t new_debug)
+{
+ if (!foreground_mode && new_debug == DEBUG_STDERR)
+ new_debug = DEBUG_SYSLOG;
+
+ if (new_debug > DEBUG_SYSLOG)
+ new_debug = DEBUG_SYSLOG;
+
+ debug = new_debug;
+}
+
+debug_t clvmd_get_debug(void)
+{
+ return debug;
+}
+
static const char *decode_cmd(unsigned char cmdl)
{
static char buf[128];
@@ -276,12 +297,15 @@ static const char *decode_cmd(unsigned char cmdl)
case CLVMD_CMD_RESTART:
command = "RESTART";
break;
+ case CLVMD_CMD_SYNC_NAMES:
+ command = "SYNC_NAMES";
+ break;
default:
command = "unknown";
break;
}
- sprintf(buf, "%s (0x%x)", command, cmdl);
+ snprintf(buf, sizeof(buf), "%s (0x%x)", command, cmdl);
return buf;
}
@@ -312,52 +336,63 @@ static void check_permissions(void)
int main(int argc, char *argv[])
{
int local_sock;
- struct local_client *newfd;
- struct utsname nodeinfo;
+ struct local_client *newfd, *delfd;
struct lvm_startup_params lvm_params;
- signed char opt;
+ int opt;
int cmd_timeout = DEFAULT_CMD_TIMEOUT;
int start_timeout = 0;
if_type_t cluster_iface = IF_AUTO;
sigset_t ss;
- int using_gulm = 0;
- int debug_opt = 0;
+ debug_t debug_opt = DEBUG_OFF;
+ debug_t debug_arg = DEBUG_OFF;
int clusterwide_opt = 0;
mode_t old_mask;
+ int ret = 1;
+
+ struct option longopts[] = {
+ { "help", 0, 0, 'h' },
+ { NULL, 0, 0, 0 }
+ };
+
+ if (!(lvm_params.excl_uuid = dm_hash_create(128))) {
+ fprintf(stderr, "Failed to allocate hash table\n");
+ return 1;
+ }
/* Deal with command-line arguments */
opterr = 0;
optind = 0;
- while ((opt = getopt(argc, argv, "?vVhd::t:RST:CI:E:")) != EOF) {
+ while ((opt = getopt_long(argc, argv, "vVhfd::t:RST:CI:E:",
+ longopts, NULL)) != -1) {
switch (opt) {
case 'h':
usage(argv[0], stdout);
exit(0);
- case '?':
- usage(argv[0], stderr);
- exit(0);
-
case 'R':
check_permissions();
- return refresh_clvmd(1)==1?0:1;
+ ret = (refresh_clvmd(1) == 1) ? 0 : 1;
+ goto out;
case 'S':
check_permissions();
- return restart_clvmd(clusterwide_opt)==1?0:1;
+ ret = (restart_clvmd(clusterwide_opt) == 1) ? 0 : 1;
+ goto out;
case 'C':
clusterwide_opt = 1;
break;
case 'd':
- debug_opt = 1;
- if (optarg)
- debug = atoi(optarg);
- else
- debug = DEBUG_STDERR;
+ debug_opt = DEBUG_STDERR;
+ debug_arg = optarg ? (debug_t) atoi(optarg) : DEBUG_STDERR;
+ if (debug_arg == DEBUG_STDERR)
+ foreground_mode = 1;
break;
+ case 'f':
+ foreground_mode = 1;
+ break;
case 't':
cmd_timeout = atoi(optarg);
if (!cmd_timeout) {
@@ -369,6 +404,12 @@ int main(int argc, char *argv[])
case 'I':
cluster_iface = parse_cluster_interface(optarg);
break;
+ case 'E':
+ if (!dm_hash_insert(lvm_params.excl_uuid, optarg, optarg)) {
+ fprintf(stderr, "Failed to allocate hash entry\n");
+ goto out;
+ }
+ break;
case 'T':
start_timeout = atoi(optarg);
if (start_timeout <= 0) {
@@ -386,20 +427,14 @@ int main(int argc, char *argv[])
exit(0);
break;
+ default:
+ usage(argv[0], stderr);
+ exit(2);
}
}
check_permissions();
- /* Setting debug options on an existing clvmd */
- if (debug_opt && !check_local_clvmd()) {
-
- /* Sending to stderr makes no sense for a detached daemon */
- if (debug == DEBUG_STDERR)
- debug = DEBUG_SYSLOG;
- return debug_clvmd(debug, clusterwide_opt)==1?0:1;
- }
-
/*
* Switch to C locale to avoid reading large locale-archive file
* used by some glibc (on some distributions it takes over 100MB).
@@ -408,12 +443,19 @@ int main(int argc, char *argv[])
if (setenv("LANG", "C", 1))
perror("Cannot set LANG to C");
+ /* Setting debug options on an existing clvmd */
+ if (debug_opt && !check_local_clvmd()) {
+ dm_hash_destroy(lvm_params.excl_uuid);
+ return debug_clvmd(debug_arg, clusterwide_opt)==1?0:1;
+ }
+
+ clvmd_set_debug(debug_opt);
+
/* Fork into the background (unless requested not to) */
- if (debug != DEBUG_STDERR) {
+ if (!foreground_mode)
be_daemon(start_timeout);
- }
- dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
+ (void) dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
old_mask = umask(0077);
if (dm_create_dir(DEFAULT_RUN_DIR) == 0) {
DEBUGLOG("clvmd: unable to create %s directory\n",
@@ -447,7 +489,7 @@ int main(int argc, char *argv[])
/* Set up signal handlers, USR1 is for cluster change notifications (in cman)
USR2 causes child threads to exit.
- HUP causes gulm version to re-read nodes list from CCS.
+ (HUP used to cause gulm to re-read the nodes list from CCS.)
PIPE should be ignored */
signal(SIGUSR2, sigusr2_handler);
signal(SIGHUP, sighup_handler);
@@ -462,9 +504,14 @@ int main(int argc, char *argv[])
/* Initialise the LVM thread variables */
dm_list_init(&lvm_cmd_head);
+ if (pthread_attr_init(&stack_attr) ||
+ pthread_attr_setstacksize(&stack_attr, STACK_SIZE)) {
+ log_sys_error("pthread_attr_init", "");
+ exit(1);
+ }
pthread_mutex_init(&lvm_thread_mutex, NULL);
pthread_cond_init(&lvm_thread_cond, NULL);
- pthread_mutex_init(&lvm_start_mutex, NULL);
+ pthread_barrier_init(&lvm_start_barrier, NULL, 2);
init_lvhash();
/* Start the cluster interface */
@@ -479,16 +526,6 @@ int main(int argc, char *argv[])
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to CMAN");
}
#endif
-#ifdef USE_GULM
- if (!clops)
- if ((cluster_iface == IF_AUTO || cluster_iface == IF_GULM) && (clops = init_gulm_cluster())) {
- max_csid_len = GULM_MAX_CSID_LEN;
- max_cluster_message = GULM_MAX_CLUSTER_MESSAGE;
- max_cluster_member_name_len = GULM_MAX_CLUSTER_MEMBER_NAME_LEN;
- using_gulm = 1;
- syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to GULM");
- }
-#endif
#ifdef USE_COROSYNC
if (!clops)
if (((cluster_iface == IF_AUTO || cluster_iface == IF_COROSYNC) && (clops = init_corosync_cluster()))) {
@@ -526,7 +563,6 @@ int main(int argc, char *argv[])
DEBUGLOG("Cluster ready, doing some more initialisation\n");
/* Save our CSID */
- uname(&nodeinfo);
clops->get_our_csid(our_csid);
/* Initialise the FD list head */
@@ -553,16 +589,12 @@ int main(int argc, char *argv[])
DEBUGLOG("starting LVM thread\n");
/* Don't let anyone else to do work until we are started */
- pthread_mutex_lock(&lvm_start_mutex);
- lvm_params.using_gulm = using_gulm;
- lvm_params.argv = argv;
- pthread_create(&lvm_thread, NULL, (lvm_pthread_fn_t*)lvm_thread_fn,
- (void *)&lvm_params);
+ pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params);
+
+ /* Don't start until the LVM thread is ready */
+ pthread_barrier_wait(&lvm_start_barrier);
/* Tell the rest of the cluster our version number */
- /* CMAN can do this immediately, gulm needs to wait until
- the core initialisation has finished and the node list
- has been gathered */
if (clops->cluster_init_completed)
clops->cluster_init_completed();
@@ -576,15 +608,39 @@ int main(int argc, char *argv[])
/* Do some work */
main_loop(local_sock, cmd_timeout);
+ pthread_mutex_lock(&lvm_thread_mutex);
+ pthread_cond_signal(&lvm_thread_cond);
+ pthread_mutex_unlock(&lvm_thread_mutex);
+ if ((errno = pthread_join(lvm_thread, NULL)))
+ log_sys_error("pthread_join", "");
+
close_local_sock(local_sock);
destroy_lvm();
- return 0;
+ for (newfd = local_client_head.next; newfd != NULL;) {
+ delfd = newfd;
+ newfd = newfd->next;
+ if (delfd->fd == local_sock)
+ delfd->fd = -1;
+ /*
+ * FIXME:
+ * needs cleanup code from read_from_local_sock() for now
+ * break of 'clvmd' may access already free memory here.
+ */
+ safe_close(&(delfd->fd));
+ free(delfd);
+ }
+
+ ret = 0;
+out:
+ dm_hash_destroy(lvm_params.excl_uuid);
+
+ return ret;
}
-/* Called when the GuLM cluster layer has completed initialisation.
+/* Called when the cluster layer has completed initialisation.
We send the version message */
-void clvmd_cluster_init_completed()
+void clvmd_cluster_init_completed(void)
{
send_version_message();
}
@@ -616,7 +672,8 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
if (client_fd >= 0) {
newfd = malloc(sizeof(struct local_client));
if (!newfd) {
- close(client_fd);
+ if (close(client_fd))
+ log_sys_error("close", "socket");
return 1;
}
@@ -666,9 +723,9 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
/* EOF on pipe or an error, close it */
if (len <= 0) {
- int jstat;
void *ret = &status;
- close(thisfd->fd);
+ if (close(thisfd->fd))
+ log_sys_error("close", "local_pipe");
/* Clear out the cross-link */
if (thisfd->bits.pipe.client != NULL)
@@ -677,7 +734,10 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
/* Reap child thread */
if (thisfd->bits.pipe.threadid) {
- jstat = pthread_join(thisfd->bits.pipe.threadid, &ret);
+ if ((errno = pthread_join(thisfd->bits.pipe.threadid,
+ &ret)))
+ log_sys_error("pthread_join", "");
+
thisfd->bits.pipe.threadid = 0;
if (thisfd->bits.pipe.client != NULL)
thisfd->bits.pipe.client->bits.localsock.
@@ -689,27 +749,25 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
status, sock_client);
/* But has the client gone away ?? */
if (sock_client == NULL) {
- DEBUGLOG
- ("Got PIPE response for dead client, ignoring it\n");
+ DEBUGLOG("Got PIPE response for dead client, ignoring it\n");
} else {
/* If error then just return that code */
if (status)
send_local_reply(sock_client, status,
sock_client->fd);
else {
- if (sock_client->bits.localsock.state ==
- POST_COMMAND) {
+ /* FIXME: closer inspect this code since state is write thread protected */
+ pthread_mutex_lock(&sock_client->bits.localsock.mutex);
+ if (sock_client->bits.localsock.state == POST_COMMAND) {
+ pthread_mutex_unlock(&sock_client->bits.localsock.mutex);
send_local_reply(sock_client, 0,
sock_client->fd);
- } else // PRE_COMMAND finished.
- {
- if (
- (status =
- distribute_command(sock_client)) !=
- 0) send_local_reply(sock_client,
- EFBIG,
- sock_client->
- fd);
+ } else {
+ /* PRE_COMMAND finished. */
+ pthread_mutex_unlock(&sock_client->bits.localsock.mutex);
+ if ((status = distribute_command(sock_client)))
+ send_local_reply(sock_client, EFBIG,
+ sock_client->fd);
}
}
}
@@ -774,9 +832,10 @@ static void request_timed_out(struct local_client *client)
/* This is where the real work happens */
static void main_loop(int local_sock, int cmd_timeout)
{
+ sigset_t ss;
+
DEBUGLOG("Using timeout of %d seconds\n", cmd_timeout);
- sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGINT);
sigaddset(&ss, SIGTERM);
@@ -827,7 +886,6 @@ static void main_loop(int local_sock, int cmd_timeout)
struct local_client *free_fd;
lastfd->next = thisfd->next;
free_fd = thisfd;
- thisfd = lastfd;
DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
@@ -863,7 +921,6 @@ static void main_loop(int local_sock, int cmd_timeout)
ret, errno);
lastfd->next = thisfd->next;
free_fd = thisfd;
- thisfd = lastfd;
safe_close(&(free_fd->fd));
/* Queue cleanup, this also frees the client struct */
@@ -987,7 +1044,10 @@ static void be_daemon(int timeout)
exit(3);
}
- pipe(child_pipe);
+ if (pipe(child_pipe)) {
+ perror("Error creating pipe");
+ exit(3);
+ }
switch (fork()) {
case -1:
@@ -995,11 +1055,11 @@ static void be_daemon(int timeout)
exit(2);
case 0: /* Child */
- close(child_pipe[0]);
+ (void) close(child_pipe[0]);
break;
default: /* Parent */
- close(child_pipe[1]);
+ (void) close(child_pipe[1]);
wait_for_child(child_pipe[0], timeout);
}
@@ -1030,9 +1090,9 @@ static int read_from_local_sock(struct local_client *thisfd)
int len;
int argslen;
int missing_len;
- char buffer[PIPE_BUF];
+ char buffer[PIPE_BUF + 1];
- len = read(thisfd->fd, buffer, sizeof(buffer));
+ len = read(thisfd->fd, buffer, sizeof(buffer) - 1);
if (len == -1 && errno == EINTR)
return 1;
@@ -1041,7 +1101,6 @@ static int read_from_local_sock(struct local_client *thisfd)
/* EOF or error on socket */
if (len <= 0) {
int *status;
- int jstat;
DEBUGLOG("EOF on local socket: inprogress=%d\n",
thisfd->bits.localsock.in_progress);
@@ -1068,9 +1127,10 @@ static int read_from_local_sock(struct local_client *thisfd)
pthread_cond_signal(&thisfd->bits.localsock.cond);
pthread_mutex_unlock(&thisfd->bits.localsock.mutex);
- jstat =
- pthread_join(thisfd->bits.localsock.threadid,
- (void **) &status);
+ if ((errno = pthread_join(thisfd->bits.localsock.threadid,
+ (void **) &status)))
+ log_sys_error("pthread_join", "");
+
DEBUGLOG("Joined child thread\n");
thisfd->bits.localsock.threadid = 0;
@@ -1083,8 +1143,8 @@ static int read_from_local_sock(struct local_client *thisfd)
struct local_client *lastfd = NULL;
struct local_client *free_fd = NULL;
- close(thisfd->bits.localsock.pipe_client->fd); /* Close pipe */
- close(thisfd->bits.localsock.pipe);
+ (void) close(thisfd->bits.localsock.pipe_client->fd); /* Close pipe */
+ (void) close(thisfd->bits.localsock.pipe);
/* Remove pipe client */
for (newfd = &local_client_head; newfd != NULL;
@@ -1122,6 +1182,7 @@ static int read_from_local_sock(struct local_client *thisfd)
struct clvm_header *inheader;
int status;
+ buffer[len] = 0; /* Ensure \0 terminated */
inheader = (struct clvm_header *) buffer;
/* Fill in the client ID */
@@ -1129,20 +1190,16 @@ static int read_from_local_sock(struct local_client *thisfd)
/* If we are already busy then return an error */
if (thisfd->bits.localsock.in_progress) {
- struct clvm_header reply;
- reply.cmd = CLVMD_CMD_REPLY;
- reply.status = EBUSY;
- reply.arglen = 0;
- reply.flags = 0;
+ struct clvm_header reply = {
+ .cmd = CLVMD_CMD_REPLY,
+ .status = EBUSY
+ };
send_message(&reply, sizeof(reply), our_csid,
thisfd->fd,
"Error sending EBUSY reply to local user");
return len;
}
- /* Free any old buffer space */
- free(thisfd->bits.localsock.cmd);
-
/* See if we have the whole message */
argslen =
len - strlen(inheader->node) - sizeof(struct clvm_header);
@@ -1151,15 +1208,30 @@ static int read_from_local_sock(struct local_client *thisfd)
if (missing_len < 0)
missing_len = 0;
+ /* We need at least sizeof(struct clvm_header) bytes in buffer */
+ if (len < sizeof(struct clvm_header) || argslen < 0 ||
+ missing_len > MAX_MISSING_LEN) {
+ struct clvm_header reply = {
+ .cmd = CLVMD_CMD_REPLY,
+ .status = EINVAL
+ };
+ send_message(&reply, sizeof(reply), our_csid,
+ thisfd->fd,
+ "Error sending EINVAL reply to local user");
+ return 0;
+ }
+
+ /* Free any old buffer space */
+ free(thisfd->bits.localsock.cmd);
+
/* Save the message */
thisfd->bits.localsock.cmd = malloc(len + missing_len);
if (!thisfd->bits.localsock.cmd) {
- struct clvm_header reply;
- reply.cmd = CLVMD_CMD_REPLY;
- reply.status = ENOMEM;
- reply.arglen = 0;
- reply.flags = 0;
+ struct clvm_header reply = {
+ .cmd = CLVMD_CMD_REPLY,
+ .status = ENOMEM
+ };
send_message(&reply, sizeof(reply), our_csid,
thisfd->fd,
"Error sending ENOMEM reply to local user");
@@ -1174,15 +1246,22 @@ static int read_from_local_sock(struct local_client *thisfd)
char *argptr =
inheader->node + strlen(inheader->node) + 1;
- while (missing_len > 0 && len >= 0) {
- DEBUGLOG
- ("got %d bytes, need another %d (total %d)\n",
- argslen, missing_len, inheader->arglen);
+ while (missing_len > 0) {
+ DEBUGLOG("got %d bytes, need another %d (total %d)\n",
+ argslen, missing_len, inheader->arglen);
len = read(thisfd->fd, argptr + argslen,
missing_len);
- if (len >= 0) {
+ if (len == -1 && errno == EINTR)
+ continue;
+ if (len > 0) {
missing_len -= len;
argslen += len;
+ } else {
+ /* EOF or error on socket */
+ DEBUGLOG("EOF on local socket\n");
+ free(thisfd->bits.localsock.cmd);
+ thisfd->bits.localsock.cmd = NULL;
+ return 0;
}
}
}
@@ -1207,13 +1286,12 @@ static int read_from_local_sock(struct local_client *thisfd)
/* Check the node name for validity */
if (inheader->node[0] && clops->csid_from_name(csid, inheader->node)) {
/* Error, node is not in the cluster */
- struct clvm_header reply;
- DEBUGLOG("Unknown node: '%s'\n", inheader->node);
+ struct clvm_header reply = {
+ .cmd = CLVMD_CMD_REPLY,
+ .status = ENOENT
+ };
- reply.cmd = CLVMD_CMD_REPLY;
- reply.status = ENOENT;
- reply.flags = 0;
- reply.arglen = 0;
+ DEBUGLOG("Unknown node: '%s'\n", inheader->node);
send_message(&reply, sizeof(reply), our_csid,
thisfd->fd,
"Error sending ENOENT reply to local user");
@@ -1234,17 +1312,29 @@ static int read_from_local_sock(struct local_client *thisfd)
}
/* Create a pipe and add the reading end to our FD list */
- pipe(comms_pipe);
+ if (pipe(comms_pipe)) {
+ struct clvm_header reply = {
+ .cmd = CLVMD_CMD_REPLY,
+ .status = EBUSY
+ };
+
+ DEBUGLOG("creating pipe failed: %s\n", strerror(errno));
+ send_message(&reply, sizeof(reply), our_csid,
+ thisfd->fd,
+ "Error sending EBUSY reply to local user");
+ return len;
+ }
+
newfd = malloc(sizeof(struct local_client));
if (!newfd) {
- struct clvm_header reply;
- close(comms_pipe[0]);
- close(comms_pipe[1]);
-
- reply.cmd = CLVMD_CMD_REPLY;
- reply.status = ENOMEM;
- reply.arglen = 0;
- reply.flags = 0;
+ struct clvm_header reply = {
+ .cmd = CLVMD_CMD_REPLY,
+ .status = ENOMEM
+ };
+
+ (void) close(comms_pipe[0]);
+ (void) close(comms_pipe[1]);
+
send_message(&reply, sizeof(reply), our_csid,
thisfd->fd,
"Error sending ENOMEM reply to local user");
@@ -1279,8 +1369,8 @@ static int read_from_local_sock(struct local_client *thisfd)
thisfd->bits.localsock.in_progress = TRUE;
thisfd->bits.localsock.state = PRE_COMMAND;
DEBUGLOG("Creating pre&post thread\n");
- status = pthread_create(&thisfd->bits.localsock.threadid, NULL,
- pre_and_post_thread, thisfd);
+ status = pthread_create(&thisfd->bits.localsock.threadid,
+ &stack_attr, pre_and_post_thread, thisfd);
DEBUGLOG("Created pre&post thread, state = %d\n", status);
}
return len;
@@ -1306,7 +1396,10 @@ static int distribute_command(struct local_client *thisfd)
int len = thisfd->bits.localsock.cmd_len;
thisfd->xid = global_xid++;
- DEBUGLOG("distribute command: XID = %d\n", thisfd->xid);
+ DEBUGLOG("distribute command: XID = %d, flags=0x%x (%s%s)\n",
+ thisfd->xid, inheader->flags,
+ (inheader->flags & CLVMD_FLAG_LOCAL) ? "LOCAL" : "",
+ (inheader->flags & CLVMD_FLAG_REMOTE) ? "REMOTE" : "");
/* Forward it to other nodes in the cluster if needed */
if (!(inheader->flags & CLVMD_FLAG_LOCAL)) {
@@ -1319,7 +1412,11 @@ static int distribute_command(struct local_client *thisfd)
thisfd->bits.localsock.in_progress = TRUE;
thisfd->bits.localsock.sent_out = TRUE;
- /* Do it here first */
+ /*
+ * Send to local node first, even if CLVMD_FLAG_REMOTE
+ * is set so we still get a reply if this is the
+ * only node.
+ */
add_to_lvmqueue(thisfd, inheader, len, NULL);
DEBUGLOG("Sending message to all cluster nodes\n");
@@ -1372,7 +1469,6 @@ static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
int replylen = 0;
int buflen = max_cluster_message - sizeof(struct clvm_header) - 1;
int status;
- int msg_malloced = 0;
/* Get the node name as we /may/ need it later */
clops->name_from_csid(csid, nodename);
@@ -1431,9 +1527,9 @@ static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
if (replyargs != NULL) {
/* Run the command */
- status =
- do_command(NULL, msg, msglen, &replyargs, buflen,
- &replylen);
+ /* FIXME: usage of init_test() is unprotected */
+ status = do_command(NULL, msg, msglen, &replyargs,
+ buflen, &replylen);
} else {
status = ENOMEM;
}
@@ -1481,10 +1577,6 @@ static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
}
}
- /* Free buffer if it was malloced */
- if (msg_malloced) {
- free(msg);
- }
free(replyargs);
}
@@ -1554,11 +1646,6 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
DEBUGLOG("in sub thread: client = %p\n", client);
pthread_mutex_lock(&client->bits.localsock.mutex);
- /* Don't start until the LVM thread is ready */
- pthread_mutex_lock(&lvm_start_mutex);
- pthread_mutex_unlock(&lvm_start_mutex);
- DEBUGLOG("Sub thread ready for work.\n");
-
/* Ignore SIGUSR1 (handled by master process) but enable
SIGUSR2 (kills subthreads) */
sigemptyset(&ss);
@@ -1572,6 +1659,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
/* Loop around doing PRE and POST functions until the client goes away */
while (!client->bits.localsock.finished) {
/* Execute the code */
+ /* FIXME: usage of init_test() is unprotected as in do_command() */
status = do_pre_command(client);
if (status)
@@ -1654,7 +1742,12 @@ static int process_local_command(struct clvm_header *msg, int msglen,
if (replybuf == NULL)
return -1;
- status = do_command(client, msg, msglen, &replybuf, buflen, &replylen);
+ /* If remote flag is set, just set a successful status code. */
+ if (msg->flags & CLVMD_FLAG_REMOTE)
+ status = 0;
+ else
+ /* FIXME: usage of init_test() is unprotected */
+ status = do_command(client, msg, msglen, &replybuf, buflen, &replylen);
if (status)
client->bits.localsock.all_success = 0;
@@ -1723,13 +1816,18 @@ static void send_local_reply(struct local_client *client, int status, int fd)
}
/* Add in the size of our header */
- message_len = message_len + sizeof(struct clvm_header) + 1;
- replybuf = malloc(message_len);
+ message_len = message_len + sizeof(struct clvm_header);
+ if (!(replybuf = malloc(message_len))) {
+ DEBUGLOG("Memory allocation fails\n");
+ return;
+ }
clientreply = (struct clvm_header *) replybuf;
clientreply->status = status;
clientreply->cmd = CLVMD_CMD_REPLY;
clientreply->node[0] = '\0';
+ clientreply->xid = 0;
+ clientreply->clientid = 0;
clientreply->flags = 0;
ptr = clientreply->args;
@@ -1764,7 +1862,7 @@ static void send_local_reply(struct local_client *client, int status, int fd)
/* Terminate with an empty node name */
*ptr = '\0';
- clientreply->arglen = ptr - clientreply->args + 1;
+ clientreply->arglen = ptr - clientreply->args;
/* And send it */
send_message(replybuf, message_len, our_csid, fd,
@@ -1795,7 +1893,7 @@ static void free_reply(struct local_client *client)
}
/* Send our version number to the cluster */
-static void send_version_message()
+static void send_version_message(void)
{
char message[sizeof(struct clvm_header) + sizeof(int) * 3];
struct clvm_header *msg = (struct clvm_header *) message;
@@ -1847,7 +1945,7 @@ static int send_message(void *buf, int msglen, const char *csid, int fd,
break;
}
- len = write(fd, buf + ptr, msglen - ptr);
+ len = write(fd, (char*)buf + ptr, msglen - ptr);
if (len <= 0) {
if (errno == EINTR)
@@ -1900,11 +1998,11 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
/*
* Routine that runs in the "LVM thread".
*/
-static void lvm_thread_fn(void *arg)
+static void *lvm_thread_fn(void *arg)
{
- struct dm_list *cmdl, *tmp;
sigset_t ss;
struct lvm_startup_params *lvm_params = arg;
+ struct lvm_thread_cmd *cmd;
DEBUGLOG("LVM thread function started\n");
@@ -1915,24 +2013,22 @@ static void lvm_thread_fn(void *arg)
pthread_sigmask(SIG_BLOCK, &ss, NULL);
/* Initialise the interface to liblvm */
- init_clvm(lvm_params->using_gulm, lvm_params->argv);
+ init_clvm(lvm_params->excl_uuid);
/* Allow others to get moving */
- pthread_mutex_unlock(&lvm_start_mutex);
+ pthread_barrier_wait(&lvm_start_barrier);
+ DEBUGLOG("Sub thread ready for work.\n");
/* Now wait for some actual work */
- for (;;) {
- DEBUGLOG("LVM thread waiting for work\n");
+ pthread_mutex_lock(&lvm_thread_mutex);
- pthread_mutex_lock(&lvm_thread_mutex);
- if (dm_list_empty(&lvm_cmd_head))
+ while (!quit) {
+ if (dm_list_empty(&lvm_cmd_head)) {
+ DEBUGLOG("LVM thread waiting for work\n");
pthread_cond_wait(&lvm_thread_cond, &lvm_thread_mutex);
-
- dm_list_iterate_safe(cmdl, tmp, &lvm_cmd_head) {
- struct lvm_thread_cmd *cmd;
-
- cmd =
- dm_list_struct_base(cmdl, struct lvm_thread_cmd, list);
+ } else {
+ cmd = dm_list_item(dm_list_first(&lvm_cmd_head),
+ struct lvm_thread_cmd);
dm_list_del(&cmd->list);
pthread_mutex_unlock(&lvm_thread_mutex);
@@ -1942,8 +2038,11 @@ static void lvm_thread_fn(void *arg)
pthread_mutex_lock(&lvm_thread_mutex);
}
- pthread_mutex_unlock(&lvm_thread_mutex);
}
+
+ pthread_mutex_unlock(&lvm_thread_mutex);
+
+ pthread_exit(NULL);
}
/* Pass down some work to the LVM thread */
@@ -1994,42 +2093,52 @@ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
static int check_local_clvmd(void)
{
int local_socket;
- struct sockaddr_un sockaddr;
int ret = 0;
+ struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
+
+ if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
+ log_error("%s: clvmd socket name too long.", CLVMD_SOCKNAME);
+ return -1;
+ }
/* Open local socket */
if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+ log_sys_error("socket", "local socket");
return -1;
}
- memset(&sockaddr, 0, sizeof(sockaddr));
- memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
- sockaddr.sun_family = AF_UNIX;
-
if (connect(local_socket,(struct sockaddr *) &sockaddr,
sizeof(sockaddr))) {
+ log_sys_error("connect", "local socket");
ret = -1;
}
- close(local_socket);
+ if (close(local_socket))
+ log_sys_error("close", "local socket");
+
return ret;
}
static void close_local_sock(int local_socket)
{
if (local_socket != -1 && close(local_socket))
- stack;
+ log_sys_error("close", CLVMD_SOCKNAME);
if (CLVMD_SOCKNAME[0] != '\0' && unlink(CLVMD_SOCKNAME))
stack;
}
/* Open the local socket, that's the one we talk to libclvm down */
-static int open_local_sock()
+static int open_local_sock(void)
{
- int local_socket = -1;
- struct sockaddr_un sockaddr;
mode_t old_mask;
+ int local_socket = -1;
+ struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
+
+ if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
+ log_error("%s: clvmd socket name too long.", CLVMD_SOCKNAME);
+ return -1;
+ }
close_local_sock(local_socket);
@@ -2046,11 +2155,9 @@ static int open_local_sock()
/* Set Close-on-exec & non-blocking */
if (fcntl(local_socket, F_SETFD, 1))
DEBUGLOG("setting CLOEXEC on local_socket failed: %s\n", strerror(errno));
- fcntl(local_socket, F_SETFL, fcntl(local_socket, F_GETFL, 0) | O_NONBLOCK);
+ if (fcntl(local_socket, F_SETFL, fcntl(local_socket, F_GETFL, 0) | O_NONBLOCK))
+ DEBUGLOG("setting O_NONBLOCK on local_socket failed: %s\n", strerror(errno));
- memset(&sockaddr, 0, sizeof(sockaddr));
- memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
- sockaddr.sun_family = AF_UNIX;
if (bind(local_socket, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) {
log_error("can't bind local socket: %m");
@@ -2071,7 +2178,7 @@ error:
return -1;
}
-void process_message(struct local_client *client, const char *buf, int len,
+void process_message(struct local_client *client, char *buf, int len,
const char *csid)
{
struct clvm_header *inheader;
@@ -2108,7 +2215,7 @@ static struct local_client *find_client(int clientid)
{
struct local_client *thisfd;
for (thisfd = &local_client_head; thisfd != NULL; thisfd = thisfd->next) {
- if (thisfd->fd == ntohl(clientid))
+ if (thisfd->fd == (int)ntohl(clientid))
return thisfd;
}
return NULL;
@@ -2170,8 +2277,6 @@ static if_type_t parse_cluster_interface(char *ifname)
iface = IF_AUTO;
if (!strcmp(ifname, "cman"))
iface = IF_CMAN;
- if (!strcmp(ifname, "gulm"))
- iface = IF_GULM;
if (!strcmp(ifname, "openais"))
iface = IF_OPENAIS;
if (!strcmp(ifname, "corosync"))
@@ -2187,7 +2292,7 @@ static if_type_t parse_cluster_interface(char *ifname)
* only called if the command-line option is not present, and if it fails
* we still try the interfaces in order.
*/
-static if_type_t get_cluster_type()
+static if_type_t get_cluster_type(void)
{
#ifdef HAVE_COROSYNC_CONFDB_H
confdb_handle_t handle;
@@ -2227,6 +2332,9 @@ static if_type_t get_cluster_type()
if (result != CS_OK)
goto out;
+ if (namelen >= sizeof(buf))
+ namelen = sizeof(buf) - 1;
+
buf[namelen] = '\0';
type = parse_cluster_interface(buf);
DEBUGLOG("got interface type '%s' from confdb\n", buf);