Uses a lock file instead than a pid file.

It's more appropriate for a not daemon.
This commit is contained in:
Andrea Mazzoleni 2013-06-18 21:06:31 +02:00
parent bc2a837953
commit fceaa8a4cf
7 changed files with 46 additions and 70 deletions

View file

@ -9,9 +9,9 @@ SnapRAID HISTORY
* Added RAID5/RAID6 mmx and sse2 implementations with unrolling by 4.
They are a little faster than the previous unroll by 2.
* Added a hash seed to make harder intentional collision attacks.
* Added a pid file to avoid multiple running instances on the same array.
The file is named as the first content file adding the .pid extension.
There is also the undocumented --test-skip-pid to avoid to check it.
* Added a lock file to avoid multiple running instances on the same array.
The file is named as parity file adding the .lock extension.
There is also the undocumented --test-skip-lock to avoid to check it.
3.1 2013/5
==========

View file

@ -125,10 +125,10 @@
#endif
/**
* Enable PID file support.
* Enable lock file support.
*/
#if HAVE_FLOCK && HAVE_FTRUNCATE
#define HAVE_PIDFILE 1
#define HAVE_LOCKFILE 1
#endif
/**

View file

@ -84,7 +84,7 @@ void usage(void)
#define OPT_TEST_SKIP_SEQUENTIAL 263
#define OPT_TEST_FORCE_MURMUR3 264
#define OPT_TEST_FORCE_SPOOKY2 265
#define OPT_TEST_SKIP_PID 266
#define OPT_TEST_SKIP_LOCK 266
#if HAVE_GETOPT_LONG
struct option long_options[] = {
@ -139,8 +139,8 @@ struct option long_options[] = {
/* Force Spooky2 hash */
{ "test-force-spooky2", 0, 0, OPT_TEST_FORCE_SPOOKY2 },
/* Skip the use of pid file */
{ "test-skip-pid", 0, 0, OPT_TEST_SKIP_PID },
/* Skip the use of lock file */
{ "test-skip-lock", 0, 0, OPT_TEST_SKIP_LOCK },
{ 0, 0, 0, 0 }
};
@ -188,7 +188,7 @@ int main(int argc, char* argv[])
int test_skip_device;
int test_force_murmur3;
int test_force_spooky2;
int test_skip_pid;
int test_skip_lock;
const char* conf;
struct snapraid_state state;
int operation;
@ -202,7 +202,7 @@ int main(int argc, char* argv[])
const char* command;
const char* import;
const char* log;
int pid;
int lock;
os_init();
@ -225,7 +225,7 @@ int main(int argc, char* argv[])
test_skip_device = 0;
test_force_murmur3 = 0;
test_force_spooky2 = 0;
test_skip_pid = 0;
test_skip_lock = 0;
blockstart = 0;
blockcount = 0;
tommy_list_init(&filterlist_file);
@ -233,7 +233,7 @@ int main(int argc, char* argv[])
filter_missing = 0;
import = 0;
log = 0;
pid = 0;
lock = 0;
opterr = 0;
while ((c =
@ -354,8 +354,8 @@ int main(int argc, char* argv[])
case OPT_TEST_FORCE_SPOOKY2 :
test_force_spooky2 = 1;
break;
case OPT_TEST_SKIP_PID :
test_skip_pid = 1;
case OPT_TEST_SKIP_LOCK :
test_skip_lock = 1;
break;
default:
fprintf(stderr, "Unknown option '%c'\n", (char)c);
@ -445,15 +445,15 @@ int main(int argc, char* argv[])
/* read the configuration file */
state_config(&state, conf, command, verbose, gui, force_zero, force_empty, force_uuid, find_by_name, test_expect_unrecoverable, test_expect_recoverable, test_skip_sign, test_skip_fallocate, test_skip_sequential, test_skip_device, test_force_murmur3, test_force_spooky2);
#if HAVE_PIDFILE
/* create the pid file */
if (!test_skip_pid) {
pid = pid_lock(state.pidfile);
if (pid == -1) {
#if HAVE_LOCKFILE
/* create the lock file */
if (!test_skip_lock) {
lock = lock_lock(state.lockfile);
if (lock == -1) {
if (errno != EWOULDBLOCK) {
fprintf(stderr, "Error creating the pid file '%s'. %s.\n", state.pidfile, strerror(errno));
fprintf(stderr, "Error creating the lock file '%s'. %s.\n", state.lockfile, strerror(errno));
} else {
fprintf(stderr, "The pid file '%s' is already locked!\n", state.pidfile);
fprintf(stderr, "The lock file '%s' is already locked!\n", state.lockfile);
fprintf(stderr, "SnapRAID is already in use!\n");
}
exit(EXIT_FAILURE);
@ -580,10 +580,10 @@ int main(int argc, char* argv[])
}
}
#if HAVE_PIDFILE
if (!test_skip_pid) {
if (pid_unlock(pid, state.pidfile) == -1) {
fprintf(stderr, "Error closing the pid file '%s'. %s.\n", state.pidfile, strerror(errno));
#if HAVE_LOCKFILE
if (!test_skip_lock) {
if (lock_unlock(lock) == -1) {
fprintf(stderr, "Error closing the lock file '%s'. %s.\n", state.lockfile, strerror(errno));
exit(EXIT_FAILURE);
}
}

12
state.c
View file

@ -45,7 +45,7 @@ void state_init(struct snapraid_state* state)
state->qarity_device = 0;
state->pool[0] = 0;
state->pool_device = 0;
state->pidfile[0] = 0;
state->lockfile[0] = 0;
state->level = 1; /* default is the lowest protection */
tommy_list_init(&state->disklist);
@ -359,6 +359,10 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
}
state->parity_device = st.st_dev;
/* set lock file */
pathcpy(state->lockfile, sizeof(state->lockfile), state->parity);
pathcat(state->lockfile, sizeof(state->lockfile), ".lock");
} else if (strcmp(tag, "q-parity") == 0) {
char device[PATH_MAX];
char* slash;
@ -463,12 +467,6 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
content = content_alloc(buffer, st.st_dev);
tommy_list_insert_tail(&state->contentlist, &content->node, content);
/* if not set pid file, set it as the first content file */
if (!state->pidfile[0]) {
pathcpy(state->pidfile, sizeof(state->pidfile), buffer);
pathcat(state->pidfile, sizeof(state->pidfile), ".pid");
}
} else if (strcmp(tag, "disk") == 0) {
char dir[PATH_MAX];
char device[PATH_MAX];

View file

@ -50,7 +50,7 @@ struct snapraid_state {
uint64_t qarity_device; /**< Device identifier of the qarity. */
char pool[PATH_MAX]; /**< Path of the pool tree. */
uint64_t pool_device; /**< Device identifier of the pool. */
char pidfile[PATH_MAX]; /**< Path of the pid file to use. */
char lockfile[PATH_MAX]; /**< Path of the lock file to use. */
unsigned char hashseed[HASH_SIZE]; /**< Hash seed. */
unsigned level; /**< Number of parity levels. 1 for RAID5, 2 for RAID6. */
unsigned hash; /**< Hash kind used. */

40
util.c
View file

@ -867,16 +867,14 @@ void randomize(void* void_ptr, unsigned size)
}
/****************************************************************************/
/* pid */
/* lock */
#if HAVE_PIDFILE
int pid_lock(const char* file)
#if HAVE_LOCKFILE
int lock_lock(const char* file)
{
char buffer[64];
ssize_t len;
int f;
f = open(file, O_CREAT | O_WRONLY, 0600);
f = open(file, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (f == -1) {
return -1;
}
@ -887,38 +885,18 @@ int pid_lock(const char* file)
return -1;
}
/* write the pid into the file */
snprintf(buffer, sizeof(buffer), "%ld", (long)getpid());
len = strlen(buffer);
if (write(f, buffer, len) != len) {
close(f);
return -1;
}
if (ftruncate(f, len) == -1) {
close(f);
return -1;
}
return 0;
}
#endif
#if HAVE_PIDFILE
int pid_unlock(int f, const char* file)
#if HAVE_LOCKFILE
int lock_unlock(int f)
{
/*
* Remove file before closing it.
* This opens a race course in case another process already opened it.
* but has not yet failed the next flock() call.
* But removing it after the close, opens a similar race course.
* It seems that deleting a pid file is something just impossible to do it right.
* Intentionally don't remove file the lock file.
* Removing it just introduces race course with other process
* that could have already opened it.
*/
if (remove(file) == -1) {
close(f);
return -1;
}
if (close(f) == -1) {
return -1;

12
util.h
View file

@ -487,19 +487,19 @@ static inline oathash_t oathashm(oathash_t hash, const unsigned char* value, uns
}
/****************************************************************************/
/* pid */
/* lock */
/**
* Creates and locks the pid file.
* Returns -1 on error, otherwise it's the file handle to pass to pid_unlock().
* Creates and locks the lock file.
* Returns -1 on error, otherwise it's the file handle to pass to lock_unlock().
*/
int pid_lock(const char* file);
int lock_lock(const char* file);
/**
* Unlocks the pid file.
* Unlocks the lock file.
* Returns -1 on error.
*/
int pid_unlock(int f, const char* file);
int lock_unlock(int f);
#endif