~wb-munzinger/+junk/ocfs2-tools

« back to all changes in this revision

Viewing changes to ocfs2_controld/ckpt.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2009-07-06 07:26:30 UTC
  • mfrom: (1.1.7 upstream) (0.1.5 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090706072630-59335sl51k3rvu74
Tags: 1.4.2-1
* New upstream release (Closes: #535471).
* Drop patch for limits.h, included upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c; c-basic-offset: 8; -*-
 
2
 * vim: noexpandtab sw=8 ts=8 sts=0:
 
3
 *
 
4
 * Copyright (C) 2008 Oracle.  All rights reserved.
 
5
 *
 
6
 *  This copyrighted material is made available to anyone wishing to use,
 
7
 *  modify, copy, or redistribute it subject to the terms and conditions
 
8
 *  of the GNU General Public License v.2.
 
9
 */
 
10
 
 
11
 
 
12
#include <stdio.h>
 
13
#include <stdlib.h>
 
14
#include <stddef.h>
 
15
#include <stdarg.h>
 
16
#include <string.h>
 
17
#include <sys/types.h>
 
18
#include <sys/stat.h>
 
19
#include <limits.h>
 
20
#include <inttypes.h>
 
21
#include <errno.h>
 
22
#include <syslog.h>
 
23
#include <time.h>
 
24
#include <unistd.h>
 
25
#include <assert.h>
 
26
#include <openais/saAis.h>
 
27
#include <openais/saCkpt.h>
 
28
 
 
29
#include "ocfs2_controld.h"
 
30
 
 
31
 
 
32
 
 
33
struct ckpt_handle {
 
34
        SaNameT                 ch_name;
 
35
        SaCkptCheckpointHandleT ch_handle;
 
36
};
 
37
 
 
38
static SaCkptHandleT daemon_handle;
 
39
struct ckpt_handle *global_handle;
 
40
 
 
41
/* This is the version OpenAIS supports */
 
42
static SaVersionT version = { 'B', 1, 1 };
 
43
 
 
44
static SaCkptCallbacksT callbacks = {
 
45
        NULL,
 
46
        NULL,
 
47
};
 
48
 
 
49
/*
 
50
 * All of our checkpoints store 4K of data in 32 sections of 128bytes.  We
 
51
 * probably won't actually use more than one section of each checkpoint,
 
52
 * but we spec them larger so that we can use space later compatibly.  Note
 
53
 * that data space is only allocated when needed, so if we store one section
 
54
 * of 10 bytes, the checkpoint uses 10 bytes, not 4K.
 
55
 *
 
56
 * Retention time is 0 - when a daemon exits, it should disappear.
 
57
 *
 
58
 * Max section ID size is basically big enough to hold a uuid (32
 
59
 * characters) plus something extra.  We don't use uuids in section names
 
60
 * yet, but just in case.
 
61
 */
 
62
#define CKPT_MAX_SECTION_SIZE   128
 
63
#define CKPT_MAX_SECTIONS       32
 
64
#define CKPT_MAX_SECTION_ID     40
 
65
static SaCkptCheckpointCreationAttributesT ckpt_attributes = {
 
66
        .creationFlags          = SA_CKPT_WR_ALL_REPLICAS,
 
67
        .checkpointSize         = 4096,
 
68
        .retentionDuration      = 0LL,
 
69
        .maxSections            = CKPT_MAX_SECTIONS,
 
70
        .maxSectionSize         = CKPT_MAX_SECTION_SIZE,
 
71
        .maxSectionIdSize       = CKPT_MAX_SECTION_ID,
 
72
};
 
73
 
 
74
static void ais_err_to_errno(SaAisErrorT error, int *rc, char **reason)
 
75
{
 
76
        switch (error) {
 
77
                case SA_AIS_OK:
 
78
                        *rc = 0;
 
79
                        *reason = "Success";
 
80
                        break;
 
81
                case SA_AIS_ERR_LIBRARY:
 
82
                        *rc = -ENXIO;
 
83
                        *reason = "Internal library error";
 
84
                        break;
 
85
                case SA_AIS_ERR_TIMEOUT:
 
86
                        *rc = -ETIMEDOUT;
 
87
                        *reason = "Timed out";
 
88
                        break;
 
89
                case SA_AIS_ERR_TRY_AGAIN:
 
90
                        *rc = -EAGAIN;
 
91
                        *reason = "Try again";
 
92
                        break;
 
93
                case SA_AIS_ERR_INVALID_PARAM:
 
94
                        *rc = -EINVAL;
 
95
                        *reason = "Invalid parameter";
 
96
                        break;
 
97
                case SA_AIS_ERR_NO_MEMORY:
 
98
                        *rc = -ENOMEM;
 
99
                        *reason = "Out of memory";
 
100
                        break;
 
101
                case SA_AIS_ERR_NO_RESOURCES:
 
102
                        *rc = -EBUSY;
 
103
                        *reason = "Insufficient resources";
 
104
                        break;
 
105
                case SA_AIS_ERR_VERSION:
 
106
                        *rc = -EPROTOTYPE;
 
107
                        *reason = "Protocol not compatible";
 
108
                        break;
 
109
                case SA_AIS_ERR_BAD_HANDLE:
 
110
                        *rc = -EINVAL;
 
111
                        *reason = "Bad Ckpt handle";
 
112
                        break;
 
113
                case SA_AIS_ERR_INIT:
 
114
                        *rc = -ENODEV;
 
115
                        *reason = "Initialization not complete";
 
116
                        break;
 
117
                case SA_AIS_ERR_NOT_EXIST:
 
118
                        *rc = -ENOENT;
 
119
                        *reason = "Object does not exist";
 
120
                        break;
 
121
                case SA_AIS_ERR_EXIST:
 
122
                        *rc = -EEXIST;
 
123
                        *reason = "Object already exists";
 
124
                        break;
 
125
                case SA_AIS_ERR_BAD_FLAGS:
 
126
                        *rc = -EINVAL;
 
127
                        *reason = "Invalid flags";
 
128
                        break;
 
129
                case SA_AIS_ERR_ACCESS:
 
130
                        *rc = -EACCES;
 
131
                        *reason = "Permission denied";
 
132
                        break;
 
133
                default:
 
134
                        *rc = -ENOSYS;
 
135
                        *reason = "Unknown error";
 
136
                        log_error("Unknown error seen! (%d)", error);
 
137
                        break;
 
138
        }
 
139
}
 
140
 
 
141
/*
 
142
 * Our retention-time scheme of 0 means that we need to create any
 
143
 * checkpoint we want to update.  Nobody is writing to the same checkpoint
 
144
 * at the same time.
 
145
 */
 
146
static int call_ckpt_open(struct ckpt_handle *handle, int write)
 
147
{
 
148
        int rc, existcount = 0, againcount = 0;
 
149
        char *reason;
 
150
        SaAisErrorT error;
 
151
        int flags = SA_CKPT_CHECKPOINT_READ;
 
152
 
 
153
        if (write)
 
154
                flags |= (SA_CKPT_CHECKPOINT_WRITE |
 
155
                          SA_CKPT_CHECKPOINT_CREATE);
 
156
 
 
157
        while (1) {
 
158
                log_debug("Opening checkpoint \"%.*s\" (try %d)",
 
159
                          handle->ch_name.length, handle->ch_name.value,
 
160
                          existcount + againcount + 1);
 
161
                error = saCkptCheckpointOpen(daemon_handle,
 
162
                                             &handle->ch_name,
 
163
                                             write ? &ckpt_attributes : NULL,
 
164
                                             flags, 0, &handle->ch_handle);
 
165
                ais_err_to_errno(error, &rc, &reason);
 
166
                if (!rc) {
 
167
                        log_debug("Opened checkpoint \"%.*s\" with handle 0x%llx",
 
168
                                  handle->ch_name.length,
 
169
                                  handle->ch_name.value,
 
170
                                  handle->ch_handle);
 
171
                        break;
 
172
                }
 
173
                if ((rc != -EAGAIN) &&
 
174
                    (!write || (rc != -EEXIST))){
 
175
                        log_error("Unable to open checkpoint \"%.*s\": %s",
 
176
                                  handle->ch_name.length,
 
177
                                  handle->ch_name.value,
 
178
                                  reason);
 
179
                        break;
 
180
                }
 
181
                if (write && (rc == -EEXIST)) {
 
182
                        /*
 
183
                         * EEXIST means one of two things:
 
184
                         *
 
185
                         * 1) Another daemon is up and running.  This
 
186
                         *    one is just going to sit here printing to
 
187
                         *    the log until it's killed or the other one
 
188
                         *    dies.  This will confuse people; they'll
 
189
                         *    stop the running daemon, but not be able to
 
190
                         *    unload the stack.  We have to do this because
 
191
                         *    of reason (2).
 
192
                         *
 
193
                         * 2) The daemon was stopped and then immediately
 
194
                         *    restarted.  AIS cleans up the checkpoint
 
195
                         *    in a lazy fashion, so there is no guarantee
 
196
                         *    the checkpoint is gone by the time the new
 
197
                         *    daemon starts up.  So we can get an EEXIST
 
198
                         *    for a little while until AIS gets around to
 
199
                         *    the cleanup.  Because scheduling, etc, can
 
200
                         *    take a while, we don't know how long that
 
201
                         *    will be.  So we keep retrying.  Eventually,
 
202
                         *    AIS will clean up the checkpoint from the
 
203
                         *    daemon that exited and let us create our new
 
204
                         *    one.
 
205
                         */
 
206
                        retry_warning(existcount,
 
207
                                      "Checkpoint exists seen %d times "
 
208
                                      "while opening checkpoint  \"%.*s\", "
 
209
                                      "still trying",
 
210
                                      existcount,
 
211
                                      handle->ch_name.length,
 
212
                                      handle->ch_name.value);
 
213
                } else if (rc == -EAGAIN) {
 
214
                        /* TRY_AGAIN is Ckpt saying it's just busy. */
 
215
                        retry_warning(againcount,
 
216
                                      "TRY_AGAIN seen %d times while "
 
217
                                      "opening checkpoint \"%.*s\", "
 
218
                                      "still trying",
 
219
                                      againcount,
 
220
                                      handle->ch_name.length,
 
221
                                      handle->ch_name.value);
 
222
                } else
 
223
                        assert(0);
 
224
 
 
225
                sleep_ms(10);
 
226
        }
 
227
 
 
228
        return rc;
 
229
}
 
230
 
 
231
static void call_ckpt_close(struct ckpt_handle *handle)
 
232
{
 
233
        int rc, againcount = 0;
 
234
        char *reason;
 
235
        SaAisErrorT error;
 
236
 
 
237
        while (1) {
 
238
                log_debug("Closing checkpoint \"%.*s\" (try %d)",
 
239
                          handle->ch_name.length, handle->ch_name.value,
 
240
                          againcount + 1);
 
241
                error = saCkptCheckpointClose(handle->ch_handle);
 
242
                ais_err_to_errno(error, &rc, &reason);
 
243
                if (!rc) {
 
244
                        log_debug("Closed checkpoint \"%.*s\"",
 
245
                                  handle->ch_name.length,
 
246
                                  handle->ch_name.value);
 
247
                        break;
 
248
                }
 
249
                if (rc != -EAGAIN) {
 
250
                        log_error("Unable to close checkpoint \"%.*s\": %s",
 
251
                                  handle->ch_name.length,
 
252
                                  handle->ch_name.value,
 
253
                                  reason);
 
254
                        break;
 
255
                }
 
256
 
 
257
                retry_warning(againcount,
 
258
                              "TRY_AGAIN seen %d times while "
 
259
                              "closing checkpoint \"%.*s\", "
 
260
                              "still trying",
 
261
                              againcount,
 
262
                              handle->ch_name.length,
 
263
                              handle->ch_name.value);
 
264
 
 
265
                sleep_ms(10);
 
266
        }
 
267
}
 
268
 
 
269
/*
 
270
 * All of our sections live for the life of the checkpoint.  We don't need
 
271
 * to delete them.
 
272
 */
 
273
static int call_section_create(struct ckpt_handle *handle, const char *name,
 
274
                               const char *data, size_t data_len)
 
275
{
 
276
        int rc, againcount = 0;
 
277
        char *reason;
 
278
        SaAisErrorT error;
 
279
        SaCkptSectionIdT id = {
 
280
                .idLen = strlen(name),
 
281
                .id = (SaUint8T *)name,
 
282
        };
 
283
        SaCkptSectionCreationAttributesT attrs = {
 
284
                .sectionId = &id,
 
285
                .expirationTime = SA_TIME_END,
 
286
        };
 
287
 
 
288
        while (1) {
 
289
                log_debug("Creating section \"%s\" on checkpoint "
 
290
                          "\"%.*s\" (try %d)",
 
291
                          name, handle->ch_name.length,
 
292
                          handle->ch_name.value, againcount + 1);
 
293
                error = saCkptSectionCreate(handle->ch_handle, &attrs,
 
294
                                            data, data_len);
 
295
                ais_err_to_errno(error, &rc, &reason);
 
296
                if (!rc) {
 
297
                        log_debug("Created section \"%s\" on checkpoint "
 
298
                                  "\"%.*s\"",
 
299
                                  name, handle->ch_name.length,
 
300
                                  handle->ch_name.value);
 
301
                        break;
 
302
                }
 
303
                if (rc != -EAGAIN) {
 
304
                        log_error("Unable to create section \"%s\" on "
 
305
                                  "checkpoint \"%.*s\": %s",
 
306
                                  name, handle->ch_name.length,
 
307
                                  handle->ch_name.value, reason);
 
308
                        break;
 
309
                }
 
310
 
 
311
                retry_warning(againcount,
 
312
                              "TRY_AGAIN seen %d times while "
 
313
                              "creating section \"%s\" on checkpoint "
 
314
                              "\"%.*s\", still trying",
 
315
                              againcount, name,
 
316
                              handle->ch_name.length,
 
317
                              handle->ch_name.value);
 
318
 
 
319
                sleep_ms(10);
 
320
}
 
321
 
 
322
        return rc;
 
323
}
 
324
 
 
325
static int call_section_write(struct ckpt_handle *handle, const char *name,
 
326
                              const char *data, size_t data_len)
 
327
{
 
328
        int rc, againcount = 0;
 
329
        char *reason;
 
330
        SaAisErrorT error;
 
331
        SaCkptSectionIdT id = {
 
332
                .idLen = strlen(name),
 
333
                .id = (SaUint8T *)name,
 
334
        };
 
335
 
 
336
        while (1) {
 
337
                log_debug("Writing to section \"%s\" on checkpoint "
 
338
                          "\"%.*s\" (try %d)",
 
339
                          name, handle->ch_name.length,
 
340
                          handle->ch_name.value, againcount + 1);
 
341
                error = saCkptSectionOverwrite(handle->ch_handle, &id,
 
342
                                               data, data_len);
 
343
                ais_err_to_errno(error, &rc, &reason);
 
344
                if (!rc) {
 
345
                        log_debug("Stored section \"%s\" on checkpoint "
 
346
                                  "\"%.*s\"",
 
347
                                  name, handle->ch_name.length,
 
348
                                  handle->ch_name.value);
 
349
                        break;
 
350
                }
 
351
 
 
352
                /* If it doesn't exist, create it. */
 
353
                if (rc == -ENOENT) {
 
354
                        rc = call_section_create(handle, name, data, data_len);
 
355
                        break;
 
356
                }
 
357
 
 
358
                if (rc != -EAGAIN) {
 
359
                        log_error("Unable to write section \"%s\" on "
 
360
                                  "checkpoint \"%.*s\": %s",
 
361
                                  name, handle->ch_name.length,
 
362
                                  handle->ch_name.value, reason);
 
363
                        break;
 
364
                }
 
365
 
 
366
                retry_warning(againcount,
 
367
                              "TRY_AGAIN seen %d times while "
 
368
                              "writing section \"%s\" on checkpoint "
 
369
                              "\"%.*s\", still trying",
 
370
                              againcount, name,
 
371
                              handle->ch_name.length,
 
372
                              handle->ch_name.value);
 
373
 
 
374
                sleep_ms(10);
 
375
        }
 
376
 
 
377
        return rc;
 
378
}
 
379
 
 
380
static int call_section_read(struct ckpt_handle *handle, const char *name,
 
381
                             char **data, size_t *data_len)
 
382
{
 
383
        int rc, againcount = 0;
 
384
        char *reason, *p;
 
385
        char readbuf[CKPT_MAX_SECTION_SIZE];
 
386
        SaAisErrorT error;
 
387
        SaCkptIOVectorElementT readvec[] = {
 
388
                {
 
389
                        .sectionId = {
 
390
                                .idLen = strlen(name),
 
391
                                .id = (SaUint8T *)name,
 
392
                        },
 
393
                        .dataBuffer = readbuf,
 
394
                        .dataSize = CKPT_MAX_SECTION_SIZE,
 
395
                }
 
396
        };
 
397
 
 
398
        while (1) {
 
399
                log_debug("Reading from section \"%s\" on checkpoint "
 
400
                          "\"%.*s\" (try %d)",
 
401
                          name, handle->ch_name.length,
 
402
                          handle->ch_name.value, againcount + 1);
 
403
                error = saCkptCheckpointRead(handle->ch_handle, readvec, 1,
 
404
                                             NULL);
 
405
                ais_err_to_errno(error, &rc, &reason);
 
406
                if (!rc) {
 
407
                        log_debug("Read section \"%s\" from checkpoint "
 
408
                                  "\"%.*s\"",
 
409
                                  name, handle->ch_name.length,
 
410
                                  handle->ch_name.value);
 
411
                        break;
 
412
                }
 
413
 
 
414
                /* -ENOENT is a clean error for the caller to handle */
 
415
                if (rc == -ENOENT) {
 
416
                        log_debug("Checkpoint \"%.*s\" does not have a "
 
417
                                  "section named \"%s\"",
 
418
                                  handle->ch_name.length,
 
419
                                  handle->ch_name.value, name);
 
420
                        break;
 
421
                }
 
422
 
 
423
                if (rc != -EAGAIN) {
 
424
                        log_error("Unable to read section \"%s\" from "
 
425
                                  "checkpoint \"%.*s\": %s",
 
426
                                  name, handle->ch_name.length,
 
427
                                  handle->ch_name.value, reason);
 
428
                        break;
 
429
                }
 
430
 
 
431
                retry_warning(againcount,
 
432
                              "TRY_AGAIN seen %d times while "
 
433
                              "reading section \"%s\" on checkpoint "
 
434
                              "\"%.*s\", still trying",
 
435
                              againcount, name,
 
436
                              handle->ch_name.length,
 
437
                              handle->ch_name.value);
 
438
 
 
439
                sleep_ms(10);
 
440
        }
 
441
 
 
442
        if (rc)
 
443
                goto out;
 
444
 
 
445
        p = malloc(sizeof(char) * readvec[0].readSize);
 
446
        if (p) {
 
447
                memcpy(p, readbuf, readvec[0].readSize);
 
448
                *data = p;
 
449
                *data_len = readvec[0].readSize;
 
450
        } else {
 
451
                log_error("Unable to allocate memory while reading section "
 
452
                          "\"%s\" from checkpoint \"%.*s\"",
 
453
                          name, handle->ch_name.length,
 
454
                          handle->ch_name.value);
 
455
                rc = -ENOMEM;
 
456
                goto out;
 
457
        }
 
458
 
 
459
out:
 
460
        return rc;
 
461
}
 
462
 
 
463
int ckpt_section_store(struct ckpt_handle *handle, const char *section,
 
464
                       const char *data, size_t data_len)
 
465
{
 
466
        if (strlen(section) > CKPT_MAX_SECTION_ID) {
 
467
                log_error("Error: section id \"%s\" is too long "
 
468
                          "(max is %d)",
 
469
                          section, CKPT_MAX_SECTION_ID);
 
470
                return -EINVAL;
 
471
        }
 
472
        if (data_len > CKPT_MAX_SECTION_SIZE) {
 
473
                log_error("Error: attempt to store %d bytes in a section "
 
474
                          "(max is %d)",
 
475
                          data_len, CKPT_MAX_SECTION_SIZE);
 
476
                return -EINVAL;
 
477
        }
 
478
 
 
479
        return call_section_write(handle, section, data, data_len);
 
480
}
 
481
 
 
482
int ckpt_global_store(const char *section, const char *data, size_t data_len)
 
483
{
 
484
        if (!global_handle) {
 
485
                log_error("Error: The global checkpoint is not initialized");
 
486
                return -EINVAL;
 
487
        }
 
488
 
 
489
        return ckpt_section_store(global_handle, section, data, data_len);
 
490
}
 
491
 
 
492
int ckpt_section_get(struct ckpt_handle *handle, const char *section,
 
493
                     char **data, size_t *data_len)
 
494
{
 
495
        if (strlen(section) > CKPT_MAX_SECTION_ID) {
 
496
                log_error("Error: section id \"%s\" is too long "
 
497
                          "(max is %d)",
 
498
                          section, CKPT_MAX_SECTION_ID);
 
499
                return -EINVAL;
 
500
        }
 
501
 
 
502
        return call_section_read(handle, section, data, data_len);
 
503
}
 
504
 
 
505
int ckpt_global_get(const char *section, char **data, size_t *data_len)
 
506
{
 
507
        if (!global_handle) {
 
508
                log_error("Error: The global checkpoint is not initialized");
 
509
                return -EINVAL;
 
510
        }
 
511
 
 
512
        return call_section_read(global_handle, section, data, data_len);
 
513
}
 
514
 
 
515
/*
 
516
 * We name our ckeckpoints in one of three ways, all prefixed with 'ocfs2:'.
 
517
 *
 
518
 * The global checkpoint is named 'ocfs2:controld'.
 
519
 * The node info checkpoint is named 'ocfs2:controld:<8-hex-char-nodeid>'
 
520
 * A mount checkpoint is named 'ocfs2:<uuid>:<8-hex-char-nodeid>'
 
521
 */
 
522
#define CKPT_PREFIX "ocfs2:"
 
523
static int ckpt_new(const char *name, int write, struct ckpt_handle **handle)
 
524
{
 
525
        int rc;
 
526
        size_t namelen = strlen(name) + strlen(CKPT_PREFIX);
 
527
        struct ckpt_handle *h;
 
528
 
 
529
        if (namelen > SA_MAX_NAME_LENGTH) {
 
530
                log_error("Checkpoint name \"%s\" too long", name);
 
531
                return -EINVAL;
 
532
        }
 
533
 
 
534
        h = malloc(sizeof(struct ckpt_handle));
 
535
        if (!h) {
 
536
                log_error("Unable to allocate checkpoint handle");
 
537
                return -ENOMEM;
 
538
        }
 
539
 
 
540
        memset(h, 0, sizeof(struct ckpt_handle));
 
541
        h->ch_name.length = snprintf((char *)(h->ch_name.value),
 
542
                                     SA_MAX_NAME_LENGTH, "%s%s",
 
543
                                     CKPT_PREFIX, name);
 
544
 
 
545
        rc = call_ckpt_open(h, write);
 
546
        if (!rc)
 
547
                *handle = h;
 
548
        else
 
549
                free(h);
 
550
 
 
551
        return rc;
 
552
}
 
553
 
 
554
static void ckpt_free(struct ckpt_handle *handle)
 
555
{
 
556
        if (handle->ch_handle)
 
557
                call_ckpt_close(handle);
 
558
 
 
559
        free(handle);
 
560
}
 
561
 
 
562
int ckpt_open_global(int write)
 
563
{
 
564
        if (global_handle)
 
565
                return 0;
 
566
 
 
567
        return ckpt_new("controld", write, &global_handle);
 
568
}
 
569
 
 
570
void ckpt_close_global(void)
 
571
{
 
572
        if (global_handle) {
 
573
                ckpt_free(global_handle);
 
574
                global_handle = NULL;
 
575
        }
 
576
}
 
577
 
 
578
int ckpt_open_node(int nodeid, struct ckpt_handle **handle)
 
579
{
 
580
        char name[SA_MAX_NAME_LENGTH];
 
581
 
 
582
        snprintf(name, SA_MAX_NAME_LENGTH, "controld:%08x", nodeid);
 
583
 
 
584
        return ckpt_new(name, 0, handle);
 
585
}
 
586
 
 
587
int ckpt_open_this_node(struct ckpt_handle **handle)
 
588
{
 
589
        char name[SA_MAX_NAME_LENGTH];
 
590
 
 
591
        snprintf(name, SA_MAX_NAME_LENGTH, "controld:%08x", our_nodeid);
 
592
 
 
593
        return ckpt_new(name, 1, handle);
 
594
}
 
595
 
 
596
void ckpt_close(struct ckpt_handle *handle)
 
597
{
 
598
        ckpt_free(handle);
 
599
}
 
600
 
 
601
int setup_ckpt(void)
 
602
{
 
603
        int rc, againcount = 0;
 
604
        char *reason;
 
605
        SaAisErrorT error;
 
606
 
 
607
        while (1) {
 
608
                log_debug("Initializing CKPT service (try %d)",
 
609
                          againcount + 1);
 
610
                error = saCkptInitialize(&daemon_handle, &callbacks,
 
611
                                         &version);
 
612
                ais_err_to_errno(error, &rc, &reason);
 
613
                if (!rc) {
 
614
                        log_debug("Connected to CKPT service with handle 0x%llx",
 
615
                                  daemon_handle);
 
616
                        break;
 
617
                }
 
618
                if (rc != -EAGAIN) {
 
619
                        log_error("Unable to connect to CKPT: %s", reason);
 
620
                        break;
 
621
                }
 
622
                retry_warning(againcount,
 
623
                              "TRY_AGAIN seen %d times while "
 
624
                              "connectiong to CKPT, still trying",
 
625
                              againcount);
 
626
                sleep_ms(10);
 
627
        }
 
628
 
 
629
        return rc;
 
630
}
 
631
 
 
632
void exit_ckpt(void)
 
633
{
 
634
        int rc, againcount = 0;
 
635
        char *reason;
 
636
        SaAisErrorT error;
 
637
 
 
638
        if (!daemon_handle)
 
639
                return;
 
640
 
 
641
        while (1) {
 
642
                log_debug("Disconnecting from CKPT service (try %d)",
 
643
                          againcount + 1);
 
644
                error = saCkptFinalize(daemon_handle);
 
645
                ais_err_to_errno(error, &rc, &reason);
 
646
                if (!rc) {
 
647
                        log_debug("Disconnected from CKPT service");
 
648
                        break;
 
649
                }
 
650
                if (rc != -EAGAIN) {
 
651
                        log_error("Unable to disconnect from CKPT: %s",
 
652
                                  reason);
 
653
                        break;
 
654
                }
 
655
                retry_warning(againcount,
 
656
                              "TRY_AGAIN seen %d times while "
 
657
                              "disconnecting to CKPT, still trying",
 
658
                              againcount);
 
659
                sleep_ms(10);
 
660
        }
 
661
}
 
662
 
 
663
#ifdef DEBUG_EXE
 
664
int dump_point, dump_wrap, daemon_debug_opt = 1;
 
665
char daemon_debug_buf[1024];
 
666
char dump_buf[DUMP_SIZE];
 
667
void daemon_dump_save(void)
 
668
{
 
669
        int len, i;
 
670
 
 
671
        len = strlen(daemon_debug_buf);
 
672
 
 
673
        for (i = 0; i < len; i++) {
 
674
                dump_buf[dump_point++] = daemon_debug_buf[i];
 
675
 
 
676
                if (dump_point == DUMP_SIZE) {
 
677
                        dump_point = 0;
 
678
                        dump_wrap = 1;
 
679
                }
 
680
        }
 
681
}
 
682
 
 
683
int our_nodeid = 2;
 
684
int main(int argc, char *argv[])
 
685
{
 
686
        int rc;
 
687
        char *buf;
 
688
        size_t buflen;
 
689
        struct ckpt_handle *h;
 
690
 
 
691
        rc = setup_ckpt();
 
692
        if (rc)
 
693
                goto out;
 
694
 
 
695
        rc = ckpt_open_global(1);
 
696
        if (rc)
 
697
                goto out_exit;
 
698
        rc = ckpt_global_store("version", "1.0", strlen("1.0"));
 
699
        if (!rc) {
 
700
                rc = ckpt_global_get("foo", &buf, &buflen);
 
701
                if (rc != -ENOENT) {
 
702
                        log_error("read should not have found anything");
 
703
                        rc = -EIO;
 
704
                } else
 
705
                        rc = 0;
 
706
        }
 
707
        ckpt_close_global();
 
708
        if (rc)
 
709
                goto out_exit;
 
710
 
 
711
        rc = ckpt_open_this_node(&h);
 
712
        if (rc)
 
713
                goto out_exit;
 
714
        rc = ckpt_section_store(h, "foo", "bar", strlen("bar"));
 
715
        if (!rc) {
 
716
                rc = ckpt_section_get(h, "foo", &buf, &buflen);
 
717
                if (!rc) {
 
718
                        if ((buflen != strlen("bar")) ||
 
719
                            memcmp(buf, "bar", strlen("bar"))) {
 
720
                                log_error("read returned bad value");
 
721
                                rc = -EIO;
 
722
                        }
 
723
                        free(buf);
 
724
                }
 
725
        }
 
726
        ckpt_close(h);
 
727
        if (rc)
 
728
                goto out_exit;
 
729
 
 
730
        rc = ckpt_open_node(4, &h);
 
731
        if (rc)
 
732
                goto out_exit;
 
733
        ckpt_close(h);
 
734
 
 
735
out_exit:
 
736
        exit_ckpt();
 
737
 
 
738
out:
 
739
        return rc;
 
740
}
 
741
#endif  /* DEBUG_EXE */