2
* Copyright 2004-2012 Red Hat, Inc.
4
* This copyrighted material is made available to anyone wishing to use,
5
* modify, copy, or redistribute it subject to the terms and conditions
6
* of the GNU General Public License v2 or (at your option) any later version.
10
#include "dlm_daemon.h"
13
#include <linux/netlink.h>
14
#include <linux/genetlink.h>
15
#include <linux/dlm_netlink.h>
18
#include <systemd/sd-daemon.h>
21
#include "copyright.cf"
24
#define CLIENT_NALLOC 32
25
static int client_maxi;
26
static int client_size = 0;
27
static struct client *client = NULL;
28
static struct pollfd *pollfd = NULL;
29
static pthread_t query_thread;
30
static pthread_mutex_t query_mutex;
31
static struct list_head fs_register_list;
32
static int kernel_monitor_fd;
41
int do_read(int fd, void *buf, size_t count)
46
rv = read(fd, (char *)buf + off, count - off);
49
if (rv == -1 && errno == EINTR)
58
int do_write(int fd, void *buf, size_t count)
63
rv = write(fd, (char *)buf + off, count);
64
if (rv == -1 && errno == EINTR)
67
log_error("write errno %d", errno);
79
uint64_t monotime(void)
82
clock_gettime(CLOCK_MONOTONIC, &ts);
86
static void client_alloc(void)
91
client = malloc(CLIENT_NALLOC * sizeof(struct client));
92
pollfd = malloc(CLIENT_NALLOC * sizeof(struct pollfd));
94
client = realloc(client, (client_size + CLIENT_NALLOC) *
95
sizeof(struct client));
96
pollfd = realloc(pollfd, (client_size + CLIENT_NALLOC) *
97
sizeof(struct pollfd));
99
log_error("can't alloc for pollfd");
101
if (!client || !pollfd)
102
log_error("can't alloc for client array");
104
for (i = client_size; i < client_size + CLIENT_NALLOC; i++) {
105
client[i].workfn = NULL;
106
client[i].deadfn = NULL;
109
pollfd[i].revents = 0;
111
client_size += CLIENT_NALLOC;
114
void client_dead(int ci)
116
close(client[ci].fd);
117
client[ci].workfn = NULL;
122
int client_add(int fd, void (*workfn)(int ci), void (*deadfn)(int ci))
129
for (i = 0; i < client_size; i++) {
130
if (client[i].fd == -1) {
131
client[i].workfn = workfn;
133
client[i].deadfn = deadfn;
135
client[i].deadfn = client_dead;
138
pollfd[i].events = POLLIN;
149
int client_fd(int ci)
151
return client[ci].fd;
154
void client_ignore(int ci, int fd)
157
pollfd[ci].events = 0;
160
void client_back(int ci, int fd)
163
pollfd[ci].events = POLLIN;
166
static void sigterm_handler(int sig)
171
static void sigchld_handler(int sig)
175
static struct lockspace *create_ls(char *name)
177
struct lockspace *ls;
179
ls = malloc(sizeof(*ls));
182
memset(ls, 0, sizeof(struct lockspace));
183
strncpy(ls->name, name, DLM_LOCKSPACE_LEN);
185
INIT_LIST_HEAD(&ls->changes);
186
INIT_LIST_HEAD(&ls->node_history);
187
INIT_LIST_HEAD(&ls->saved_messages);
188
INIT_LIST_HEAD(&ls->plock_resources);
189
ls->plock_resources_root = RB_ROOT;
191
INIT_LIST_HEAD(&ls->deadlk_nodes);
192
INIT_LIST_HEAD(&ls->transactions);
193
INIT_LIST_HEAD(&ls->resources);
195
setup_lockspace_config(ls);
200
struct lockspace *find_ls(char *name)
202
struct lockspace *ls;
204
list_for_each_entry(ls, &lockspaces, list) {
205
if ((strlen(ls->name) == strlen(name)) &&
206
!strncmp(ls->name, name, strlen(name)))
212
struct lockspace *find_ls_id(uint32_t id)
214
struct lockspace *ls;
216
list_for_each_entry(ls, &lockspaces, list) {
217
if (ls->global_id == id)
224
struct list_head list;
225
char name[DLM_LOCKSPACE_LEN+1];
228
static int fs_register_check(char *name)
231
list_for_each_entry(fs, &fs_register_list, list) {
232
if (!strcmp(name, fs->name))
238
static int fs_register_add(char *name)
242
if (fs_register_check(name))
245
fs = malloc(sizeof(struct fs_reg));
248
strncpy(fs->name, name, DLM_LOCKSPACE_LEN);
249
list_add(&fs->list, &fs_register_list);
253
static void fs_register_del(char *name)
256
list_for_each_entry(fs, &fs_register_list, list) {
257
if (!strcmp(name, fs->name)) {
267
static char *get_args(char *buf, int *argc, char **argv, char sep, int want)
269
char *p = buf, *rp = NULL;
274
for (i = 1; i < MAXARGS; i++) {
275
p = strchr(buf, sep);
290
/* we ended by hitting \0, return the point following that */
292
rp = strchr(buf, '\0') + 1;
297
const char *dlm_mode_str(int mode)
318
/* recv "online" (join) and "offline" (leave) messages from dlm via uevents */
320
#define MAX_LINE_UEVENT 256
322
static void process_uevent(int ci)
324
struct lockspace *ls;
325
char buf[MAX_LINE_UEVENT];
326
char *argv[MAXARGS], *act, *sys;
329
memset(buf, 0, sizeof(buf));
330
memset(argv, 0, sizeof(char *) * MAXARGS);
333
rv = recv(client[ci].fd, &buf, sizeof(buf), 0);
338
log_error("uevent recv error %d errno %d", rv, errno);
342
if (!strstr(buf, "dlm"))
345
log_debug("uevent: %s", buf);
347
get_args(buf, &argc, argv, '/', 4);
349
log_error("uevent message has %d args", argc);
353
if ((strlen(sys) != strlen("dlm")) || strcmp(sys, "dlm"))
356
log_debug("kernel: %s %s", act, argv[3]);
360
if (!strcmp(act, "online@")) {
361
ls = find_ls(argv[3]);
367
ls = create_ls(argv[3]);
373
if (fs_register_check(ls->name))
374
ls->fs_registered = 1;
376
rv = dlm_join_lockspace(ls);
378
/* ls already freed */
382
} else if (!strcmp(act, "offline@")) {
383
ls = find_ls(argv[3]);
389
dlm_leave_lockspace(ls);
393
log_error("process_uevent %s error %d errno %d",
397
static int setup_uevent(void)
399
struct sockaddr_nl snl;
402
s = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
404
log_error("uevent netlink socket");
408
memset(&snl, 0, sizeof(snl));
409
snl.nl_family = AF_NETLINK;
410
snl.nl_pid = getpid();
413
rv = bind(s, (struct sockaddr *) &snl, sizeof(snl));
415
log_error("uevent bind error %d errno %d", rv, errno);
423
static void init_header(struct dlmc_header *h, int cmd, char *name, int result,
426
memset(h, 0, sizeof(struct dlmc_header));
428
h->magic = DLMC_MAGIC;
429
h->version = DLMC_VERSION;
430
h->len = sizeof(struct dlmc_header) + extra_len;
435
strncpy(h->name, name, DLM_LOCKSPACE_LEN);
438
static char copy_buf[LOG_DUMP_SIZE];
440
static void query_dump_debug(int fd)
442
struct dlmc_header h;
445
copy_log_dump(copy_buf, &len);
447
init_header(&h, DLMC_CMD_DUMP_DEBUG, NULL, 0, len);
448
send(fd, &h, sizeof(h), MSG_NOSIGNAL);
451
send(fd, copy_buf, len, MSG_NOSIGNAL);
454
static void copy_options(char *buf, int *len)
456
struct dlm_option *o;
460
for (i = 0; i < dlm_options_max; i++) {
463
memset(tmp, 0, sizeof(tmp));
465
if (o->req_arg == req_arg_str)
466
snprintf(tmp, 255, "%s=%s\n", o->name, o->use_str);
468
snprintf(tmp, 255, "%s=%d\n", o->name, o->use_int);
470
if (pos + strlen(tmp) >= LOG_DUMP_SIZE)
473
ret = sprintf(buf + pos, "%s", tmp);
480
static void query_dump_config(int fd)
482
struct dlmc_header h;
485
copy_options(copy_buf, &len);
487
init_header(&h, DLMC_CMD_DUMP_CONFIG, NULL, 0, len);
488
send(fd, &h, sizeof(h), MSG_NOSIGNAL);
491
send(fd, copy_buf, len, MSG_NOSIGNAL);
494
static void query_dump_log_plock(int fd)
496
struct dlmc_header h;
499
copy_log_dump_plock(copy_buf, &len);
501
init_header(&h, DLMC_CMD_DUMP_DEBUG, NULL, 0, len);
502
send(fd, &h, sizeof(h), MSG_NOSIGNAL);
505
send(fd, copy_buf, len, MSG_NOSIGNAL);
508
static void query_dump_plocks(int fd, char *name)
510
struct lockspace *ls;
511
struct dlmc_header h;
521
rv = copy_plock_state(ls, copy_buf, &len);
523
init_header(&h, DLMC_CMD_DUMP_PLOCKS, name, rv, len);
524
send(fd, &h, sizeof(h), MSG_NOSIGNAL);
527
send(fd, copy_buf, len, MSG_NOSIGNAL);
530
/* combines a header and the data and sends it back to the client in
531
a single do_write() call */
533
static void do_reply(int fd, int cmd, char *name, int result, int option,
534
char *buf, int buflen)
536
struct dlmc_header *h;
540
reply_len = sizeof(struct dlmc_header) + buflen;
541
reply = malloc(reply_len);
544
memset(reply, 0, reply_len);
545
h = (struct dlmc_header *)reply;
547
init_header(h, cmd, name, result, buflen);
551
memcpy(reply + sizeof(struct dlmc_header), buf, buflen);
553
do_write(fd, reply, reply_len);
558
static void query_lockspace_info(int fd, char *name)
560
struct lockspace *ls;
561
struct dlmc_lockspace lockspace;
570
memset(&lockspace, 0, sizeof(lockspace));
572
rv = set_lockspace_info(ls, &lockspace);
574
do_reply(fd, DLMC_CMD_LOCKSPACE_INFO, name, rv, 0,
575
(char *)&lockspace, sizeof(lockspace));
578
static void query_node_info(int fd, char *name, int nodeid)
580
struct lockspace *ls;
581
struct dlmc_node node;
590
memset(&node, 0, sizeof(node));
592
rv = set_node_info(ls, nodeid, &node);
594
do_reply(fd, DLMC_CMD_NODE_INFO, name, rv, 0,
595
(char *)&node, sizeof(node));
598
static void query_lockspaces(int fd, int max)
601
struct dlmc_lockspace *lss = NULL;
604
rv = set_lockspaces(&ls_count, &lss);
611
if (ls_count > max) {
618
do_reply(fd, DLMC_CMD_LOCKSPACES, NULL, result, 0,
619
(char *)lss, ls_count * sizeof(struct dlmc_lockspace));
625
static void query_lockspace_nodes(int fd, char *name, int option, int max)
627
struct lockspace *ls;
629
struct dlmc_node *nodes = NULL;
639
rv = set_lockspace_nodes(ls, option, &node_count, &nodes);
646
/* node_count is the number of structs copied/returned; the caller's
647
max may be less than that, in which case we copy as many as they
648
asked for and return -E2BIG */
650
if (node_count > max) {
657
do_reply(fd, DLMC_CMD_LOCKSPACE_NODES, name, result, 0,
658
(char *)nodes, node_count * sizeof(struct dlmc_node));
664
static void process_connection(int ci)
666
struct dlmc_header h;
669
struct lockspace *ls;
671
rv = do_read(client[ci].fd, &h, sizeof(h));
673
log_debug("connection %d read error %d", ci, rv);
677
if (h.magic != DLMC_MAGIC) {
678
log_debug("connection %d magic error %x", ci, h.magic);
682
if ((h.version & 0xFFFF0000) != (DLMC_VERSION & 0xFFFF0000)) {
683
log_debug("connection %d version error %x", ci, h.version);
687
if (h.len > sizeof(h)) {
688
extra_len = h.len - sizeof(h);
689
extra = malloc(extra_len);
691
log_error("process_connection no mem %d", extra_len);
694
memset(extra, 0, extra_len);
696
rv = do_read(client[ci].fd, extra, extra_len);
698
log_debug("connection %d extra read error %d", ci, rv);
704
case DLMC_CMD_FENCE_ACK:
705
fence_ack_node(atoi(h.name));
708
case DLMC_CMD_FS_REGISTER:
709
if (opt(enable_fscontrol_ind)) {
710
rv = fs_register_add(h.name);
711
ls = find_ls(h.name);
713
ls->fs_registered = 1;
717
do_reply(client[ci].fd, DLMC_CMD_FS_REGISTER, h.name, rv, 0,
721
case DLMC_CMD_FS_UNREGISTER:
722
fs_register_del(h.name);
723
ls = find_ls(h.name);
725
ls->fs_registered = 0;
728
case DLMC_CMD_FS_NOTIFIED:
729
ls = find_ls(h.name);
731
rv = set_fs_notified(ls, h.data);
734
/* pass back the nodeid provided by caller in option field */
735
do_reply(client[ci].fd, DLMC_CMD_FS_NOTIFIED, h.name, rv,
740
case DLMC_CMD_DEADLOCK_CHECK:
741
ls = find_ls(h.name);
743
send_cycle_start(ls);
748
log_error("process_connection %d unknown command %d",
756
static void process_listener(int ci)
760
fd = accept(client[ci].fd, NULL, NULL);
762
log_error("process_listener: accept error %d %d", fd, errno);
766
i = client_add(fd, process_connection, NULL);
768
log_debug("client connection %d fd %d", i, fd);
771
static int setup_listener(const char *sock_path)
773
struct sockaddr_un addr;
777
/* we listen for new client connections on socket s */
779
s = socket(AF_LOCAL, SOCK_STREAM, 0);
781
log_error("socket error %d %d", s, errno);
785
memset(&addr, 0, sizeof(addr));
786
addr.sun_family = AF_LOCAL;
787
strcpy(&addr.sun_path[1], sock_path);
788
addrlen = sizeof(sa_family_t) + strlen(addr.sun_path+1) + 1;
790
rv = bind(s, (struct sockaddr *) &addr, addrlen);
792
log_error("bind error %d %d", rv, errno);
799
log_error("listen error %d %d", rv, errno);
806
static void query_lock(void)
808
pthread_mutex_lock(&query_mutex);
811
static void query_unlock(void)
813
pthread_mutex_unlock(&query_mutex);
816
/* This is a thread, so we have to be careful, don't call log_ functions.
817
We need a thread to process queries because the main thread may block
818
for long periods when writing to sysfs to stop dlm-kernel (any maybe
821
static void *process_queries(void *arg)
823
struct dlmc_header h;
826
rv = setup_listener(DLMC_QUERY_SOCK_PATH);
833
f = accept(s, NULL, NULL);
837
rv = do_read(f, &h, sizeof(h));
842
if (h.magic != DLMC_MAGIC) {
846
if ((h.version & 0xFFFF0000) != (DLMC_VERSION & 0xFFFF0000)) {
853
case DLMC_CMD_DUMP_DEBUG:
856
case DLMC_CMD_DUMP_CONFIG:
857
query_dump_config(f);
859
case DLMC_CMD_DUMP_LOG_PLOCK:
860
query_dump_log_plock(f);
862
case DLMC_CMD_DUMP_PLOCKS:
863
query_dump_plocks(f, h.name);
865
case DLMC_CMD_LOCKSPACE_INFO:
866
query_lockspace_info(f, h.name);
868
case DLMC_CMD_NODE_INFO:
869
query_node_info(f, h.name, h.data);
871
case DLMC_CMD_LOCKSPACES:
872
query_lockspaces(f, h.data);
874
case DLMC_CMD_LOCKSPACE_NODES:
875
query_lockspace_nodes(f, h.name, h.option, h.data);
877
case DLMC_CMD_DUMP_STATUS:
878
send_state_daemon(f);
879
send_state_daemon_nodes(f);
880
send_state_startup_nodes(f);
892
static int setup_queries(void)
896
pthread_mutex_init(&query_mutex, NULL);
898
rv = pthread_create(&query_thread, NULL, process_queries, NULL);
900
log_error("can't create query thread");
906
/* The dlm in kernels before 2.6.28 do not have the monitor device. We
907
keep this fd open as long as we're running. If we exit/terminate while
908
lockspaces exist in the kernel, the kernel will detect a close on this
909
fd and stop the lockspaces. */
911
static void setup_monitor(void)
916
kernel_monitor_fd = open("/dev/misc/dlm-monitor", O_RDONLY);
917
log_debug("/dev/misc/dlm-monitor fd %d", kernel_monitor_fd);
920
void cluster_dead(int ci)
923
log_error("cluster is down, exiting");
928
static void loop(void)
930
struct lockspace *ls;
931
int poll_timeout = -1;
933
void (*workfn) (int ci);
934
void (*deadfn) (int ci);
936
rv = setup_queries();
940
rv = setup_listener(DLMC_SOCK_PATH);
943
client_add(rv, process_listener, NULL);
945
rv = setup_cluster_cfg();
949
client_add(rv, process_cluster_cfg, cluster_dead);
951
rv = check_uncontrolled_lockspaces();
956
* unfence needs to happen after checking for uncontrolled dlm kernel
957
* state (for which we are probably currently fenced, the state must
958
* be cleared by a reboot). unfence needs to happen before joining
959
* the daemon cpg, after which it needs to be possible for someone to
962
rv = unfence_node(our_nodeid);
966
rv = setup_node_config();
970
rv = setup_cluster();
973
client_add(rv, process_cluster, cluster_dead);
975
rv = setup_misc_devices();
979
rv = setup_configfs_options();
985
rv = setup_configfs_members(); /* calls update_cluster() */
992
client_add(rv, process_uevent, NULL);
994
rv = setup_cpg_daemon();
997
client_add(rv, process_cpg_daemon, cluster_dead);
1004
if (opt(enable_deadlk_ind)) {
1005
rv = setup_netlink();
1008
client_add(rv, process_netlink, NULL);
1014
rv = setup_plocks();
1018
plock_ci = client_add(rv, process_plocks, NULL);
1020
#ifdef USE_SD_NOTIFY
1021
sd_notify(0, "READY=1");
1025
rv = poll(pollfd, client_maxi + 1, poll_timeout);
1026
if (rv == -1 && errno == EINTR) {
1027
if (daemon_quit && list_empty(&lockspaces))
1030
log_error("shutdown ignored, active lockspaces");
1036
log_error("poll errno %d", errno);
1042
for (i = 0; i <= client_maxi; i++) {
1043
if (client[i].fd < 0)
1045
if (pollfd[i].revents & POLLIN) {
1046
workfn = client[i].workfn;
1049
if (pollfd[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
1050
deadfn = client[i].deadfn;
1063
if (retry_fencing) {
1064
process_fencing_changes();
1065
poll_timeout = 1000;
1068
if (poll_lockspaces || poll_fs) {
1069
process_lockspace_changes();
1070
poll_timeout = 1000;
1073
if (poll_ignore_plock) {
1074
if (!limit_plocks()) {
1075
poll_ignore_plock = 0;
1076
client_back(plock_ci, plock_fd);
1078
poll_timeout = 1000;
1081
if (poll_drop_plock) {
1082
drop_resources_all();
1083
if (poll_drop_plock)
1084
poll_timeout = 1000;
1090
log_debug("shutdown");
1096
close_cluster_cfg();
1098
list_for_each_entry(ls, &lockspaces, list)
1099
log_error("abandoned lockspace %s", ls->name);
1102
static int lockfile(const char *dir, const char *name)
1104
char path[PATH_MAX];
1110
old_umask = umask(0022);
1111
rv = mkdir(dir, 0775);
1112
if (rv < 0 && errno != EEXIST) {
1118
snprintf(path, PATH_MAX, "%s/%s", dir, name);
1120
fd = open(path, O_CREAT|O_WRONLY|O_CLOEXEC, 0644);
1122
log_error("lockfile open error %s: %s",
1123
path, strerror(errno));
1127
lock.l_type = F_WRLCK;
1129
lock.l_whence = SEEK_SET;
1132
rv = fcntl(fd, F_SETLK, &lock);
1134
log_error("lockfile setlk error %s: %s",
1135
path, strerror(errno));
1139
rv = ftruncate(fd, 0);
1141
log_error("lockfile truncate error %s: %s",
1142
path, strerror(errno));
1146
memset(buf, 0, sizeof(buf));
1147
snprintf(buf, sizeof(buf), "%d\n", getpid());
1149
rv = write(fd, buf, strlen(buf));
1151
log_error("lockfile write error %s: %s",
1152
path, strerror(errno));
1162
static void unlink_lockfile(int fd, const char *dir, const char *name)
1164
char path[PATH_MAX];
1166
snprintf(path, PATH_MAX, "%s/%s", dir, name);
1171
static const char *req_arg_s(int a)
1187
static void print_usage(void)
1189
struct dlm_option *o;
1194
printf("dlm_controld [options]\n");
1196
printf("Option [arg]\n");
1197
printf("Description [default]\n");
1200
for (i = 0; i < dlm_options_max; i++) {
1201
o = &dlm_options[i];
1203
/* don't advertise options with no description */
1204
if (!strlen(o->desc))
1207
printf(" --%s", o->name);
1210
printf(" | -%c", o->letter);
1212
printf(" %s", req_arg_s(o->req_arg));
1215
printf(" %s", req_arg_s(o->req_arg));
1220
printf(" %s", o->desc);
1222
if (o->req_arg == req_arg_str)
1223
printf(" [%s]\n", o->default_str ? o->default_str : "");
1224
else if (o->req_arg == req_arg_int)
1225
printf(" [%d]\n", o->default_int);
1226
else if (o->req_arg == req_arg_bool)
1227
printf(" [%d]\n", o->default_int);
1228
else if (o->req_arg == no_arg && !o->default_int)
1237
static void set_opt_default(int ind, const char *name, char letter, int arg_type,
1238
int default_int, const char *default_str, const char *desc)
1240
dlm_options[ind].name = name;
1241
dlm_options[ind].letter = letter;
1242
dlm_options[ind].req_arg = arg_type;
1243
dlm_options[ind].desc = desc;
1244
dlm_options[ind].default_int = default_int;
1245
dlm_options[ind].default_str = default_str;
1246
dlm_options[ind].use_int = default_int;
1247
dlm_options[ind].use_str = (char *)default_str;
1250
static void set_opt_defaults(void)
1252
set_opt_default(daemon_debug_ind,
1253
"daemon_debug", 'D', no_arg,
1255
"enable debugging to stderr and don't fork");
1257
set_opt_default(foreground_ind,
1258
"foreground", '\0', no_arg,
1262
set_opt_default(log_debug_ind,
1263
"log_debug", 'K', no_arg,
1265
"enable kernel dlm debugging messages");
1267
set_opt_default(timewarn_ind,
1268
"timewarn", '\0', req_arg_int,
1270
""); /* do not advertise */
1272
set_opt_default(protocol_ind,
1273
"protocol", 'r', req_arg_str,
1275
"dlm kernel lowcomms protocol: tcp, sctp, detect");
1277
set_opt_default(debug_logfile_ind,
1278
"debug_logfile", 'L', no_arg,
1280
"write debugging to log file");
1282
set_opt_default(enable_fscontrol_ind,
1283
"enable_fscontrol", '\0', req_arg_bool,
1285
""); /* do not advertise */
1287
set_opt_default(enable_plock_ind,
1288
"enable_plock", 'p', req_arg_bool,
1290
"enable/disable posix lock support for cluster fs");
1292
set_opt_default(plock_debug_ind,
1293
"plock_debug", 'P', no_arg,
1295
"enable plock debugging");
1297
set_opt_default(plock_rate_limit_ind,
1298
"plock_rate_limit", 'l', req_arg_int,
1300
"limit rate of plock operations (0 for none)");
1302
set_opt_default(plock_ownership_ind,
1303
"plock_ownership", 'o', req_arg_bool,
1305
"enable/disable plock ownership");
1307
set_opt_default(drop_resources_time_ind,
1308
"drop_resources_time", 't', req_arg_int,
1310
"plock ownership drop resources time (milliseconds)");
1312
set_opt_default(drop_resources_count_ind,
1313
"drop_resources_count", 'c', req_arg_int,
1315
"plock ownership drop resources count");
1317
set_opt_default(drop_resources_age_ind,
1318
"drop_resources_age", 'a', req_arg_int,
1320
"plock ownership drop resources age (milliseconds)");
1322
set_opt_default(post_join_delay_ind,
1323
"post_join_delay", 'j', req_arg_int,
1325
"seconds to delay fencing after cluster join");
1327
set_opt_default(enable_fencing_ind,
1328
"enable_fencing", 'f', req_arg_bool,
1330
"enable/disable fencing");
1332
set_opt_default(enable_concurrent_fencing_ind,
1333
"enable_concurrent_fencing", '\0', req_arg_bool,
1335
"enable/disable concurrent fencing");
1337
set_opt_default(enable_startup_fencing_ind,
1338
"enable_startup_fencing", 's', req_arg_bool,
1340
"enable/disable startup fencing");
1342
set_opt_default(enable_quorum_fencing_ind,
1343
"enable_quorum_fencing", 'q', req_arg_bool,
1345
"enable/disable quorum requirement for fencing");
1347
set_opt_default(enable_quorum_lockspace_ind,
1348
"enable_quorum_lockspace", '\0', req_arg_bool,
1350
"enable/disable quorum requirement for lockspace operations");
1352
set_opt_default(help_ind,
1353
"help", 'h', no_arg,
1355
"print this help, then exit");
1357
set_opt_default(version_ind,
1358
"version", 'V', no_arg,
1360
"Print program version information, then exit");
1363
static int get_ind_name(char *s)
1365
char name[PATH_MAX];
1369
memset(name, 0, sizeof(name));
1371
for (i = 0; i < strlen(s); i++) {
1380
for (i = 0; i < dlm_options_max; i++) {
1381
if (!strcmp(dlm_options[i].name, name))
1387
static int get_ind_letter(char c)
1391
for (i = 0; i < dlm_options_max; i++) {
1392
if (dlm_options[i].letter == c)
1398
struct dlm_option *get_dlm_option(char *name)
1401
i = get_ind_name(name);
1404
return &dlm_options[i];
1407
static void set_opt_cli(int argc, char **argv)
1409
struct dlm_option *o;
1410
char *arg1, *p, *arg_str;
1411
char bundled_letters[8];
1412
int b, blc = 0, blc_max = 8;
1413
int debug_options = 0;
1421
if (!strcmp(arg1, "help") || !strcmp(arg1, "--help") || !strcmp(arg1, "-h")) {
1426
if (!strcmp(arg1, "version") || !strcmp(arg1, "--version") || !strcmp(arg1, "-V")) {
1427
printf("dlm_controld %s (built %s %s)\n",
1428
RELEASE_VERSION, __DATE__, __TIME__);
1429
printf("%s\n", REDHAT_COPYRIGHT);
1433
for (i = 1; i < argc; ) {
1436
if (!strcmp(p, "--debug_options")) {
1441
if (p[0] == '-' && p[1] == '-')
1442
ind = get_ind_name(p + 2);
1443
else if (p[0] == '-')
1444
ind = get_ind_letter(p[1]);
1446
fprintf(stderr, "unknown option arg %s\n", p);
1451
fprintf(stderr, "unknown option %s\n", p);
1455
o = &dlm_options[ind];
1459
/* "-x" has same effect as "-x 1" */
1463
/* save bundled, arg-less, single letters, e.g. -DKP */
1464
if ((p[0] == '-') && isalpha(p[1]) && (strlen(p) > 2)) {
1465
for (b = 2; b < strlen(p) && blc < blc_max; b++) {
1468
bundled_letters[blc++] = p[b];
1476
if (strstr(p, "=")) {
1477
/* arg starts after = for name or letter */
1478
arg_str = strstr(p, "=") + 1;
1480
} else if (strlen(p) > 2 && isalpha(p[1]) && isdigit(p[2])) {
1481
/* arg with no space between letter and digits */
1485
/* space separates arg from name or letter */
1487
fprintf(stderr, "option %s no arg", p);
1490
arg_str = argv[i++];
1493
if (!arg_str || arg_str[0] == '-' || arg_str[0] == '\0') {
1494
fprintf(stderr, "option %s requires arg", p);
1498
if (o->req_arg == req_arg_str) {
1499
o->cli_str = strdup(arg_str);
1500
o->use_str = o->cli_str;
1501
} else if (o->req_arg == req_arg_int) {
1502
o->cli_int = atoi(arg_str);
1503
o->use_int = o->cli_int;
1504
} else if (o->req_arg == req_arg_bool) {
1505
o->cli_int = atoi(arg_str) ? 1 : 0;
1506
o->use_int = o->cli_int;
1510
/* process bundled letters saved above */
1512
for (i = 0; i < blc; i++) {
1513
ind = get_ind_letter(bundled_letters[i]);
1515
fprintf(stderr, "unknown option char %c\n", bundled_letters[i]);
1518
o = &dlm_options[ind];
1524
if (debug_options && opt(daemon_debug_ind)) {
1525
for (i = 0; i < dlm_options_max; i++) {
1526
o = &dlm_options[i];
1527
printf("%-25s cli_set %d cli_int %d cli_str %s use_int %d use_str %s\n",
1528
o->name, o->cli_set, o->cli_int, o->cli_str, o->use_int, o->use_str);
1532
if (getenv("DLM_CONTROLD_DEBUG")) {
1533
dlm_options[daemon_debug_ind].use_int = 1;
1538
/* When this is used, the systemd service file needs ControlGroup=cpu:/ */
1539
static void set_scheduler(void)
1541
struct sched_param sched_param;
1544
rv = sched_get_priority_max(SCHED_RR);
1546
sched_param.sched_priority = rv;
1547
rv = sched_setscheduler(0, SCHED_RR, &sched_param);
1549
log_error("could not set SCHED_RR priority %d err %d",
1550
sched_param.sched_priority, errno);
1552
log_error("could not get maximum scheduler priority err %d",
1558
int main(int argc, char **argv)
1560
struct sigaction act;
1564
* config priority: cli, config file, default
1565
* - explicit cli setting will override default,
1566
* - explicit file setting will override default
1567
* - explicit file setting will not override explicit cli setting
1571
set_opt_cli(argc, argv);
1574
strcpy(fence_all_device.name, "fence_all");
1575
strcpy(fence_all_device.agent, "dlm_stonith");
1576
fence_all_device.unfence = 0;
1578
INIT_LIST_HEAD(&lockspaces);
1579
INIT_LIST_HEAD(&fs_register_list);
1582
if (!opt(daemon_debug_ind) && !opt(foreground_ind)) {
1583
if (daemon(0, 0) < 0) {
1584
perror("daemon error");
1591
fd = lockfile(RUNDIR, RUN_FILE_NAME);
1595
log_level(NULL, LOG_INFO, "dlm_controld %s started", RELEASE_VERSION);
1597
memset(&act, 0, sizeof(act));
1598
act.sa_handler = sigterm_handler;
1599
rv = sigaction(SIGTERM, &act, NULL);
1602
rv = sigaction(SIGINT, &act, NULL);
1606
memset(&act, 0, sizeof(act));
1607
act.sa_handler = SIG_IGN;
1608
rv = sigaction(SIGHUP, &act, NULL);
1612
memset(&act, 0, sizeof(act));
1613
act.sa_handler = sigchld_handler;
1614
act.sa_flags = SA_NOCLDSTOP;
1615
rv = sigaction(SIGCHLD, &act, NULL);
1619
/* set_scheduler(); */
1623
unlink_lockfile(fd, RUNDIR, RUN_FILE_NAME);