posix: add a simple health-checker

Goal of this health-checker is to detect fatal issues of the underlying
storage that is used for exporting a brick. The current implementation
requires the filesystem to detect the storage error, after which it will
notify the parent xlators and exit the glusterfsd (brick) process to
prevent further troubles.

The interval the health-check runs can be configured per volume with the
storage.health-check-interval option. The default interval is 30
seconds.

It is not trivial to write an automated test-case with the current
prove-framework. These are the manual steps that can be done to verify
the functionality:

- setup a Logical Volume (/dev/bz970960/xfs) and format is as XFS for
  brick usage

- create a volume with the one brick

    # gluster volume create failing_xfs glufs1:/bricks/failing_xfs/data
    # gluster volume start failing_xfs

- mount the volume and verify the functionality

- make the storage fail (use device-mapper, or pull disks)

    # dmsetup table
    ..
    bz970960-xfs: 0 196608 linear 7:0 2048

    # echo 0  196608 error > dmsetup-error-target
    # dmsetup load bz970960-xfs dmsetup-error-target
    # dmsetup resume bz970960-xfs

    # dmsetup table
    ...
    bz970960-xfs: 0 196608 error

- notice the errors caught by syslog:

    Jun 24 11:31:49 vm130-32 kernel: XFS (dm-2): metadata I/O error: block 0x0 ("xfs_buf_iodone_callbacks") error 5 buf count 512
    Jun 24 11:31:49 vm130-32 kernel: XFS (dm-2): I/O Error Detected. Shutting down filesystem
    Jun 24 11:31:49 vm130-32 kernel: XFS (dm-2): Please umount the filesystem and rectify the problem(s)
    Jun 24 11:31:49 vm130-32 kernel: VFS:Filesystem freeze failed
    Jun 24 11:31:50 vm130-32 GlusterFS[1969]: [2013-06-24 10:31:50.500674] M [posix-helpers.c:1114:posix_health_check_thread_proc] 0-failing_xfs-posix: health-check failed, going down
    Jun 24 11:32:09 vm130-32 kernel: XFS (dm-2): xfs_log_force: error 5 returned.
    Jun 24 11:32:20 vm130-32 GlusterFS[1969]: [2013-06-24 10:32:20.508690] M [posix-helpers.c:1119:posix_health_check_thread_proc] 0-failing_xfs-posix: still alive! -> SIGTERM

- these errors are in the log of the brick as well:

    [2013-06-24 10:31:50.500607] W [posix-helpers.c:1102:posix_health_check_thread_proc] 0-failing_xfs-posix: stat() on /bricks/failing_xfs/data returned: Input/output error
    [2013-06-24 10:31:50.500674] M [posix-helpers.c:1114:posix_health_check_thread_proc] 0-failing_xfs-posix: health-check failed, going down
    [2013-06-24 10:32:20.508690] M [posix-helpers.c:1119:posix_health_check_thread_proc] 0-failing_xfs-posix: still alive! -> SIGTERM

- the glusterfsd process has exited correctly:

    # gluster volume status
    Status of volume: failing_xfs
    Gluster process						Port	Online	Pid
    ------------------------------------------------------------------------------
    Brick glufs1:/bricks/failing_xfs/data			N/A	N	N/A
    NFS Server on localhost					2049	Y	1897

Change-Id: Ic247fbefb97f7e861307a5998a9a7a3ecc80aa07
BUG: 971774
Signed-off-by: Niels de Vos <ndevos@redhat.com>
Reviewed-on: http://review.gluster.org/5176
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
This commit is contained in:
Niels de Vos 2013-06-24 14:05:58 +02:00 committed by Vijay Bellur
parent 37d2c255e4
commit 98f62a731c
5 changed files with 146 additions and 0 deletions

View File

@ -153,6 +153,8 @@ To tune volume options
server.grace-timeout Specifies the duration for the lock state to be maintained on the server after a network disconnection. 10 10 - 1800 secs
server.statedump-path Location of the state dump file. /tmp directory of the brick New directory path
storage.health-check-interval Number of seconds between health-checks done on the filesystem that is used for the brick(s). Defaults to 30 seconds, set to 0 to disable. /tmp directory of the brick New directory path
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
You can view the changed volume options using

View File

@ -1215,6 +1215,10 @@ struct volopt_map_entry glusterd_volopt_map[] = {
.voltype = "storage/posix",
.op_version = 2
},
{ .key = "storage.health-check-interval",
.voltype = "storage/posix",
.op_version = 3
},
{ .key = "config.memory-accounting",
.voltype = "configuration",
.option = "!config",

View File

@ -22,6 +22,7 @@
#include <pthread.h>
#include <ftw.h>
#include <sys/stat.h>
#include <signal.h>
#ifndef GF_BSD_HOST_OS
#include <alloca.h>
@ -1063,3 +1064,116 @@ posix_fd_ctx_get (fd_t *fd, xlator_t *this, struct posix_fd **pfd)
return ret;
}
static void *
posix_health_check_thread_proc (void *data)
{
xlator_t *this = NULL;
struct posix_private *priv = NULL;
uint32_t interval = 0;
int ret = -1;
struct stat sb = {0, };
this = data;
priv = this->private;
/* prevent races when the interval is updated */
interval = priv->health_check_interval;
if (interval == 0)
goto out;
gf_log (this->name, GF_LOG_DEBUG, "health-check thread started, "
"interval = %d seconds", interval);
while (1) {
/* aborting sleep() is a request to exit this thread, sleep()
* will normally not return when cancelled */
ret = sleep (interval);
if (ret > 0)
break;
/* prevent thread errors while doing the health-check(s) */
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
/* Do the health-check, it should be moved to its own function
* in case it gets more complex. */
ret = stat (priv->base_path, &sb);
if (ret < 0) {
gf_log (this->name, GF_LOG_WARNING,
"stat() on %s returned: %s", priv->base_path,
strerror (errno));
goto abort;
}
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
}
out:
gf_log (this->name, GF_LOG_DEBUG, "health-check thread exiting");
LOCK (&priv->lock);
{
priv->health_check_active = _gf_false;
}
UNLOCK (&priv->lock);
return NULL;
abort:
/* health-check failed */
gf_log (this->name, GF_LOG_EMERG, "health-check failed, going down");
xlator_notify (this->parents->xlator, GF_EVENT_CHILD_DOWN, this);
ret = sleep (30);
if (ret == 0) {
gf_log (this->name, GF_LOG_EMERG, "still alive! -> SIGTERM");
kill (getpid(), SIGTERM);
}
ret = sleep (30);
if (ret == 0) {
gf_log (this->name, GF_LOG_EMERG, "still alive! -> SIGKILL");
kill (getpid(), SIGKILL);
}
return NULL;
}
void
posix_spawn_health_check_thread (xlator_t *xl)
{
struct posix_private *priv = NULL;
int ret = -1;
priv = xl->private;
LOCK (&priv->lock);
{
/* cancel the running thread */
if (priv->health_check_active == _gf_true) {
pthread_cancel (priv->health_check);
priv->health_check_active = _gf_false;
}
/* prevent scheduling a check in a tight loop */
if (priv->health_check_interval == 0)
goto unlock;
ret = pthread_create (&priv->health_check, NULL,
posix_health_check_thread_proc, xl);
if (ret < 0) {
priv->health_check_interval = 0;
priv->health_check_active = _gf_false;
gf_log (xl->name, GF_LOG_ERROR,
"unable to setup health-check thread: %s",
strerror (errno));
goto unlock;
}
/* run the thread detached, resources will be freed on exit */
pthread_detach (priv->health_check);
priv->health_check_active = _gf_true;
}
unlock:
UNLOCK (&priv->lock);
}

View File

@ -23,6 +23,7 @@
#include <pthread.h>
#include <ftw.h>
#include <sys/stat.h>
#include <signal.h>
#ifndef GF_BSD_HOST_OS
#include <alloca.h>
@ -4320,6 +4321,10 @@ reconfigure (xlator_t *this, dict_t *options)
" fallback to <hostname>:<export>");
}
GF_OPTION_RECONF ("health-check-interval", priv->health_check_interval,
options, uint32, out);
posix_spawn_health_check_thread (this);
ret = 0;
out:
return ret;
@ -4690,6 +4695,12 @@ init (xlator_t *this)
" fallback to <hostname>:<export>");
}
_private->health_check_active = _gf_false;
GF_OPTION_INIT ("health-check-interval",
_private->health_check_interval, uint32, out);
if (_private->health_check_interval)
posix_spawn_health_check_thread (this);
pthread_mutex_init (&_private->janitor_lock, NULL);
pthread_cond_init (&_private->janitor_cond, NULL);
INIT_LIST_HEAD (&_private->janitor_fds);
@ -4815,5 +4826,14 @@ struct volume_options options[] = {
.description = "return glusterd's node-uuid in pathinfo xattr"
" string instead of hostname"
},
{
.key = {"health-check-interval"},
.type = GF_OPTION_TYPE_INT,
.min = 0,
.default_value = "30",
.validate = GF_OPT_VALIDATE_MIN,
.description = "Interval in seconds for a filesystem health check, "
"set to 0 to disable"
},
{ .key = {NULL} }
};

View File

@ -127,6 +127,11 @@ struct posix_private {
/* node-uuid in pathinfo xattr */
gf_boolean_t node_uuid_pathinfo;
/* seconds to sleep between health checks */
uint32_t health_check_interval;
pthread_t health_check;
gf_boolean_t health_check_active;
};
typedef struct {
@ -178,4 +183,5 @@ gf_boolean_t posix_special_xattr (char **pattern, char *key);
void
__posix_fd_set_odirect (fd_t *fd, struct posix_fd *pfd, int opflags,
off_t offset, size_t size);
void posix_spawn_health_check_thread (xlator_t *this);
#endif /* _POSIX_H */