/* Copyright Red Hat, Inc. 2006 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file * Distributed VM states using saCkpt interface */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xvm.h" typedef struct { uint32_t ck_ready; int ck_timeout; SaCkptCheckpointHandleT ck_checkpoint; SaCkptHandleT ck_handle; char *ck_name; } ckpt_handle; #define READY_MAGIC 0x13fd237c #define VALIDATE(h) \ do { \ if (!h || h->ck_ready != READY_MAGIC) { \ errno = EINVAL; \ return -1; \ } \ } while(0) int ais_to_posix(SaAisErrorT err); int ais_to_posix(SaAisErrorT err) { switch (err) { case SA_AIS_OK: return 0; case SA_AIS_ERR_LIBRARY: return ELIBBAD; case SA_AIS_ERR_VERSION: return EPROTONOSUPPORT; //XXX case SA_AIS_ERR_INIT: return EFAULT; //XXX case SA_AIS_ERR_TIMEOUT: return ETIMEDOUT; case SA_AIS_ERR_TRY_AGAIN: return EAGAIN; case SA_AIS_ERR_INVALID_PARAM: return EINVAL; case SA_AIS_ERR_NO_MEMORY: return ENOMEM; case SA_AIS_ERR_BAD_HANDLE: return EBADF; case SA_AIS_ERR_BUSY: return EBUSY; case SA_AIS_ERR_ACCESS: return EACCES; case SA_AIS_ERR_NOT_EXIST: return ENOENT; case SA_AIS_ERR_NAME_TOO_LONG: return ENAMETOOLONG; case SA_AIS_ERR_EXIST: return EEXIST; case SA_AIS_ERR_NO_SPACE: return ENOSPC; case SA_AIS_ERR_INTERRUPT: return EINTR; case SA_AIS_ERR_NAME_NOT_FOUND: return ENOENT; case SA_AIS_ERR_NO_RESOURCES: return ENOMEM; //XXX case SA_AIS_ERR_NOT_SUPPORTED: return ENOSYS; case SA_AIS_ERR_BAD_OPERATION: return EINVAL; //XXX case SA_AIS_ERR_FAILED_OPERATION: return EIO; //XXX case SA_AIS_ERR_MESSAGE_ERROR: return EIO; // XXX case SA_AIS_ERR_QUEUE_FULL: return ENOBUFS; case SA_AIS_ERR_QUEUE_NOT_AVAILABLE: return ENOENT; case SA_AIS_ERR_BAD_FLAGS: return EINVAL; case SA_AIS_ERR_TOO_BIG: return E2BIG; case SA_AIS_ERR_NO_SECTIONS: return ENOENT; // XXX /*case SA_AIS_ERR_SECURITY: return EPERM;*/ default: return EINVAL; /* XXX */ } return -1; } static int ckpt_open(ckpt_handle *h, const char *ckpt_name, int maxsize, int maxsec, int maxsecsize, int timeout) { SaCkptCheckpointCreationAttributesT attrs; SaCkptCheckpointOpenFlagsT flags; SaNameT cpname; #if 0 SaCkptCheckpointDescriptorT status; #endif SaAisErrorT err = SA_AIS_OK; VALIDATE(h); flags = SA_CKPT_CHECKPOINT_READ | SA_CKPT_CHECKPOINT_WRITE; snprintf((char *)cpname.value, SA_MAX_NAME_LENGTH-1, "%s", ckpt_name); cpname.length = strlen(ckpt_name); h->ck_timeout = timeout; err = saCkptCheckpointOpen(h->ck_handle, &cpname, NULL, flags, timeout, &h->ck_checkpoint); if (err == SA_AIS_OK) { #if 0 saCkptCheckpointStatusGet(h->ck_handle, &status); printf("Checkpoint Size = %d bytes\n", (int) status.checkpointCreationAttributes.checkpointSize); printf("Flags = "); if (status.checkpointCreationAttributes.creationFlags & SA_CKPT_WR_ALL_REPLICAS) { printf("%s ", "SA_CKPT_WR_ALL_REPLICAS"); } if (status.checkpointCreationAttributes.creationFlags & SA_CKPT_WR_ACTIVE_REPLICA) { printf("%s ", "SA_CKPT_WR_ACTIVE_REPLICA"); } if (status.checkpointCreationAttributes.creationFlags & SA_CKPT_WR_ACTIVE_REPLICA_WEAK) { printf("%s ", "SA_CKPT_WR_ACTIVE_REPLICA_WEAK"); } if (status.checkpointCreationAttributes.creationFlags & SA_CKPT_CHECKPOINT_COLLOCATED) { printf("%s ", "SA_CKPT_CHECKPOINT_COLLOCATED"); } printf("\nMax sections = %d\n", (int)status.checkpointCreationAttributes.maxSections); printf("Max section size = %d\n", (int)status.checkpointCreationAttributes.maxSectionSize); printf("Max section ID size = %d\n", (int)status.checkpointCreationAttributes.maxSectionIdSize); printf("Section count = %d\n", status.numberOfSections); printf("\n"); #endif goto good; } attrs.creationFlags = SA_CKPT_WR_ALL_REPLICAS; attrs.checkpointSize = (SaSizeT)maxsize; attrs.retentionDuration = SA_TIME_ONE_MINUTE; attrs.maxSections = maxsec; attrs.maxSectionSize = (SaSizeT)maxsecsize; attrs.maxSectionIdSize = (SaSizeT)MAX_DOMAINNAME_LENGTH; flags = SA_CKPT_CHECKPOINT_READ | SA_CKPT_CHECKPOINT_WRITE | SA_CKPT_CHECKPOINT_CREATE; err = saCkptCheckpointOpen(h->ck_handle, &cpname, &attrs, flags, timeout, &h->ck_checkpoint); if (err == SA_AIS_OK) goto good; /* No checkpoint */ errno = ais_to_posix(err); return (errno == 0 ? 0 : -1); good: printf("Opened ckpt %s\n", ckpt_name); h->ck_name = strdup(ckpt_name); errno = ais_to_posix(err); return (errno == 0 ? 0 : -1); } void * ckpt_init(char *ckpt_name, int maxlen, int maxsec, int maxseclen, int timeout) { ckpt_handle *h; SaAisErrorT err; SaVersionT ver; if (!ckpt_name || !strlen(ckpt_name)) { errno = EINVAL; return NULL; } h = malloc(sizeof(*h)); if (!h) return NULL; memset(h, 0, sizeof(*h)); ver.releaseCode = 'B'; ver.majorVersion = 1; ver.minorVersion = 1; err = saCkptInitialize(&h->ck_handle, NULL, &ver); if (err != SA_AIS_OK) { free(h); return NULL; } else { h->ck_ready = READY_MAGIC; } if (ckpt_open(h, ckpt_name, maxlen, maxsec, maxseclen, timeout) < 0) { saCkptCheckpointClose(h->ck_checkpoint); if (h->ck_name) free(h->ck_name); free(h); return NULL; } return (void *)h; } int ckpt_write(void *hp, const char *secid, void *buf, size_t maxlen) { ckpt_handle *h = (ckpt_handle *)hp; SaCkptIOVectorElementT iov = {SA_CKPT_DEFAULT_SECTION_ID, NULL, 0, 0, 0}; SaAisErrorT err; SaCkptSectionCreationAttributesT attrs; VALIDATE(h); /* Set section ID here */ iov.sectionId.id = (uint8_t *)secid; iov.sectionId.idLen = strlen(secid); iov.dataBuffer = buf; iov.dataSize = (SaSizeT)maxlen; iov.dataOffset = 0; iov.readSize = 0; err = saCkptCheckpointWrite(h->ck_checkpoint, &iov, 1, NULL); if (err == SA_AIS_ERR_NOT_EXIST) { attrs.sectionId = &iov.sectionId; attrs.expirationTime = SA_TIME_END; err = saCkptSectionCreate(h->ck_checkpoint, &attrs, buf, maxlen); } if (err == SA_AIS_OK) saCkptCheckpointSynchronize(h->ck_checkpoint, h->ck_timeout); errno = ais_to_posix(err); if (errno) return -1; return maxlen; /* XXX */ } int ckpt_read(void *hp, const char *secid, void *buf, size_t maxlen) { ckpt_handle *h = (ckpt_handle *)hp; SaCkptIOVectorElementT iov = {SA_CKPT_DEFAULT_SECTION_ID, NULL, 0, 0, 0}; SaAisErrorT err; VALIDATE(h); //printf("reading ckpt %s\n", keyid); iov.sectionId.id = (uint8_t *)secid; iov.sectionId.idLen = strlen(secid); iov.dataBuffer = buf; iov.dataSize = (SaSizeT)maxlen; iov.dataOffset = 0; iov.readSize = 0; err = saCkptCheckpointRead(h->ck_checkpoint, &iov, 1, NULL); errno = ais_to_posix(err); if (errno) return -1; return iov.readSize; /* XXX */ } int ckpt_erase(void *hp, const char *secid) { ckpt_handle *h = (ckpt_handle *)hp; SaAisErrorT err; SaCkptSectionIdT sectionId; VALIDATE(h); sectionId.id = (uint8_t *)secid; sectionId.idLen = strlen(secid); err = saCkptSectionDelete(h->ck_checkpoint, §ionId); if (err == SA_AIS_OK) saCkptCheckpointSynchronize(h->ck_checkpoint, h->ck_timeout); errno = ais_to_posix(err); if (errno) return -1; return 0; } int ckpt_finish(void *hp) { ckpt_handle *h = (ckpt_handle *)hp; int ret = 0; SaAisErrorT err; saCkptCheckpointClose(h->ck_checkpoint); err = saCkptFinalize(h->ck_handle); if (err != SA_AIS_OK) ret = -1; else h->ck_ready = 0; if (h->ck_name) free(h->ck_name); if (ret != 0) errno = ais_to_posix(err); return ret; } #ifdef STANDALONE void usage(int ret) { printf("usage: ckpt [-c ckpt_name] <-r key|-w key -d data>\n"); exit(ret); } int main(int argc, char **argv) { char *ckptname = "ckpt_test"; char *sec = "default"; char *val; void *h; char buf[64]; int ret; int op = 0; while((ret = getopt(argc, argv, "c:w:r:d:j?")) != EOF) { switch(ret) { case 'c': ckptname = optarg; break; case 'w': op = 'w'; sec = optarg; break; case 'r': op = 'r'; sec = optarg; break; case 'd': val = optarg; break; case '?': case 'h': usage(0); default: usage(1); } } if (!op) { usage(1); } if (!sec) { usage(1); } h = ckpt_init(ckptname, 262144, 4096, 64, 10); if (!h) { perror("ckpt_init"); return -1; } if (op == 'w') { if (ckpt_write(h, sec, val, strlen(val)+1) < 0) { perror("ckpt_write"); return 1; } } else if (op == 'r') { ret = ckpt_read(h, sec, buf, sizeof(buf)); if (ret < 0) { perror("ckpt_read"); return 1; } printf("%d bytes\nDATA for '%s':\n%s\n", ret, sec, buf); } ckpt_finish(h); return 0; } #endif