diff --git a/tools/sfex_daemon.c b/tools/sfex_daemon.c index ee0c3147c..9a761b8ab 100644 --- a/tools/sfex_daemon.c +++ b/tools/sfex_daemon.c @@ -1,345 +1,345 @@ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sfex.h" #include "sfex_lib.h" #if HAVE_GLUE_CONFIG_H #include /* for HA_LOG_FACILITY */ #endif static int sysrq_fd; static int lock_index = 1; /* default 1st lock */ static time_t collision_timeout = 1; /* default 1 sec */ static time_t lock_timeout = 60; /* default 60 sec */ time_t unlock_timeout = 60; static time_t monitor_interval = 10; static sfex_controldata cdata; static sfex_lockdata ldata; static sfex_lockdata ldata_new; static const char *device; const char *progname; char *nodename; static const char *rsc_id = "sfex"; static void usage(FILE *dist) { fprintf(dist, "usage: %s [-i ] [-c ] [-t ] \n", progname); } static void acquire_lock(void) { if (read_lockdata(&cdata, &ldata, lock_index) == -1) { cl_log(LOG_ERR, "read_lockdata failed in acquire_lock\n"); exit(EXIT_FAILURE); } if ((ldata.status == SFEX_STATUS_LOCK) && (strncmp(nodename, (const char*)(ldata.nodename), sizeof(ldata.nodename)))) { unsigned int t = lock_timeout; while (t > 0) t = sleep(t); read_lockdata(&cdata, &ldata_new, lock_index); if (ldata.count != ldata_new.count) { cl_log(LOG_ERR, "can\'t acquire lock: the lock's already hold by some other node.\n"); exit(2); } } /* The lock acquisition is possible because it was not updated. */ ldata.status = SFEX_STATUS_LOCK; ldata.count = SFEX_NEXT_COUNT(ldata.count); - strncpy((char*)(ldata.nodename), nodename, sizeof(ldata.nodename)); + strncpy((char*)(ldata.nodename), nodename, sizeof(ldata.nodename) - 1); if (write_lockdata(&cdata, &ldata, lock_index) == -1) { cl_log(LOG_ERR, "write_lockdata failed\n"); exit(EXIT_FAILURE); } /* detect the collision of lock */ /* The collision occurs when two or more nodes do the reservation processing of the lock at the same time. It waits for collision_timeout seconds to detect this,and whether the superscription of lock data by another node is done is checked. If the superscription was done by another node, the lock acquisition with the own node is given up. */ { unsigned int t = collision_timeout; while (t > 0) t = sleep(t); if (read_lockdata(&cdata, &ldata_new, lock_index) == -1) { cl_log(LOG_ERR, "read_lockdata failed in collision detection\n"); } if (strncmp((char*)(ldata.nodename), (const char*)(ldata_new.nodename), sizeof(ldata.nodename))) { cl_log(LOG_ERR, "can\'t acquire lock: collision detected in the air.\n"); exit(2); } } /* extension of lock */ /* Validly time of the lock is extended. It is because of spending at the collision_timeout seconds to detect the collision. */ ldata.count = SFEX_NEXT_COUNT(ldata.count); if (write_lockdata(&cdata, &ldata, lock_index) == -1) { cl_log(LOG_ERR, "write_lockdata failed in extension of lock\n"); exit(EXIT_FAILURE); } cl_log(LOG_INFO, "lock acquired\n"); } static void error_todo (void) { if (fork() == 0) { cl_log(LOG_INFO, "Execute \"crm_resource -F -r %s --node %s\" command\n", rsc_id, nodename); execl("/usr/sbin/crm_resource", "crm_resource", "-F", "-r", rsc_id, "--node", nodename, NULL); } else { exit(EXIT_FAILURE); } } static void failure_todo(void) { #ifdef SFEX_TESTING exit(EXIT_FAILURE); #else /*execl("/usr/sbin/crm_resource", "crm_resource", "-F", "-r", rsc_id, "--node", nodename, NULL); */ int ret; cl_log(LOG_INFO, "Force reboot node %s\n", nodename); ret = write(sysrq_fd, "b\n", 2); if (ret == -1) { cl_log(LOG_ERR, "%s\n", strerror(errno)); } close(sysrq_fd); exit(EXIT_FAILURE); #endif } static void update_lock(void) { /* read lock data */ if (read_lockdata(&cdata, &ldata, lock_index) == -1) { cl_log(LOG_ERR, "read_lockdata failed in update_lock\n"); error_todo(); exit(EXIT_FAILURE); } /* check current lock status */ /* if own node is not locking, lock update is failed */ if (ldata.status != SFEX_STATUS_LOCK || strncmp((const char*)(ldata.nodename), nodename, sizeof(ldata.nodename))) { cl_log(LOG_ERR, "can't update lock.\n"); failure_todo(); exit(EXIT_FAILURE); } /* lock update */ ldata.count = SFEX_NEXT_COUNT(ldata.count); if (write_lockdata(&cdata, &ldata, lock_index) == -1) { cl_log(LOG_ERR, "write_lockdata failed in update_lock\n"); error_todo(); exit(EXIT_FAILURE); } } static void release_lock(void) { /* The only thing I care about in release_lock(), is to terminate the process */ /* read lock data */ if (read_lockdata(&cdata, &ldata, lock_index) == -1) { cl_log(LOG_ERR, "read_lockdata failed in release_lock\n"); exit(EXIT_FAILURE); } /* check current lock status */ /* if own node is not locking, we judge that lock has been released already */ if (ldata.status != SFEX_STATUS_LOCK || strncmp((const char*)(ldata.nodename), nodename, sizeof(ldata.nodename))) { cl_log(LOG_ERR, "lock was already released.\n"); exit(EXIT_FAILURE); } /* lock release */ ldata.status = SFEX_STATUS_UNLOCK; if (write_lockdata(&cdata, &ldata, lock_index) == -1) { /*FIXME: We are going to self-stop */ cl_log(LOG_ERR, "write_lockdata failed in release_lock\n"); exit(EXIT_FAILURE); } cl_log(LOG_INFO, "lock released\n"); } static void quit_handler(int signo, siginfo_t *info, void *context) { cl_log(LOG_INFO, "quit_handler called. now releasing lock\n"); release_lock(); cl_log(LOG_INFO, "Shutdown sfex_daemon with EXIT_SUCCESS\n"); exit(EXIT_SUCCESS); } int main(int argc, char *argv[]) { int ret; progname = get_progname(argv[0]); nodename = get_nodename(); cl_log_set_entity(progname); cl_log_set_facility(HA_LOG_FACILITY); cl_inherit_logging_environment(0); /* read command line option */ opterr = 0; while (1) { int c = getopt(argc, argv, "hi:c:t:m:n:r:"); if (c == -1) break; switch (c) { case 'h': /* help*/ usage(stdout); exit(EXIT_SUCCESS); case 'i': /* -i */ { unsigned long l = strtoul(optarg, NULL, 10); if (l < SFEX_MIN_NUMLOCKS || l > SFEX_MAX_NUMLOCKS) { cl_log(LOG_ERR, "index %s is out of range or invalid. it must be integer value between %lu and %lu.\n", optarg, (unsigned long)SFEX_MIN_NUMLOCKS, (unsigned long)SFEX_MAX_NUMLOCKS); exit(4); } lock_index = l; } break; case 'c': /* -c */ { unsigned long l = strtoul(optarg, NULL, 10); if (l < 1 || l > INT_MAX) { cl_log(LOG_ERR, "collision_timeout %s is out of range or invalid. it must be integer value between %lu and %lu.\n", optarg, (unsigned long)1, (unsigned long)INT_MAX); exit(4); } collision_timeout = l; } break; case 'm': /* -m */ { unsigned long l = strtoul(optarg, NULL, 10); if (l < 1 || l > INT_MAX) { cl_log(LOG_ERR, "monitor_interval %s is out of range or invalid. it must be integer value between %lu and %lu.\n", optarg, (unsigned long)1, (unsigned long)INT_MAX); exit(4); } monitor_interval = l; } break; case 't': /* -t */ { unsigned long l = strtoul(optarg, NULL, 10); if (l < 1 || l > INT_MAX) { cl_log(LOG_ERR, "lock_timeout %s is out of range or invalid. it must be integer value between %lu and %lu.\n", optarg, (unsigned long)1, (unsigned long)INT_MAX); exit(4); } lock_timeout = l; } break; case 'n': { free(nodename); if (strlen(optarg) > SFEX_MAX_NODENAME) { cl_log(LOG_ERR, "nodename %s is too long. must be less than %d byte.\n", optarg, (unsigned int)SFEX_MAX_NODENAME); exit(EXIT_FAILURE); } nodename = strdup(optarg); } break; case 'r': { rsc_id = strdup(optarg); } break; case '?': /* error */ usage(stderr); exit(4); } } /* check parameter except the option */ if (optind >= argc) { cl_log(LOG_ERR, "no device specified.\n"); usage(stderr); exit(EXIT_FAILURE); } else if (optind + 1 < argc) { cl_log(LOG_ERR, "too many arguments.\n"); usage(stderr); exit(EXIT_FAILURE); } device = argv[optind]; prepare_lock(device); #if !SFEX_TESTING sysrq_fd = open("/proc/sysrq-trigger", O_WRONLY); if (sysrq_fd == -1) { cl_log(LOG_ERR, "failed to open /proc/sysrq-trigger due to %s\n", strerror(errno)); exit(EXIT_FAILURE); } #endif ret = lock_index_check(&cdata, lock_index); if (ret == -1) exit(EXIT_FAILURE); { struct sigaction sig_act; sigemptyset (&sig_act.sa_mask); sig_act.sa_flags = SA_SIGINFO; sig_act.sa_sigaction = quit_handler; ret = sigaction(SIGTERM, &sig_act, NULL); if (ret == -1) { cl_log(LOG_ERR, "sigaction failed\n"); exit(EXIT_FAILURE); } } cl_log(LOG_INFO, "Starting SFeX Daemon...\n"); /* acquire lock first.*/ acquire_lock(); if (daemon(0, 1) != 0) { cl_perror("%s::%d: daemon() failed.", __FUNCTION__, __LINE__); release_lock(); exit(EXIT_FAILURE); } cl_make_realtime(-1, -1, 128, 128); cl_log(LOG_INFO, "SFeX Daemon started.\n"); while (1) { sleep (monitor_interval); update_lock(); } } diff --git a/tools/sfex_lib.c b/tools/sfex_lib.c index 47ce0d749..59d05486a 100644 --- a/tools/sfex_lib.c +++ b/tools/sfex_lib.c @@ -1,474 +1,474 @@ /*------------------------------------------------------------------------- * * Shared Disk File EXclusiveness Control Program(SF-EX) * * sfex_lib.c --- Libraries for other SF-EX modules. * * 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 * of the License, 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; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * Copyright (c) 2007 NIPPON TELEGRAPH AND TELEPHONE CORPORATION * * $Id$ * *-------------------------------------------------------------------------*/ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "sfex.h" #include "sfex_lib.h" static void *locked_mem; static int dev_fd; unsigned long sector_size = 0; int prepare_lock (const char *device) { int sec_tmp = 0; do { dev_fd = open (device, O_RDWR | O_DIRECT | O_SYNC); if (dev_fd == -1) { if (errno == EINTR || errno == EAGAIN) continue; cl_log(LOG_ERR, "can't open device %s: %s\n", device, strerror (errno)); exit (3); } break; } while (1); ioctl(dev_fd, BLKSSZGET, &sec_tmp); sector_size = (unsigned long)sec_tmp; if (sector_size == 0) { cl_log(LOG_ERR, "Get sector size failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (posix_memalign ((void **) (&locked_mem), SFEX_ODIRECT_ALIGNMENT, sector_size) != 0) { cl_log(LOG_ERR, "Failed to allocate aligned memory\n"); exit (3); } memset (locked_mem, 0, sector_size); return 0; } /* * get_progname --- a program name * * We get program name from directory path. It does not include delimiter * characters. Return value is pointer that point string of program name. * We assume delimiter is '/'. */ const char * get_progname (const char *argv0) { char *p; p = strrchr (argv0, '/'); if (p) return p + 1; else return argv0; } /* * get_nodename --- get a node name(hostname) * * We get a node name by using uname(2) and return pointer of it. * The error checks are done in this function. The caller does not have * to check return value. */ char * get_nodename (void) { struct utsname u; char *n; if (uname (&u)) { cl_log(LOG_ERR, "%s\n", strerror (errno)); exit (3); } if (strlen (u.nodename) > SFEX_MAX_NODENAME) { cl_log(LOG_ERR, "nodename %s is too long. must be less than %lu byte.\n", u.nodename, (unsigned long)SFEX_MAX_NODENAME); exit (3); } n = strdup (&u.nodename[0]); if (!n) { cl_log(LOG_ERR, "%s\n", strerror (errno)); exit (3); } return n; } /* * init_controldata --- initialize control data * * We initialize each member of sfex_controldata structure. */ void init_controldata (sfex_controldata * cdata, size_t blocksize, int numlocks) { memcpy (cdata->magic, SFEX_MAGIC, sizeof (cdata->magic)); cdata->version = SFEX_VERSION; cdata->revision = SFEX_REVISION; cdata->blocksize = blocksize; cdata->numlocks = numlocks; } /* * init_lockdata --- initialize lock data * * We initialize each member of sfex_lockdata structure. */ void init_lockdata (sfex_lockdata * ldata) { ldata->status = SFEX_STATUS_UNLOCK; ldata->count = 0; ldata->nodename[0] = 0; } /* * write_controldata --- write control data into file * * We write sfex_controldata struct into file. We open a file with * synchronization mode and write out control data. * * cdata --- pointer of control data * * device --- name of target file */ void write_controldata (const sfex_controldata * cdata) { sfex_controldata_ondisk *block; int fd; block = (sfex_controldata_ondisk *) (locked_mem); /* We write control data into the buffer with given format. */ /* We write the offset value of each field of the control data directly. * Because a point using this value is limited to two places, we do not * use macro. If you change the following offset values, you must change * values in the read_controldata() function. */ memset (block, 0, cdata->blocksize); memcpy (block->magic, cdata->magic, sizeof (block->magic)); snprintf ((char *) (block->version), sizeof (block->version), "%d", cdata->version); snprintf ((char *) (block->revision), sizeof (block->revision), "%d", cdata->revision); snprintf ((char *) (block->blocksize), sizeof (block->blocksize), "%u", (unsigned)cdata->blocksize); snprintf ((char *) (block->numlocks), sizeof (block->numlocks), "%d", cdata->numlocks); fd = dev_fd; if (lseek (fd, 0, SEEK_SET) == -1) { cl_log(LOG_ERR, "can't seek file pointer: %s\n", strerror (errno)); exit (3); } /* write buffer into a file */ do { ssize_t s = write (fd, block, cdata->blocksize); if (s == -1) { if (errno == EINTR || errno == EAGAIN) continue; cl_log(LOG_ERR, "can't write meta-data: %s\n", strerror (errno)); exit (3); } else break; } while (1); } /* * write_lockdata --- write lock data into file * * We write sfex_lockdata into file and seek file pointer to the given * position of lock data. * * cdata --- pointer for control data * * ldata --- pointer for lock data * * device --- file name for write * * index --- index number for lock data. 1 origine. */ int write_lockdata (const sfex_controldata * cdata, const sfex_lockdata * ldata, int index) { sfex_lockdata_ondisk *block; int fd; block = (sfex_lockdata_ondisk *) locked_mem; /* We write lock data into buffer with given format */ /* We write the offset value of each field of the control data directly. * Because a point using this value is limited to two places, we do not * use macro. If you chage the following offset values, you must change * values in the read_lockdata() function. */ memset (block, 0, cdata->blocksize); block->status = ldata->status; snprintf ((char *) (block->count), sizeof (block->count), "%d", ldata->count); snprintf ((char *) (block->nodename), sizeof (block->nodename), "%s", ldata->nodename); fd = dev_fd; /* seek a file pointer to given position */ if (lseek (fd, cdata->blocksize * index, SEEK_SET) == -1) { cl_log(LOG_ERR, "can't seek file pointer: %s\n", strerror (errno)); return -1; } /* write buffer into file */ do { ssize_t s = write (fd, block, cdata->blocksize); if (s == -1) { if (errno == EINTR || errno == EAGAIN) continue; cl_log(LOG_ERR, "can't write meta-data: %s\n", strerror (errno)); return -1; } else if (s != cdata->blocksize) { /* if writing atomically failed, this process is error */ cl_log(LOG_ERR, "can't write meta-data atomically.\n"); return -1; } break; } while (1); return 0; } /* * read_controldata --- read control data from file * * read sfex_controldata structure from file. * * cdata --- pointer for control data * * device --- file name for reading */ int read_controldata (sfex_controldata * cdata) { sfex_controldata_ondisk *block; block = (sfex_controldata_ondisk *) (locked_mem); if (lseek (dev_fd, 0, SEEK_SET) == -1) { cl_log(LOG_ERR, "can't seek file pointer: %s\n", strerror (errno)); return -1; } /* read data from file */ do { ssize_t s = read (dev_fd, block, sector_size); if (s == -1) { if (errno == EINTR || errno == EAGAIN) continue; cl_log(LOG_ERR, "can't read controldata meta-data: %s\n", strerror (errno)); return -1; } else break; } while (1); /* read control data from buffer */ /* 1. check the magic number. 2. check null terminator of each field 3. check the version number. 4. Unmuch of revision number is allowed */ /* We write the offset value of each field of the control data directly. * Because a point using this value is limited to two places, we do not * use macro. If you chage the following offset values, you must change * values in the write_controldata() function. */ memcpy (cdata->magic, block->magic, 4); if (memcmp (cdata->magic, SFEX_MAGIC, sizeof (cdata->magic))) { cl_log(LOG_ERR, "magic number mismatched. %c%c%c%c <-> %s\n", block->magic[0], block->magic[1], block->magic[2], block->magic[3], SFEX_MAGIC); return -1; } if (block->version[sizeof (block->version)-1] || block->revision[sizeof (block->revision)-1] || block->blocksize[sizeof (block->blocksize)-1] || block->numlocks[sizeof (block->numlocks)-1]) { cl_log(LOG_ERR, "control data format error.\n"); return -1; } cdata->version = atoi ((char *) (block->version)); if (cdata->version != SFEX_VERSION) { cl_log(LOG_ERR, "version number mismatched. program is %d, data is %d.\n", SFEX_VERSION, cdata->version); return -1; } cdata->revision = atoi ((char *) (block->revision)); cdata->blocksize = atoi ((char *) (block->blocksize)); cdata->numlocks = atoi ((char *) (block->numlocks)); return 0; } /* * read_lockdata --- read lock data from file * * read sfex_lockdata from file and seek file pointer to head position of the * file. * * cdata --- pointer for control data * * ldata --- pointer for lock data. Read lock data are stored into this * pointed area. * * device --- file name of source file * * index --- index number. 1 origin. */ int read_lockdata (const sfex_controldata * cdata, sfex_lockdata * ldata, int index) { sfex_lockdata_ondisk *block; int fd; block = (sfex_lockdata_ondisk *) (locked_mem); fd = dev_fd; /* seek a file pointer to given position */ if (lseek (fd, cdata->blocksize * index, SEEK_SET) == -1) { cl_log(LOG_ERR, "can't seek file pointer: %s\n", strerror (errno)); return -1; } /* read from file */ do { ssize_t s = read (fd, block, cdata->blocksize); if (s == -1) { if (errno == EINTR || errno == EAGAIN) continue; cl_log(LOG_ERR, "can't read lockdata meta-data: %s\n", strerror (errno)); return -1; } else if (s != cdata->blocksize) { cl_log(LOG_ERR, "can't read meta-data atomically.\n"); return -1; } break; } while (1); /* read control data form buffer */ /* 1. check null terminator of each field 2. check the status */ /* We write the offset value of each field of the control data directly. * Because a point using this value is limited to two places, we do not * use macro. If you chage the following offset values, you must change * values in the write_lockdata() function. */ if (block->count[sizeof(block->count)-1] || block->nodename[sizeof(block->nodename)-1]) { cl_log(LOG_ERR, "lock data format error.\n"); return -1; } ldata->status = block->status; if (ldata->status != SFEX_STATUS_UNLOCK && ldata->status != SFEX_STATUS_LOCK) { cl_log(LOG_ERR, "lock data format error.\n"); return -1; } ldata->count = atoi ((char *) (block->count)); - strncpy ((char *) (ldata->nodename), (const char *) (block->nodename), sizeof(block->nodename)); + strncpy ((char *) (ldata->nodename), (const char *) (block->nodename), sizeof(block->nodename) - 0); #ifdef SFEX_DEBUG cl_log(LOG_INFO, "status: %c\n", ldata->status); cl_log(LOG_INFO, "count: %d\n", ldata->count); cl_log(LOG_INFO, "nodename: %s\n", ldata->nodename); #endif return 0; } /* * lock_index_check --- check the value of index * * The lock_index_check function checks whether the value of index exceeds * the number of lock data on the shared disk. * * cdata --- pointer for control data * * index --- index number */ int lock_index_check(sfex_controldata * cdata, int index) { if (read_controldata(cdata) == -1) { cl_log(LOG_ERR, "%s\n", "read_controldata failed in lock_index_check"); return -1; } #ifdef SFEX_DEBUG cl_log(LOG_INFO, "version: %d\n", cdata->version); cl_log(LOG_INFO, "revision: %d\n", cdata->revision); cl_log(LOG_INFO, "blocksize: %d\n", cdata->blocksize); cl_log(LOG_INFO, "numlocks: %d\n", cdata->numlocks); #endif if (index > cdata->numlocks) { cl_log(LOG_ERR, "index %d is too large. %d locks are stored.\n", index, cdata->numlocks); return -1; } if (cdata->blocksize != sector_size) { cl_log(LOG_ERR, "sector_size is not the same as the blocksize.\n"); return -1; } return 0; }