~ubuntu-branches/ubuntu/trusty/dlm/trusty

« back to all changes in this revision

Viewing changes to dlm_controld/main.c

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez
  • Date: 2013-07-23 15:50:10 UTC
  • Revision ID: package-import@ubuntu.com-20130723155010-khpwf6vc04wjho2a
Tags: upstream-4.0.1
ImportĀ upstreamĀ versionĀ 4.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2004-2012 Red Hat, Inc.
 
3
 *
 
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.
 
7
 */
 
8
 
 
9
#define EXTERN
 
10
#include "dlm_daemon.h"
 
11
#include <ctype.h>
 
12
#include <pthread.h>
 
13
#include <linux/netlink.h>
 
14
#include <linux/genetlink.h>
 
15
#include <linux/dlm_netlink.h>
 
16
 
 
17
#ifdef USE_SD_NOTIFY
 
18
#include <systemd/sd-daemon.h>
 
19
#endif
 
20
 
 
21
#include "copyright.cf"
 
22
#include "version.cf"
 
23
 
 
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;
 
33
 
 
34
struct client {
 
35
        int fd;
 
36
        void *workfn;
 
37
        void *deadfn;
 
38
        struct lockspace *ls;
 
39
};
 
40
 
 
41
int do_read(int fd, void *buf, size_t count)
 
42
{
 
43
        int rv, off = 0;
 
44
 
 
45
        while (off < count) {
 
46
                rv = read(fd, (char *)buf + off, count - off);
 
47
                if (rv == 0)
 
48
                        return -1;
 
49
                if (rv == -1 && errno == EINTR)
 
50
                        continue;
 
51
                if (rv == -1)
 
52
                        return -1;
 
53
                off += rv;
 
54
        }
 
55
        return 0;
 
56
}
 
57
 
 
58
int do_write(int fd, void *buf, size_t count)
 
59
{
 
60
        int rv, off = 0;
 
61
 
 
62
 retry:
 
63
        rv = write(fd, (char *)buf + off, count);
 
64
        if (rv == -1 && errno == EINTR)
 
65
                goto retry;
 
66
        if (rv < 0) {
 
67
                log_error("write errno %d", errno);
 
68
                return rv;
 
69
        }
 
70
 
 
71
        if (rv != count) {
 
72
                count -= rv;
 
73
                off += rv;
 
74
                goto retry;
 
75
        }
 
76
        return 0;
 
77
}
 
78
 
 
79
uint64_t monotime(void)
 
80
{
 
81
        struct timespec ts;
 
82
        clock_gettime(CLOCK_MONOTONIC, &ts);
 
83
        return ts.tv_sec;
 
84
}
 
85
 
 
86
static void client_alloc(void)
 
87
{
 
88
        int i;
 
89
 
 
90
        if (!client) {
 
91
                client = malloc(CLIENT_NALLOC * sizeof(struct client));
 
92
                pollfd = malloc(CLIENT_NALLOC * sizeof(struct pollfd));
 
93
        } else {
 
94
                client = realloc(client, (client_size + CLIENT_NALLOC) *
 
95
                                         sizeof(struct client));
 
96
                pollfd = realloc(pollfd, (client_size + CLIENT_NALLOC) *
 
97
                                         sizeof(struct pollfd));
 
98
                if (!pollfd)
 
99
                        log_error("can't alloc for pollfd");
 
100
        }
 
101
        if (!client || !pollfd)
 
102
                log_error("can't alloc for client array");
 
103
 
 
104
        for (i = client_size; i < client_size + CLIENT_NALLOC; i++) {
 
105
                client[i].workfn = NULL;
 
106
                client[i].deadfn = NULL;
 
107
                client[i].fd = -1;
 
108
                pollfd[i].fd = -1;
 
109
                pollfd[i].revents = 0;
 
110
        }
 
111
        client_size += CLIENT_NALLOC;
 
112
}
 
113
 
 
114
void client_dead(int ci)
 
115
{
 
116
        close(client[ci].fd);
 
117
        client[ci].workfn = NULL;
 
118
        client[ci].fd = -1;
 
119
        pollfd[ci].fd = -1;
 
120
}
 
121
 
 
122
int client_add(int fd, void (*workfn)(int ci), void (*deadfn)(int ci))
 
123
{
 
124
        int i;
 
125
 
 
126
        if (!client)
 
127
                client_alloc();
 
128
 again:
 
129
        for (i = 0; i < client_size; i++) {
 
130
                if (client[i].fd == -1) {
 
131
                        client[i].workfn = workfn;
 
132
                        if (deadfn)
 
133
                                client[i].deadfn = deadfn;
 
134
                        else
 
135
                                client[i].deadfn = client_dead;
 
136
                        client[i].fd = fd;
 
137
                        pollfd[i].fd = fd;
 
138
                        pollfd[i].events = POLLIN;
 
139
                        if (i > client_maxi)
 
140
                                client_maxi = i;
 
141
                        return i;
 
142
                }
 
143
        }
 
144
 
 
145
        client_alloc();
 
146
        goto again;
 
147
}
 
148
 
 
149
int client_fd(int ci)
 
150
{
 
151
        return client[ci].fd;
 
152
}
 
153
 
 
154
void client_ignore(int ci, int fd)
 
155
{
 
156
        pollfd[ci].fd = -1;
 
157
        pollfd[ci].events = 0;
 
158
}
 
159
 
 
160
void client_back(int ci, int fd)
 
161
{
 
162
        pollfd[ci].fd = fd;
 
163
        pollfd[ci].events = POLLIN;
 
164
}
 
165
 
 
166
static void sigterm_handler(int sig)
 
167
{
 
168
        daemon_quit = 1;
 
169
}
 
170
 
 
171
static void sigchld_handler(int sig)
 
172
{
 
173
}
 
174
 
 
175
static struct lockspace *create_ls(char *name)
 
176
{
 
177
        struct lockspace *ls;
 
178
 
 
179
        ls = malloc(sizeof(*ls));
 
180
        if (!ls)
 
181
                goto out;
 
182
        memset(ls, 0, sizeof(struct lockspace));
 
183
        strncpy(ls->name, name, DLM_LOCKSPACE_LEN);
 
184
 
 
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;
 
190
#if 0
 
191
        INIT_LIST_HEAD(&ls->deadlk_nodes);
 
192
        INIT_LIST_HEAD(&ls->transactions);
 
193
        INIT_LIST_HEAD(&ls->resources);
 
194
#endif
 
195
        setup_lockspace_config(ls);
 
196
 out:
 
197
        return ls;
 
198
}
 
199
 
 
200
struct lockspace *find_ls(char *name)
 
201
{
 
202
        struct lockspace *ls;
 
203
 
 
204
        list_for_each_entry(ls, &lockspaces, list) {
 
205
                if ((strlen(ls->name) == strlen(name)) &&
 
206
                    !strncmp(ls->name, name, strlen(name)))
 
207
                        return ls;
 
208
        }
 
209
        return NULL;
 
210
}
 
211
 
 
212
struct lockspace *find_ls_id(uint32_t id)
 
213
{
 
214
        struct lockspace *ls;
 
215
 
 
216
        list_for_each_entry(ls, &lockspaces, list) {
 
217
                if (ls->global_id == id)
 
218
                        return ls;
 
219
        }
 
220
        return NULL;
 
221
}
 
222
 
 
223
struct fs_reg {
 
224
        struct list_head list;
 
225
        char name[DLM_LOCKSPACE_LEN+1];
 
226
};
 
227
 
 
228
static int fs_register_check(char *name)
 
229
{
 
230
        struct fs_reg *fs;
 
231
        list_for_each_entry(fs, &fs_register_list, list) {
 
232
                if (!strcmp(name, fs->name))
 
233
                        return 1;
 
234
        }
 
235
        return 0;
 
236
}
 
237
 
 
238
static int fs_register_add(char *name)
 
239
{
 
240
        struct fs_reg *fs;
 
241
 
 
242
        if (fs_register_check(name))
 
243
                return -EALREADY;
 
244
 
 
245
        fs = malloc(sizeof(struct fs_reg));
 
246
        if (!fs)
 
247
                return -ENOMEM;
 
248
        strncpy(fs->name, name, DLM_LOCKSPACE_LEN);
 
249
        list_add(&fs->list, &fs_register_list);
 
250
        return 0;
 
251
}
 
252
 
 
253
static void fs_register_del(char *name)
 
254
{
 
255
        struct fs_reg *fs;
 
256
        list_for_each_entry(fs, &fs_register_list, list) {
 
257
                if (!strcmp(name, fs->name)) {
 
258
                        list_del(&fs->list);
 
259
                        free(fs);
 
260
                        return;
 
261
                }
 
262
        }
 
263
}
 
264
 
 
265
#define MAXARGS 8
 
266
 
 
267
static char *get_args(char *buf, int *argc, char **argv, char sep, int want)
 
268
{
 
269
        char *p = buf, *rp = NULL;
 
270
        int i;
 
271
 
 
272
        argv[0] = p;
 
273
 
 
274
        for (i = 1; i < MAXARGS; i++) {
 
275
                p = strchr(buf, sep);
 
276
                if (!p)
 
277
                        break;
 
278
                *p = '\0';
 
279
 
 
280
                if (want == i) {
 
281
                        rp = p + 1;
 
282
                        break;
 
283
                }
 
284
 
 
285
                argv[i] = p + 1;
 
286
                buf = p + 1;
 
287
        }
 
288
        *argc = i;
 
289
 
 
290
        /* we ended by hitting \0, return the point following that */
 
291
        if (!rp)
 
292
                rp = strchr(buf, '\0') + 1;
 
293
 
 
294
        return rp;
 
295
}
 
296
 
 
297
const char *dlm_mode_str(int mode)
 
298
{
 
299
        switch (mode) {
 
300
        case DLM_LOCK_IV:
 
301
                return "IV";
 
302
        case DLM_LOCK_NL:
 
303
                return "NL";
 
304
        case DLM_LOCK_CR:
 
305
                return "CR";
 
306
        case DLM_LOCK_CW:
 
307
                return "CW";
 
308
        case DLM_LOCK_PR:
 
309
                return "PR";
 
310
        case DLM_LOCK_PW:
 
311
                return "PW";
 
312
        case DLM_LOCK_EX:
 
313
                return "EX";
 
314
        }
 
315
        return "??";
 
316
}
 
317
 
 
318
/* recv "online" (join) and "offline" (leave) messages from dlm via uevents */
 
319
 
 
320
#define MAX_LINE_UEVENT 256
 
321
 
 
322
static void process_uevent(int ci)
 
323
{
 
324
        struct lockspace *ls;
 
325
        char buf[MAX_LINE_UEVENT];
 
326
        char *argv[MAXARGS], *act, *sys;
 
327
        int rv, argc = 0;
 
328
 
 
329
        memset(buf, 0, sizeof(buf));
 
330
        memset(argv, 0, sizeof(char *) * MAXARGS);
 
331
 
 
332
 retry_recv:
 
333
        rv = recv(client[ci].fd, &buf, sizeof(buf), 0);
 
334
        if (rv < 0) {
 
335
                if (errno == EINTR)
 
336
                        goto retry_recv;
 
337
                if (errno != EAGAIN)
 
338
                        log_error("uevent recv error %d errno %d", rv, errno);
 
339
                return;
 
340
        }
 
341
 
 
342
        if (!strstr(buf, "dlm"))
 
343
                return;
 
344
 
 
345
        log_debug("uevent: %s", buf);
 
346
 
 
347
        get_args(buf, &argc, argv, '/', 4);
 
348
        if (argc != 4)
 
349
                log_error("uevent message has %d args", argc);
 
350
        act = argv[0];
 
351
        sys = argv[2];
 
352
 
 
353
        if ((strlen(sys) != strlen("dlm")) || strcmp(sys, "dlm"))
 
354
                return;
 
355
 
 
356
        log_debug("kernel: %s %s", act, argv[3]);
 
357
 
 
358
        rv = 0;
 
359
 
 
360
        if (!strcmp(act, "online@")) {
 
361
                ls = find_ls(argv[3]);
 
362
                if (ls) {
 
363
                        rv = -EEXIST;
 
364
                        goto out;
 
365
                }
 
366
 
 
367
                ls = create_ls(argv[3]);
 
368
                if (!ls) {
 
369
                        rv = -ENOMEM;
 
370
                        goto out;
 
371
                }
 
372
 
 
373
                if (fs_register_check(ls->name))
 
374
                        ls->fs_registered = 1;
 
375
 
 
376
                rv = dlm_join_lockspace(ls);
 
377
                if (rv) {
 
378
                        /* ls already freed */
 
379
                        goto out;
 
380
                }
 
381
 
 
382
        } else if (!strcmp(act, "offline@")) {
 
383
                ls = find_ls(argv[3]);
 
384
                if (!ls) {
 
385
                        rv = -ENOENT;
 
386
                        goto out;
 
387
                }
 
388
 
 
389
                dlm_leave_lockspace(ls);
 
390
        }
 
391
 out:
 
392
        if (rv < 0)
 
393
                log_error("process_uevent %s error %d errno %d",
 
394
                          act, rv, errno);
 
395
}
 
396
 
 
397
static int setup_uevent(void)
 
398
{
 
399
        struct sockaddr_nl snl;
 
400
        int s, rv;
 
401
 
 
402
        s = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
 
403
        if (s < 0) {
 
404
                log_error("uevent netlink socket");
 
405
                return s;
 
406
        }
 
407
 
 
408
        memset(&snl, 0, sizeof(snl));
 
409
        snl.nl_family = AF_NETLINK;
 
410
        snl.nl_pid = getpid();
 
411
        snl.nl_groups = 1;
 
412
 
 
413
        rv = bind(s, (struct sockaddr *) &snl, sizeof(snl));
 
414
        if (rv < 0) {
 
415
                log_error("uevent bind error %d errno %d", rv, errno);
 
416
                close(s);
 
417
                return rv;
 
418
        }
 
419
 
 
420
        return s;
 
421
}
 
422
 
 
423
static void init_header(struct dlmc_header *h, int cmd, char *name, int result,
 
424
                        int extra_len)
 
425
{
 
426
        memset(h, 0, sizeof(struct dlmc_header));
 
427
 
 
428
        h->magic = DLMC_MAGIC;
 
429
        h->version = DLMC_VERSION;
 
430
        h->len = sizeof(struct dlmc_header) + extra_len;
 
431
        h->command = cmd;
 
432
        h->data = result;
 
433
 
 
434
        if (name)
 
435
                strncpy(h->name, name, DLM_LOCKSPACE_LEN);
 
436
}
 
437
 
 
438
static char copy_buf[LOG_DUMP_SIZE];
 
439
 
 
440
static void query_dump_debug(int fd)
 
441
{
 
442
        struct dlmc_header h;
 
443
        int len = 0;
 
444
 
 
445
        copy_log_dump(copy_buf, &len);
 
446
 
 
447
        init_header(&h, DLMC_CMD_DUMP_DEBUG, NULL, 0, len);
 
448
        send(fd, &h, sizeof(h), MSG_NOSIGNAL);
 
449
 
 
450
        if (len)
 
451
                send(fd, copy_buf, len, MSG_NOSIGNAL);
 
452
}
 
453
 
 
454
static void copy_options(char *buf, int *len)
 
455
{
 
456
        struct dlm_option *o;
 
457
        char tmp[256];
 
458
        int i, ret, pos = 0;
 
459
 
 
460
        for (i = 0; i < dlm_options_max; i++) {
 
461
                o = &dlm_options[i];
 
462
 
 
463
                memset(tmp, 0, sizeof(tmp));
 
464
 
 
465
                if (o->req_arg == req_arg_str)
 
466
                        snprintf(tmp, 255, "%s=%s\n", o->name, o->use_str);
 
467
                else
 
468
                        snprintf(tmp, 255, "%s=%d\n", o->name, o->use_int);
 
469
 
 
470
                if (pos + strlen(tmp) >= LOG_DUMP_SIZE)
 
471
                        break;
 
472
 
 
473
                ret = sprintf(buf + pos, "%s", tmp);
 
474
                pos += ret;
 
475
        }
 
476
 
 
477
        *len = pos;
 
478
}
 
479
 
 
480
static void query_dump_config(int fd)
 
481
{
 
482
        struct dlmc_header h;
 
483
        int len = 0;
 
484
 
 
485
        copy_options(copy_buf, &len);
 
486
 
 
487
        init_header(&h, DLMC_CMD_DUMP_CONFIG, NULL, 0, len);
 
488
        send(fd, &h, sizeof(h), MSG_NOSIGNAL);
 
489
 
 
490
        if (len)
 
491
                send(fd, copy_buf, len, MSG_NOSIGNAL);
 
492
}
 
493
 
 
494
static void query_dump_log_plock(int fd)
 
495
{
 
496
        struct dlmc_header h;
 
497
        int len = 0;
 
498
 
 
499
        copy_log_dump_plock(copy_buf, &len);
 
500
 
 
501
        init_header(&h, DLMC_CMD_DUMP_DEBUG, NULL, 0, len);
 
502
        send(fd, &h, sizeof(h), MSG_NOSIGNAL);
 
503
 
 
504
        if (len)
 
505
                send(fd, copy_buf, len, MSG_NOSIGNAL);
 
506
}
 
507
 
 
508
static void query_dump_plocks(int fd, char *name)
 
509
{
 
510
        struct lockspace *ls;
 
511
        struct dlmc_header h;
 
512
        int len = 0;
 
513
        int rv;
 
514
 
 
515
        ls = find_ls(name);
 
516
        if (!ls) {
 
517
                rv = -ENOENT;
 
518
                goto out;
 
519
        }
 
520
 
 
521
        rv = copy_plock_state(ls, copy_buf, &len);
 
522
 out:
 
523
        init_header(&h, DLMC_CMD_DUMP_PLOCKS, name, rv, len);
 
524
        send(fd, &h, sizeof(h), MSG_NOSIGNAL);
 
525
 
 
526
        if (len)
 
527
                send(fd, copy_buf, len, MSG_NOSIGNAL);
 
528
}
 
529
 
 
530
/* combines a header and the data and sends it back to the client in
 
531
   a single do_write() call */
 
532
 
 
533
static void do_reply(int fd, int cmd, char *name, int result, int option,
 
534
                     char *buf, int buflen)
 
535
{
 
536
        struct dlmc_header *h;
 
537
        char *reply;
 
538
        int reply_len;
 
539
 
 
540
        reply_len = sizeof(struct dlmc_header) + buflen;
 
541
        reply = malloc(reply_len);
 
542
        if (!reply)
 
543
                return;
 
544
        memset(reply, 0, reply_len);
 
545
        h = (struct dlmc_header *)reply;
 
546
 
 
547
        init_header(h, cmd, name, result, buflen);
 
548
        h->option = option;
 
549
 
 
550
        if (buf && buflen)
 
551
                memcpy(reply + sizeof(struct dlmc_header), buf, buflen);
 
552
 
 
553
        do_write(fd, reply, reply_len);
 
554
 
 
555
        free(reply);
 
556
}
 
557
 
 
558
static void query_lockspace_info(int fd, char *name)
 
559
{
 
560
        struct lockspace *ls;
 
561
        struct dlmc_lockspace lockspace;
 
562
        int rv;
 
563
 
 
564
        ls = find_ls(name);
 
565
        if (!ls) {
 
566
                rv = -ENOENT;
 
567
                goto out;
 
568
        }
 
569
 
 
570
        memset(&lockspace, 0, sizeof(lockspace));
 
571
 
 
572
        rv = set_lockspace_info(ls, &lockspace);
 
573
 out:
 
574
        do_reply(fd, DLMC_CMD_LOCKSPACE_INFO, name, rv, 0,
 
575
                 (char *)&lockspace, sizeof(lockspace));
 
576
}
 
577
 
 
578
static void query_node_info(int fd, char *name, int nodeid)
 
579
{
 
580
        struct lockspace *ls;
 
581
        struct dlmc_node node;
 
582
        int rv;
 
583
 
 
584
        ls = find_ls(name);
 
585
        if (!ls) {
 
586
                rv = -ENOENT;
 
587
                goto out;
 
588
        }
 
589
 
 
590
        memset(&node, 0, sizeof(node));
 
591
 
 
592
        rv = set_node_info(ls, nodeid, &node);
 
593
 out:
 
594
        do_reply(fd, DLMC_CMD_NODE_INFO, name, rv, 0,
 
595
                 (char *)&node, sizeof(node));
 
596
}
 
597
 
 
598
static void query_lockspaces(int fd, int max)
 
599
{
 
600
        int ls_count = 0;
 
601
        struct dlmc_lockspace *lss = NULL;
 
602
        int rv, result;
 
603
 
 
604
        rv = set_lockspaces(&ls_count, &lss);
 
605
        if (rv < 0) {
 
606
                result = rv;
 
607
                ls_count = 0;
 
608
                goto out;
 
609
        }
 
610
 
 
611
        if (ls_count > max) {
 
612
                result = -E2BIG;
 
613
                ls_count = max;
 
614
        } else {
 
615
                result = ls_count;
 
616
        }
 
617
 out:
 
618
        do_reply(fd, DLMC_CMD_LOCKSPACES, NULL, result, 0,
 
619
                 (char *)lss, ls_count * sizeof(struct dlmc_lockspace));
 
620
 
 
621
        if (lss)
 
622
                free(lss);
 
623
}
 
624
 
 
625
static void query_lockspace_nodes(int fd, char *name, int option, int max)
 
626
{
 
627
        struct lockspace *ls;
 
628
        int node_count = 0;
 
629
        struct dlmc_node *nodes = NULL;
 
630
        int rv, result;
 
631
 
 
632
        ls = find_ls(name);
 
633
        if (!ls) {
 
634
                result = -ENOENT;
 
635
                node_count = 0;
 
636
                goto out;
 
637
        }
 
638
 
 
639
        rv = set_lockspace_nodes(ls, option, &node_count, &nodes);
 
640
        if (rv < 0) {
 
641
                result = rv;
 
642
                node_count = 0;
 
643
                goto out;
 
644
        }
 
645
 
 
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 */
 
649
 
 
650
        if (node_count > max) {
 
651
                result = -E2BIG;
 
652
                node_count = max;
 
653
        } else {
 
654
                result = node_count;
 
655
        }
 
656
 out:
 
657
        do_reply(fd, DLMC_CMD_LOCKSPACE_NODES, name, result, 0,
 
658
                 (char *)nodes, node_count * sizeof(struct dlmc_node));
 
659
 
 
660
        if (nodes)
 
661
                free(nodes);
 
662
}
 
663
 
 
664
static void process_connection(int ci)
 
665
{
 
666
        struct dlmc_header h;
 
667
        char *extra = NULL;
 
668
        int rv, extra_len;
 
669
        struct lockspace *ls;
 
670
 
 
671
        rv = do_read(client[ci].fd, &h, sizeof(h));
 
672
        if (rv < 0) {
 
673
                log_debug("connection %d read error %d", ci, rv);
 
674
                goto out;
 
675
        }
 
676
 
 
677
        if (h.magic != DLMC_MAGIC) {
 
678
                log_debug("connection %d magic error %x", ci, h.magic);
 
679
                goto out;
 
680
        }
 
681
 
 
682
        if ((h.version & 0xFFFF0000) != (DLMC_VERSION & 0xFFFF0000)) {
 
683
                log_debug("connection %d version error %x", ci, h.version);
 
684
                goto out;
 
685
        }
 
686
 
 
687
        if (h.len > sizeof(h)) {
 
688
                extra_len = h.len - sizeof(h);
 
689
                extra = malloc(extra_len);
 
690
                if (!extra) {
 
691
                        log_error("process_connection no mem %d", extra_len);
 
692
                        goto out;
 
693
                }
 
694
                memset(extra, 0, extra_len);
 
695
 
 
696
                rv = do_read(client[ci].fd, extra, extra_len);
 
697
                if (rv < 0) {
 
698
                        log_debug("connection %d extra read error %d", ci, rv);
 
699
                        goto out;
 
700
                }
 
701
        }
 
702
 
 
703
        switch (h.command) {
 
704
        case DLMC_CMD_FENCE_ACK:
 
705
                fence_ack_node(atoi(h.name));
 
706
                break;
 
707
 
 
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);
 
712
                        if (ls)
 
713
                                ls->fs_registered = 1;
 
714
                } else {
 
715
                        rv = -EOPNOTSUPP;
 
716
                }
 
717
                do_reply(client[ci].fd, DLMC_CMD_FS_REGISTER, h.name, rv, 0,
 
718
                         NULL, 0);
 
719
                break;
 
720
 
 
721
        case DLMC_CMD_FS_UNREGISTER:
 
722
                fs_register_del(h.name);
 
723
                ls = find_ls(h.name);
 
724
                if (ls)
 
725
                        ls->fs_registered = 0;
 
726
                break;
 
727
 
 
728
        case DLMC_CMD_FS_NOTIFIED:
 
729
                ls = find_ls(h.name);
 
730
                if (ls)
 
731
                        rv = set_fs_notified(ls, h.data);
 
732
                else
 
733
                        rv = -ENOENT;
 
734
                /* pass back the nodeid provided by caller in option field */
 
735
                do_reply(client[ci].fd, DLMC_CMD_FS_NOTIFIED, h.name, rv,
 
736
                         h.data, NULL, 0);
 
737
                break;
 
738
 
 
739
#if 0
 
740
        case DLMC_CMD_DEADLOCK_CHECK:
 
741
                ls = find_ls(h.name);
 
742
                if (ls)
 
743
                        send_cycle_start(ls);
 
744
                client_dead(ci);
 
745
                break;
 
746
#endif
 
747
        default:
 
748
                log_error("process_connection %d unknown command %d",
 
749
                          ci, h.command);
 
750
        }
 
751
 out:
 
752
        if (extra)
 
753
                free(extra);
 
754
}
 
755
 
 
756
static void process_listener(int ci)
 
757
{
 
758
        int fd, i;
 
759
 
 
760
        fd = accept(client[ci].fd, NULL, NULL);
 
761
        if (fd < 0) {
 
762
                log_error("process_listener: accept error %d %d", fd, errno);
 
763
                return;
 
764
        }
 
765
        
 
766
        i = client_add(fd, process_connection, NULL);
 
767
 
 
768
        log_debug("client connection %d fd %d", i, fd);
 
769
}
 
770
 
 
771
static int setup_listener(const char *sock_path)
 
772
{
 
773
        struct sockaddr_un addr;
 
774
        socklen_t addrlen;
 
775
        int rv, s;
 
776
 
 
777
        /* we listen for new client connections on socket s */
 
778
 
 
779
        s = socket(AF_LOCAL, SOCK_STREAM, 0);
 
780
        if (s < 0) {
 
781
                log_error("socket error %d %d", s, errno);
 
782
                return s;
 
783
        }
 
784
 
 
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;
 
789
 
 
790
        rv = bind(s, (struct sockaddr *) &addr, addrlen);
 
791
        if (rv < 0) {
 
792
                log_error("bind error %d %d", rv, errno);
 
793
                close(s);
 
794
                return rv;
 
795
        }
 
796
 
 
797
        rv = listen(s, 5);
 
798
        if (rv < 0) {
 
799
                log_error("listen error %d %d", rv, errno);
 
800
                close(s);
 
801
                return rv;
 
802
        }
 
803
        return s;
 
804
}
 
805
 
 
806
static void query_lock(void)
 
807
{
 
808
        pthread_mutex_lock(&query_mutex);
 
809
}
 
810
 
 
811
static void query_unlock(void)
 
812
{
 
813
        pthread_mutex_unlock(&query_mutex);
 
814
}
 
815
 
 
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
 
819
   other places). */
 
820
 
 
821
static void *process_queries(void *arg)
 
822
{
 
823
        struct dlmc_header h;
 
824
        int s, f, rv;
 
825
 
 
826
        rv = setup_listener(DLMC_QUERY_SOCK_PATH);
 
827
        if (rv < 0)
 
828
                return NULL;
 
829
 
 
830
        s = rv;
 
831
 
 
832
        for (;;) {
 
833
                f = accept(s, NULL, NULL);
 
834
                if (f < 0)
 
835
                        return NULL;
 
836
 
 
837
                rv = do_read(f, &h, sizeof(h));
 
838
                if (rv < 0) {
 
839
                        goto out;
 
840
                }
 
841
 
 
842
                if (h.magic != DLMC_MAGIC) {
 
843
                        goto out;
 
844
                }
 
845
 
 
846
                if ((h.version & 0xFFFF0000) != (DLMC_VERSION & 0xFFFF0000)) {
 
847
                        goto out;
 
848
                }
 
849
 
 
850
                query_lock();
 
851
 
 
852
                switch (h.command) {
 
853
                case DLMC_CMD_DUMP_DEBUG:
 
854
                        query_dump_debug(f);
 
855
                        break;
 
856
                case DLMC_CMD_DUMP_CONFIG:
 
857
                        query_dump_config(f);
 
858
                        break;
 
859
                case DLMC_CMD_DUMP_LOG_PLOCK:
 
860
                        query_dump_log_plock(f);
 
861
                        break;
 
862
                case DLMC_CMD_DUMP_PLOCKS:
 
863
                        query_dump_plocks(f, h.name);
 
864
                        break;
 
865
                case DLMC_CMD_LOCKSPACE_INFO:
 
866
                        query_lockspace_info(f, h.name);
 
867
                        break;
 
868
                case DLMC_CMD_NODE_INFO:
 
869
                        query_node_info(f, h.name, h.data);
 
870
                        break;
 
871
                case DLMC_CMD_LOCKSPACES:
 
872
                        query_lockspaces(f, h.data);
 
873
                        break;
 
874
                case DLMC_CMD_LOCKSPACE_NODES:
 
875
                        query_lockspace_nodes(f, h.name, h.option, h.data);
 
876
                        break;
 
877
                case DLMC_CMD_DUMP_STATUS:
 
878
                        send_state_daemon(f);
 
879
                        send_state_daemon_nodes(f);
 
880
                        send_state_startup_nodes(f);
 
881
                        break;
 
882
                default:
 
883
                        break;
 
884
                }
 
885
                query_unlock();
 
886
 
 
887
 out:
 
888
                close(f);
 
889
        }
 
890
}
 
891
 
 
892
static int setup_queries(void)
 
893
{
 
894
        int rv;
 
895
 
 
896
        pthread_mutex_init(&query_mutex, NULL);
 
897
 
 
898
        rv = pthread_create(&query_thread, NULL, process_queries, NULL);
 
899
        if (rv < 0) {
 
900
                log_error("can't create query thread");
 
901
                return rv;
 
902
        }
 
903
        return 0;
 
904
}
 
905
 
 
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. */
 
910
 
 
911
static void setup_monitor(void)
 
912
{
 
913
        if (!monitor_minor)
 
914
                return;
 
915
 
 
916
        kernel_monitor_fd = open("/dev/misc/dlm-monitor", O_RDONLY);
 
917
        log_debug("/dev/misc/dlm-monitor fd %d", kernel_monitor_fd);
 
918
}
 
919
 
 
920
void cluster_dead(int ci)
 
921
{
 
922
        if (!cluster_down)
 
923
                log_error("cluster is down, exiting");
 
924
        daemon_quit = 1;
 
925
        cluster_down = 1;
 
926
}
 
927
 
 
928
static void loop(void)
 
929
{
 
930
        struct lockspace *ls;
 
931
        int poll_timeout = -1;
 
932
        int rv, i;
 
933
        void (*workfn) (int ci);
 
934
        void (*deadfn) (int ci);
 
935
 
 
936
        rv = setup_queries();
 
937
        if (rv < 0)
 
938
                goto out;
 
939
 
 
940
        rv = setup_listener(DLMC_SOCK_PATH);
 
941
        if (rv < 0)
 
942
                goto out;
 
943
        client_add(rv, process_listener, NULL);
 
944
 
 
945
        rv = setup_cluster_cfg();
 
946
        if (rv < 0)
 
947
                goto out;
 
948
        if (rv > 0) 
 
949
                client_add(rv, process_cluster_cfg, cluster_dead);
 
950
 
 
951
        rv = check_uncontrolled_lockspaces();
 
952
        if (rv < 0)
 
953
                goto out;
 
954
 
 
955
        /*
 
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
 
960
         * fence us.
 
961
         */
 
962
        rv = unfence_node(our_nodeid);
 
963
        if (rv < 0)
 
964
                goto out;
 
965
 
 
966
        rv = setup_node_config();
 
967
        if (rv < 0)
 
968
                goto out;
 
969
 
 
970
        rv = setup_cluster();
 
971
        if (rv < 0)
 
972
                goto out;
 
973
        client_add(rv, process_cluster, cluster_dead);
 
974
 
 
975
        rv = setup_misc_devices();
 
976
        if (rv < 0)
 
977
                goto out;
 
978
 
 
979
        rv = setup_configfs_options();
 
980
        if (rv < 0)
 
981
                goto out;
 
982
 
 
983
        setup_monitor();
 
984
 
 
985
        rv = setup_configfs_members();          /* calls update_cluster() */
 
986
        if (rv < 0)
 
987
                goto out;
 
988
 
 
989
        rv = setup_uevent();
 
990
        if (rv < 0)
 
991
                goto out;
 
992
        client_add(rv, process_uevent, NULL);
 
993
 
 
994
        rv = setup_cpg_daemon();
 
995
        if (rv < 0)
 
996
                goto out;
 
997
        client_add(rv, process_cpg_daemon, cluster_dead);
 
998
 
 
999
        rv = set_protocol();
 
1000
        if (rv < 0)
 
1001
                goto out;
 
1002
 
 
1003
#if 0
 
1004
        if (opt(enable_deadlk_ind)) {
 
1005
                rv = setup_netlink();
 
1006
                if (rv < 0)
 
1007
                        goto out;
 
1008
                client_add(rv, process_netlink, NULL);
 
1009
 
 
1010
                setup_deadlock();
 
1011
        }
 
1012
#endif
 
1013
 
 
1014
        rv = setup_plocks();
 
1015
        if (rv < 0)
 
1016
                goto out;
 
1017
        plock_fd = rv;
 
1018
        plock_ci = client_add(rv, process_plocks, NULL);
 
1019
 
 
1020
#ifdef USE_SD_NOTIFY
 
1021
        sd_notify(0, "READY=1");
 
1022
#endif
 
1023
 
 
1024
        for (;;) {
 
1025
                rv = poll(pollfd, client_maxi + 1, poll_timeout);
 
1026
                if (rv == -1 && errno == EINTR) {
 
1027
                        if (daemon_quit && list_empty(&lockspaces))
 
1028
                                goto out;
 
1029
                        if (daemon_quit) {
 
1030
                                log_error("shutdown ignored, active lockspaces");
 
1031
                                daemon_quit = 0;
 
1032
                        }
 
1033
                        continue;
 
1034
                }
 
1035
                if (rv < 0) {
 
1036
                        log_error("poll errno %d", errno);
 
1037
                        goto out;
 
1038
                }
 
1039
 
 
1040
                query_lock();
 
1041
 
 
1042
                for (i = 0; i <= client_maxi; i++) {
 
1043
                        if (client[i].fd < 0)
 
1044
                                continue;
 
1045
                        if (pollfd[i].revents & POLLIN) {
 
1046
                                workfn = client[i].workfn;
 
1047
                                workfn(i);
 
1048
                        }
 
1049
                        if (pollfd[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
 
1050
                                deadfn = client[i].deadfn;
 
1051
                                deadfn(i);
 
1052
                        }
 
1053
                }
 
1054
                query_unlock();
 
1055
 
 
1056
                if (daemon_quit)
 
1057
                        break;
 
1058
 
 
1059
                query_lock();
 
1060
 
 
1061
                poll_timeout = -1;
 
1062
 
 
1063
                if (retry_fencing) {
 
1064
                        process_fencing_changes();
 
1065
                        poll_timeout = 1000;
 
1066
                }
 
1067
 
 
1068
                if (poll_lockspaces || poll_fs) {
 
1069
                        process_lockspace_changes();
 
1070
                        poll_timeout = 1000;
 
1071
                }
 
1072
 
 
1073
                if (poll_ignore_plock) {
 
1074
                        if (!limit_plocks()) {
 
1075
                                poll_ignore_plock = 0;
 
1076
                                client_back(plock_ci, plock_fd);
 
1077
                        }
 
1078
                        poll_timeout = 1000;
 
1079
                }
 
1080
 
 
1081
                if (poll_drop_plock) {
 
1082
                        drop_resources_all();
 
1083
                        if (poll_drop_plock)
 
1084
                                poll_timeout = 1000;
 
1085
                }
 
1086
 
 
1087
                query_unlock();
 
1088
        }
 
1089
 out:
 
1090
        log_debug("shutdown");
 
1091
        close_plocks();
 
1092
        close_cpg_daemon();
 
1093
        clear_configfs();
 
1094
        close_logging();
 
1095
        close_cluster();
 
1096
        close_cluster_cfg();
 
1097
 
 
1098
        list_for_each_entry(ls, &lockspaces, list)
 
1099
                log_error("abandoned lockspace %s", ls->name);
 
1100
}
 
1101
 
 
1102
static int lockfile(const char *dir, const char *name)
 
1103
{
 
1104
        char path[PATH_MAX];
 
1105
        char buf[16];
 
1106
        struct flock lock;
 
1107
        mode_t old_umask;
 
1108
        int fd, rv;
 
1109
 
 
1110
        old_umask = umask(0022);
 
1111
        rv = mkdir(dir, 0775);
 
1112
        if (rv < 0 && errno != EEXIST) {
 
1113
                umask(old_umask);
 
1114
                return rv;
 
1115
        }
 
1116
        umask(old_umask);
 
1117
 
 
1118
        snprintf(path, PATH_MAX, "%s/%s", dir, name);
 
1119
 
 
1120
        fd = open(path, O_CREAT|O_WRONLY|O_CLOEXEC, 0644);
 
1121
        if (fd < 0) {
 
1122
                log_error("lockfile open error %s: %s",
 
1123
                          path, strerror(errno));
 
1124
                return -1;
 
1125
        }
 
1126
 
 
1127
        lock.l_type = F_WRLCK;
 
1128
        lock.l_start = 0;
 
1129
        lock.l_whence = SEEK_SET;
 
1130
        lock.l_len = 0;
 
1131
 
 
1132
        rv = fcntl(fd, F_SETLK, &lock);
 
1133
        if (rv < 0) {
 
1134
                log_error("lockfile setlk error %s: %s",
 
1135
                          path, strerror(errno));
 
1136
                goto fail;
 
1137
        }
 
1138
 
 
1139
        rv = ftruncate(fd, 0);
 
1140
        if (rv < 0) {
 
1141
                log_error("lockfile truncate error %s: %s",
 
1142
                          path, strerror(errno));
 
1143
                goto fail;
 
1144
        }
 
1145
 
 
1146
        memset(buf, 0, sizeof(buf));
 
1147
        snprintf(buf, sizeof(buf), "%d\n", getpid());
 
1148
 
 
1149
        rv = write(fd, buf, strlen(buf));
 
1150
        if (rv <= 0) {
 
1151
                log_error("lockfile write error %s: %s",
 
1152
                          path, strerror(errno));
 
1153
                goto fail;
 
1154
        }
 
1155
 
 
1156
        return fd;
 
1157
 fail:
 
1158
        close(fd);
 
1159
        return -1;
 
1160
}
 
1161
 
 
1162
static void unlink_lockfile(int fd, const char *dir, const char *name)
 
1163
{
 
1164
        char path[PATH_MAX];
 
1165
 
 
1166
        snprintf(path, PATH_MAX, "%s/%s", dir, name);
 
1167
        unlink(path);
 
1168
        close(fd);
 
1169
}
 
1170
 
 
1171
static const char *req_arg_s(int a)
 
1172
{
 
1173
        switch (a) {
 
1174
        case no_arg:
 
1175
                return "";
 
1176
        case req_arg_bool:
 
1177
                return "0|1";
 
1178
        case req_arg_int:
 
1179
                return "<int>";
 
1180
        case req_arg_str:
 
1181
                return "<str>";
 
1182
        default:
 
1183
                return "<arg>";
 
1184
        }
 
1185
}
 
1186
 
 
1187
static void print_usage(void)
 
1188
{
 
1189
        struct dlm_option *o;
 
1190
        int i;
 
1191
 
 
1192
        printf("Usage:\n");
 
1193
        printf("\n");
 
1194
        printf("dlm_controld [options]\n");
 
1195
        printf("\n");
 
1196
        printf("Option [arg]\n");
 
1197
        printf("Description [default]\n");
 
1198
        printf("\n");
 
1199
 
 
1200
        for (i = 0; i < dlm_options_max; i++) {
 
1201
                o = &dlm_options[i];
 
1202
 
 
1203
                /* don't advertise options with no description */
 
1204
                if (!strlen(o->desc))
 
1205
                        continue;
 
1206
 
 
1207
                printf("  --%s", o->name);
 
1208
 
 
1209
                if (o->letter) {
 
1210
                        printf(" | -%c", o->letter);
 
1211
                        if (o->req_arg)
 
1212
                                printf(" %s", req_arg_s(o->req_arg));
 
1213
                } else {
 
1214
                        if (o->req_arg)
 
1215
                                printf(" %s", req_arg_s(o->req_arg));
 
1216
                }
 
1217
 
 
1218
                printf("\n");
 
1219
 
 
1220
                printf("        %s", o->desc);
 
1221
 
 
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)
 
1229
                        printf(" [0]\n");
 
1230
                else
 
1231
                        printf("\n");
 
1232
 
 
1233
                printf("\n");
 
1234
        }
 
1235
}
 
1236
 
 
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)
 
1239
{
 
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;
 
1248
}
 
1249
 
 
1250
static void set_opt_defaults(void)
 
1251
{
 
1252
        set_opt_default(daemon_debug_ind,
 
1253
                        "daemon_debug", 'D', no_arg,
 
1254
                        0, NULL,
 
1255
                        "enable debugging to stderr and don't fork");
 
1256
 
 
1257
        set_opt_default(foreground_ind,
 
1258
                        "foreground", '\0', no_arg,
 
1259
                        0, NULL,
 
1260
                        "don't fork");
 
1261
 
 
1262
        set_opt_default(log_debug_ind,
 
1263
                        "log_debug", 'K', no_arg,
 
1264
                        0, NULL,
 
1265
                        "enable kernel dlm debugging messages");
 
1266
 
 
1267
        set_opt_default(timewarn_ind,
 
1268
                        "timewarn", '\0', req_arg_int,
 
1269
                        0, NULL,
 
1270
                        ""); /* do not advertise */
 
1271
 
 
1272
        set_opt_default(protocol_ind,
 
1273
                        "protocol", 'r', req_arg_str,
 
1274
                        -1, "detect",
 
1275
                        "dlm kernel lowcomms protocol: tcp, sctp, detect");
 
1276
 
 
1277
        set_opt_default(debug_logfile_ind,
 
1278
                        "debug_logfile", 'L', no_arg,
 
1279
                        0, NULL,
 
1280
                        "write debugging to log file");
 
1281
 
 
1282
        set_opt_default(enable_fscontrol_ind,
 
1283
                        "enable_fscontrol", '\0', req_arg_bool,
 
1284
                        0, NULL,
 
1285
                        ""); /* do not advertise */
 
1286
 
 
1287
        set_opt_default(enable_plock_ind,
 
1288
                        "enable_plock", 'p', req_arg_bool,
 
1289
                        1, NULL,
 
1290
                        "enable/disable posix lock support for cluster fs");
 
1291
 
 
1292
        set_opt_default(plock_debug_ind,
 
1293
                        "plock_debug", 'P', no_arg,
 
1294
                        0, NULL,
 
1295
                        "enable plock debugging");
 
1296
 
 
1297
        set_opt_default(plock_rate_limit_ind,
 
1298
                        "plock_rate_limit", 'l', req_arg_int,
 
1299
                        0, NULL,
 
1300
                        "limit rate of plock operations (0 for none)");
 
1301
 
 
1302
        set_opt_default(plock_ownership_ind,
 
1303
                        "plock_ownership", 'o', req_arg_bool,
 
1304
                        0, NULL,
 
1305
                        "enable/disable plock ownership");
 
1306
 
 
1307
        set_opt_default(drop_resources_time_ind,
 
1308
                        "drop_resources_time", 't', req_arg_int,
 
1309
                        10000, NULL,
 
1310
                        "plock ownership drop resources time (milliseconds)");
 
1311
 
 
1312
        set_opt_default(drop_resources_count_ind,
 
1313
                        "drop_resources_count", 'c', req_arg_int,
 
1314
                        10, NULL,
 
1315
                        "plock ownership drop resources count");
 
1316
 
 
1317
        set_opt_default(drop_resources_age_ind,
 
1318
                        "drop_resources_age", 'a', req_arg_int,
 
1319
                        10000, NULL,
 
1320
                        "plock ownership drop resources age (milliseconds)");
 
1321
 
 
1322
        set_opt_default(post_join_delay_ind,
 
1323
                        "post_join_delay", 'j', req_arg_int,
 
1324
                        30, NULL,
 
1325
                        "seconds to delay fencing after cluster join");
 
1326
 
 
1327
        set_opt_default(enable_fencing_ind,
 
1328
                        "enable_fencing", 'f', req_arg_bool,
 
1329
                        1, NULL,
 
1330
                        "enable/disable fencing");
 
1331
 
 
1332
        set_opt_default(enable_concurrent_fencing_ind,
 
1333
                        "enable_concurrent_fencing", '\0', req_arg_bool,
 
1334
                        0, NULL,
 
1335
                        "enable/disable concurrent fencing");
 
1336
 
 
1337
        set_opt_default(enable_startup_fencing_ind,
 
1338
                        "enable_startup_fencing", 's', req_arg_bool,
 
1339
                        1, NULL,
 
1340
                        "enable/disable startup fencing");
 
1341
 
 
1342
        set_opt_default(enable_quorum_fencing_ind,
 
1343
                        "enable_quorum_fencing", 'q', req_arg_bool,
 
1344
                        1, NULL,
 
1345
                        "enable/disable quorum requirement for fencing");
 
1346
 
 
1347
        set_opt_default(enable_quorum_lockspace_ind,
 
1348
                        "enable_quorum_lockspace", '\0', req_arg_bool,
 
1349
                        1, NULL,
 
1350
                        "enable/disable quorum requirement for lockspace operations");
 
1351
 
 
1352
        set_opt_default(help_ind,
 
1353
                        "help", 'h', no_arg,
 
1354
                        -1, NULL,
 
1355
                        "print this help, then exit");
 
1356
 
 
1357
        set_opt_default(version_ind,
 
1358
                        "version", 'V', no_arg,
 
1359
                        -1, NULL,
 
1360
                        "Print program version information, then exit");
 
1361
}
 
1362
 
 
1363
static int get_ind_name(char *s)
 
1364
{
 
1365
        char name[PATH_MAX];
 
1366
        char *p = s;
 
1367
        int i;
 
1368
 
 
1369
        memset(name, 0, sizeof(name));
 
1370
 
 
1371
        for (i = 0; i < strlen(s); i++) {
 
1372
                if (*p == '=')
 
1373
                        break;
 
1374
                if (*p == ' ')
 
1375
                        break;
 
1376
                name[i] = *p;
 
1377
                p++;
 
1378
        }
 
1379
 
 
1380
        for (i = 0; i < dlm_options_max; i++) {
 
1381
                if (!strcmp(dlm_options[i].name, name))
 
1382
                        return i;
 
1383
        }
 
1384
        return -1;
 
1385
}
 
1386
 
 
1387
static int get_ind_letter(char c)
 
1388
{
 
1389
        int i;
 
1390
 
 
1391
        for (i = 0; i < dlm_options_max; i++) {
 
1392
                if (dlm_options[i].letter == c)
 
1393
                        return i;
 
1394
        }
 
1395
        return -1;
 
1396
}
 
1397
 
 
1398
struct dlm_option *get_dlm_option(char *name)
 
1399
{
 
1400
        int i;
 
1401
        i = get_ind_name(name);
 
1402
        if (i < 0)
 
1403
                return NULL;
 
1404
        return &dlm_options[i];
 
1405
}
 
1406
 
 
1407
static void set_opt_cli(int argc, char **argv)
 
1408
{
 
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;
 
1414
        int i, ind;
 
1415
 
 
1416
        if (argc < 2)
 
1417
                return;
 
1418
 
 
1419
        arg1 = argv[1];
 
1420
 
 
1421
        if (!strcmp(arg1, "help") || !strcmp(arg1, "--help") || !strcmp(arg1, "-h")) {
 
1422
                print_usage();
 
1423
                exit(EXIT_SUCCESS);
 
1424
        }
 
1425
 
 
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);
 
1430
                exit(EXIT_SUCCESS);
 
1431
        }
 
1432
 
 
1433
        for (i = 1; i < argc; ) {
 
1434
                p = argv[i++];
 
1435
 
 
1436
                if (!strcmp(p, "--debug_options")) {
 
1437
                        debug_options = 1;
 
1438
                        continue;
 
1439
                }
 
1440
 
 
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]);
 
1445
                else {
 
1446
                        fprintf(stderr, "unknown option arg %s\n", p);
 
1447
                        exit(EXIT_FAILURE);
 
1448
                }
 
1449
 
 
1450
                if (ind < 0) {
 
1451
                        fprintf(stderr, "unknown option %s\n", p);
 
1452
                        exit(EXIT_FAILURE);
 
1453
                }
 
1454
 
 
1455
                o = &dlm_options[ind];
 
1456
                o->cli_set++;
 
1457
 
 
1458
                if (!o->req_arg) {
 
1459
                        /* "-x" has same effect as "-x 1" */
 
1460
                        o->cli_int = 1;
 
1461
                        o->use_int = 1;
 
1462
 
 
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++) {
 
1466
                                        if (!isalpha(p[b]))
 
1467
                                                break;
 
1468
                                        bundled_letters[blc++] = p[b];
 
1469
                                }
 
1470
                        }
 
1471
                        continue;
 
1472
                }
 
1473
 
 
1474
                arg_str = NULL;
 
1475
 
 
1476
                if (strstr(p, "=")) {
 
1477
                        /* arg starts after = for name or letter */
 
1478
                        arg_str = strstr(p, "=") + 1;
 
1479
 
 
1480
                } else if (strlen(p) > 2 && isalpha(p[1]) && isdigit(p[2])) {
 
1481
                        /* arg with no space between letter and digits */
 
1482
                        arg_str = p + 2;
 
1483
 
 
1484
                } else {
 
1485
                        /* space separates arg from name or letter */
 
1486
                        if (i >= argc) {
 
1487
                                fprintf(stderr, "option %s no arg", p);
 
1488
                                exit(EXIT_FAILURE);
 
1489
                        }
 
1490
                        arg_str = argv[i++];
 
1491
                }
 
1492
 
 
1493
                if (!arg_str || arg_str[0] == '-' || arg_str[0] == '\0') {
 
1494
                        fprintf(stderr, "option %s requires arg", p);
 
1495
                        exit(EXIT_FAILURE);
 
1496
                }
 
1497
 
 
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;
 
1507
                }
 
1508
        }
 
1509
 
 
1510
        /* process bundled letters saved above */
 
1511
 
 
1512
        for (i = 0; i < blc; i++) {
 
1513
                ind = get_ind_letter(bundled_letters[i]);
 
1514
                if (ind < 0) {
 
1515
                        fprintf(stderr, "unknown option char %c\n", bundled_letters[i]);
 
1516
                        exit(EXIT_FAILURE);
 
1517
                }
 
1518
                o = &dlm_options[ind];
 
1519
                o->cli_set++;
 
1520
                o->cli_int = 1;
 
1521
                o->use_int = 1;
 
1522
        }
 
1523
 
 
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);
 
1529
                }
 
1530
        }
 
1531
 
 
1532
        if (getenv("DLM_CONTROLD_DEBUG")) {
 
1533
                dlm_options[daemon_debug_ind].use_int = 1;
 
1534
        }
 
1535
}
 
1536
 
 
1537
#if 0
 
1538
/* When this is used, the systemd service file needs ControlGroup=cpu:/ */
 
1539
static void set_scheduler(void)
 
1540
{
 
1541
        struct sched_param sched_param;
 
1542
        int rv;
 
1543
 
 
1544
        rv = sched_get_priority_max(SCHED_RR);
 
1545
        if (rv != -1) {
 
1546
                sched_param.sched_priority = rv;
 
1547
                rv = sched_setscheduler(0, SCHED_RR, &sched_param);
 
1548
                if (rv == -1)
 
1549
                        log_error("could not set SCHED_RR priority %d err %d",
 
1550
                                   sched_param.sched_priority, errno);
 
1551
        } else {
 
1552
                log_error("could not get maximum scheduler priority err %d",
 
1553
                          errno);
 
1554
        }
 
1555
}
 
1556
#endif
 
1557
 
 
1558
int main(int argc, char **argv)
 
1559
{
 
1560
        struct sigaction act;
 
1561
        int fd, rv;
 
1562
 
 
1563
        /*
 
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
 
1568
         */
 
1569
 
 
1570
        set_opt_defaults();
 
1571
        set_opt_cli(argc, argv);
 
1572
        set_opt_file(0);
 
1573
 
 
1574
        strcpy(fence_all_device.name, "fence_all");
 
1575
        strcpy(fence_all_device.agent, "dlm_stonith");
 
1576
        fence_all_device.unfence = 0;
 
1577
 
 
1578
        INIT_LIST_HEAD(&lockspaces);
 
1579
        INIT_LIST_HEAD(&fs_register_list);
 
1580
        init_daemon();
 
1581
 
 
1582
        if (!opt(daemon_debug_ind) && !opt(foreground_ind)) {
 
1583
                if (daemon(0, 0) < 0) {
 
1584
                        perror("daemon error");
 
1585
                        exit(EXIT_FAILURE);
 
1586
                }
 
1587
        }
 
1588
 
 
1589
        init_logging();
 
1590
 
 
1591
        fd = lockfile(RUNDIR, RUN_FILE_NAME);
 
1592
        if (fd < 0)
 
1593
                return fd;
 
1594
 
 
1595
        log_level(NULL, LOG_INFO, "dlm_controld %s started", RELEASE_VERSION);
 
1596
 
 
1597
        memset(&act, 0, sizeof(act));
 
1598
        act.sa_handler = sigterm_handler;
 
1599
        rv = sigaction(SIGTERM, &act, NULL);
 
1600
        if (rv < 0)
 
1601
                return -rv;
 
1602
        rv = sigaction(SIGINT, &act, NULL);
 
1603
        if (rv < 0)
 
1604
                return -rv;
 
1605
 
 
1606
        memset(&act, 0, sizeof(act));
 
1607
        act.sa_handler = SIG_IGN;
 
1608
        rv = sigaction(SIGHUP, &act, NULL);
 
1609
        if (rv < 0)
 
1610
                return -rv;
 
1611
 
 
1612
        memset(&act, 0, sizeof(act));
 
1613
        act.sa_handler = sigchld_handler;
 
1614
        act.sa_flags = SA_NOCLDSTOP;
 
1615
        rv = sigaction(SIGCHLD, &act, NULL);
 
1616
        if (rv < 0)
 
1617
                return -rv;
 
1618
 
 
1619
        /* set_scheduler(); */
 
1620
 
 
1621
        loop();
 
1622
 
 
1623
        unlink_lockfile(fd, RUNDIR, RUN_FILE_NAME);
 
1624
        return 0;
 
1625
}
 
1626