/*
Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#include <glusterfs/xlator.h>
#include "error-gen.h"
#include <glusterfs/statedump.h>
#include <glusterfs/defaults.h>
/*
* The user can specify an error probability as a float percentage, but we
* store it internally as a numerator with this as the denominator. When it's
* used, it's like this:
*
* (rand() % FAILURE_GRANULARITY) < error_rate
*
* To minimize rounding errors from the modulo operation, it's good for this to
* be a power of two.
*
* (BTW this is just the normal case. If "random-failure" is set, that does
* something completely different and this number is irrelevant. See error_gen
* for the legacy code.)
*/
#define FAILURE_GRANULARITY (1 << 20)
sys_error_t error_no_list[] = {
[GF_FOP_LOOKUP] = {.error_no_count = 4,
.error_no = {ENOENT, ENOTDIR, ENAMETOOLONG, EAGAIN}},
[GF_FOP_STAT] = {.error_no_count = 7,
.error_no = {EACCES, EBADF, EFAULT, ENAMETOOLONG, ENOENT,
ENOMEM, ENOTDIR}},
[GF_FOP_READLINK] = {.error_no_count = 8,
.error_no = {EACCES, EFAULT, EINVAL, EIO, ENAMETOOLONG,
ENOENT, ENOMEM, ENOTDIR}},
[GF_FOP_MKNOD] = {.error_no_count = 11,
.error_no = {EACCES, EEXIST, EFAULT, EINVAL, ENAMETOOLONG,
ENOENT, ENOMEM, ENOSPC, ENOTDIR, EPERM,
EROFS}},
[GF_FOP_MKDIR] = {.error_no_count = 10,
.error_no = {EACCES, EEXIST, EFAULT, ENAMETOOLONG, ENOENT,
ENOMEM, ENOSPC, ENOTDIR, EPERM, EROFS}},
[GF_FOP_UNLINK] = {.error_no_count = 10,
.error_no = {EACCES, EBUSY, EFAULT, EIO, EISDIR,
ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR,
EPERM, EROFS}},
[GF_FOP_RMDIR] = {.error_no_count = 8,
.error_no = {EACCES, EBUSY, EFAULT, ENOMEM, ENOTDIR,
ENOTEMPTY, EPERM, EROFS}},
[GF_FOP_SYMLINK] = {.error_no_count = 11,
.error_no = {EACCES, EEXIST, EFAULT, EIO, ENAMETOOLONG,
ENOENT, ENOMEM, ENOSPC, ENOTDIR, EPERM,
EROFS}},
[GF_FOP_RENAME] = {.error_no_count = 13,
.error_no = {EACCES, EBUSY, EFAULT, EINVAL, EISDIR,
EMLINK, ENAMETOOLONG, ENOENT, ENOMEM,
ENOSPC, ENOTDIR, EEXIST, EXDEV}},
[GF_FOP_LINK] = {.error_no_count = 13,
.error_no = {EACCES, EFAULT, EEXIST, EIO, EMLINK,
ENAMETOOLONG, ENOENT, ENOMEM, ENOSPC, ENOTDIR,
EPERM, EROFS, EXDEV}},
[GF_FOP_TRUNCATE] = {.error_no_count = 10,
.error_no = {EACCES, EFAULT, EFBIG, EINTR, EINVAL, EIO,
EISDIR, ENAMETOOLONG, ENOENT, EISDIR}},
[GF_FOP_CREATE] = {.error_no_count = 10,
.error_no = {EACCES, EEXIST, EFAULT, EISDIR, EMFILE,
ENAMETOOLONG, ENFILE, ENODEV, ENOENT,
ENODEV}},
[GF_FOP_OPEN] = {.error_no_count = 10,
.error_no = {EACCES, EEXIST, EFAULT, EISDIR, EMFILE,
ENAMETOOLONG, ENFILE, ENODEV, ENOENT,
ENOMEM}},
[GF_FOP_READ] = {.error_no_count = 5,
.error_no = {EINVAL, EBADF, EFAULT, EISDIR, ENAMETOOLONG}},
[GF_FOP_WRITE] = {.error_no_count = 7,
.error_no = {EINVAL, EBADF, EFAULT, EISDIR, ENAMETOOLONG,
ENOSPC, GF_ERROR_SHORT_WRITE}},
[GF_FOP_STATFS] = {.error_no_count = 10,
.error_no = {EACCES, EBADF, EFAULT, EINTR, EIO,
ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS,
ENOTDIR}},
[GF_FOP_FLUSH] = {.error_no_count = 5,
.error_no = {EACCES, EFAULT, ENAMETOOLONG, ENOSYS,
ENOENT}},
[GF_FOP_FSYNC] = {.error_no_count = 4,
.error_no = {EBADF, EIO, EROFS, EINVAL}},
[GF_FOP_SETXATTR] = {.error_no_count = 4,
.error_no = {EACCES, EBADF, EINTR, ENAMETOOLONG}},
[GF_FOP_GETXATTR] = {.error_no_count = 4,
.error_no = {EACCES, EBADF, ENAMETOOLONG, EINTR}},
[GF_FOP_REMOVEXATTR] = {.error_no_count = 4,
.error_no = {EACCES, EBADF, ENAMETOOLONG, EINTR}},
[GF_FOP_FSETXATTR] = {.error_no_count = 4,
.error_no = {EACCES, EBADF, EINTR, ENAMETOOLONG}},
[GF_FOP_FGETXATTR] = {.error_no_count = 4,
.error_no = {EACCES, EBADF, ENAMETOOLONG, EINTR}},
[GF_FOP_FREMOVEXATTR] = {.error_no_count = 4,
.error_no = {EACCES, EBADF, ENAMETOOLONG, EINTR}},
[GF_FOP_OPENDIR] = {.error_no_count = 8,
.error_no = {EACCES, EEXIST, EFAULT, EISDIR, EMFILE,
ENAMETOOLONG, ENFILE, ENODEV}},
[GF_FOP_READDIR] = {.error_no_count = 5,
.error_no = {EINVAL, EACCES, EBADF, EMFILE, ENOENT}},
[GF_FOP_READDIRP] = {.error_no_count = 5,
.error_no = {EINVAL, EACCES, EBADF, EMFILE, ENOENT}},
[GF_FOP_FSYNCDIR] = {.error_no_count = 4,
.error_no = {EBADF, EIO, EROFS, EINVAL}},
[GF_FOP_ACCESS] = {.error_no_count = 8,
.error_no = {EACCES, ENAMETOOLONG, ENOENT, ENOTDIR,
EROFS, EFAULT, EINVAL, EIO}},
[GF_FOP_FTRUNCATE] = {.error_no_count = 9,
.error_no = {EACCES, EFAULT, EFBIG, EINTR, EINVAL,
EIO, EISDIR, ENAMETOOLONG, ENOENT}},
[GF_FOP_FSTAT] = {.error_no_count = 7,
.error_no = {EACCES, EBADF, EFAULT, ENAMETOOLONG, ENOENT,
ENOMEM, ENOTDIR}},
[GF_FOP_LK] = {.error_no_count = 4,
.error_no = {EACCES, EFAULT, ENOENT, EINTR}},
[GF_FOP_XATTROP] = {.error_no_count = 5,
.error_no = {EACCES, EFAULT, ENAMETOOLONG, ENOSYS,
ENOENT}},
[GF_FOP_FXATTROP] = {.error_no_count = 4,
.error_no = {EBADF, EIO, EROFS, EINVAL}},
[GF_FOP_INODELK] = {.error_no_count = 4,
.error_no = {EACCES, EBADF, EINTR, ENAMETOOLONG}},
[GF_FOP_FINODELK] = {.error_no_count = 4,
.error_no = {EACCES, EBADF, EINTR, ENAMETOOLONG}},
[GF_FOP_ENTRYLK] = {.error_no_count = 4,
.error_no = {EACCES, EBADF, ENAMETOOLONG, EINTR}},
[GF_FOP_FENTRYLK] = {.error_no_count = 10,
.error_no = {EACCES, EEXIST, EFAULT, EISDIR, EMFILE,
ENAMETOOLONG, ENFILE, ENODEV, ENOENT,
ENOMEM}},
[GF_FOP_SETATTR] = {.error_no_count = 11,
.error_no = {EACCES, EFAULT, EIO, ENAMETOOLONG, ENOENT,
ENOMEM, ENOTDIR, EPERM, EROFS, EBADF,
EIO}},
[GF_FOP_FSETATTR] = {.error_no_count = 11,
.error_no = {EACCES, EFAULT, EIO, ENAMETOOLONG, ENOENT,
ENOMEM, ENOTDIR, EPERM, EROFS, EBADF,
EIO}},
[GF_FOP_GETSPEC] = {.error_no_count = 4,
.error_no = {EACCES, EBADF, ENAMETOOLONG, EINTR}}};
int
generate_rand_no(int op_no)
{
int rand_no = 0;
int error_no_list_size = 0;
error_no_list_size = sizeof(error_no_list) / sizeof(error_no_list[0]);
if (op_no < error_no_list_size)
/* coverity[DC.WEAK_CRYPTO] */
rand_no = rand() % error_no_list[op_no].error_no_count;
return rand_no;
}
int
conv_errno_to_int(char **error_no)
{
if (!strcmp((*error_no), "ENOENT"))
return ENOENT;
else if (!strcmp((*error_no), "ENOTDIR"))
return ENOTDIR;
else if (!strcmp((*error_no), "ENAMETOOLONG"))
return ENAMETOOLONG;
else if (!strcmp((*error_no), "EACCES"))
return EACCES;
else if (!strcmp((*error_no), "EBADF"))
return EBADF;
else if (!strcmp((*error_no), "EFAULT"))
return EFAULT;
else if (!strcmp((*error_no), "ENOMEM"))
return ENOMEM;
else if (!strcmp((*error_no), "EINVAL"))
return EINVAL;
else if (!strcmp((*error_no), "EIO"))
return EIO;
else if (!strcmp((*error_no), "EEXIST"))
return EEXIST;
else if (!strcmp((*error_no), "ENOSPC"))
return ENOSPC;
else if (!strcmp((*error_no), "EPERM"))
return EPERM;
else if (!strcmp((*error_no), "EROFS"))
return EROFS;
else if (!strcmp((*error_no), "EBUSY"))
return EBUSY;
else if (!strcmp((*error_no), "EISDIR"))
return EISDIR;
else if (!strcmp((*error_no), "ENOTEMPTY"))
return ENOTEMPTY;
else if (!strcmp((*error_no), "EMLINK"))
return EMLINK;
else if (!strcmp((*error_no), "ENODEV"))
return ENODEV;
else if (!strcmp((*error_no), "EXDEV"))
return EXDEV;
else if (!strcmp((*error_no), "EMFILE"))
return EMFILE;
else if (!strcmp((*error_no), "ENFILE"))
return ENFILE;
else if (!strcmp((*error_no), "ENOSYS"))
return ENOSYS;
else if (!strcmp((*error_no), "EINTR"))
return EINTR;
else if (!strcmp((*error_no), "EFBIG"))
return EFBIG;
else if (!strcmp((*error_no), "GF_ERROR_SHORT_WRITE"))
return GF_ERROR_SHORT_WRITE;
else
return EAGAIN;
}
int
error_gen(xlator_t *this, int op_no)
{
eg_t *egp = NULL;
int count = 0;
int error_no_int = 0;
int rand_no = 0;
int ret = 0;
gf_boolean_t should_err = _gf_false;
int error_no_list_size = 0;
egp = this->private;
if (egp->random_failure) {
/*
* I honestly don't know why anyone would use this "feature"
* but I'll try to preserve its functionality anyway. Without
* locking twice to update failure_iter_no and egp->op_count
* separately, then not locking at all to update
* egp->failure_iter_no. That's not needed for compatibility,
* and it's abhorrently wrong. I have *some* standards.
*/
LOCK(&egp->lock);
{
count = ++(egp->op_count);
error_no_int = egp->error_no_int;
if ((count % egp->failure_iter_no) == 0) {
egp->op_count = 0;
/* coverity[DC.WEAK_CRYPTO] */
egp->failure_iter_no = 3 + (rand() % GF_UNIVERSAL_ANSWER);
should_err = _gf_true;
}
}
UNLOCK(&egp->lock);
} else {
/*
* It turns out that rand() is almost universally implemented
* as a linear congruential PRNG, which is about as cheap as
* it gets. This gets us real random behavior, including
* phenomena like streaks and dry spells, with controllable
* long-term probability, cheaply.
*/
if ((rand() % FAILURE_GRANULARITY) < egp->failure_iter_no) {
should_err = _gf_true;
}
}
error_no_list_size = sizeof(error_no_list) / sizeof(error_no_list[0]);
if (should_err) {
if (error_no_int)
ret = error_no_int;
else {
rand_no = generate_rand_no(op_no);
if (op_no >= error_no_list_size)
op_no = 0;
if (rand_no >= error_no_list[op_no].error_no_count)
rand_no = 0;
ret = error_no_list[op_no].error_no[rand_no];
}
}
return ret;
}
int
error_gen_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_LOOKUP];
if (enable)
op_errno = error_gen(this, GF_FOP_LOOKUP);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(lookup, frame, -1, op_errno, NULL, NULL, NULL,
NULL);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->lookup,
loc, xdata);
return 0;
}
int
error_gen_stat(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_STAT];
if (enable)
op_errno = error_gen(this, GF_FOP_STAT);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(stat, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->stat,
loc, xdata);
return 0;
}
int
error_gen_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
struct iatt *stbuf, int32_t valid, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_SETATTR];
if (enable)
op_errno = error_gen(this, GF_FOP_SETATTR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(setattr, frame, -1, op_errno, NULL, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->setattr,
loc, stbuf, valid, xdata);
return 0;
}
int
error_gen_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
struct iatt *stbuf, int32_t valid, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FSETATTR];
if (enable)
op_errno = error_gen(this, GF_FOP_FSETATTR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(fsetattr, frame, -1, op_errno, NULL, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->fsetattr,
fd, stbuf, valid, xdata);
return 0;
}
int
error_gen_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc,
off_t offset, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_TRUNCATE];
if (enable)
op_errno = error_gen(this, GF_FOP_TRUNCATE);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(truncate, frame, -1, op_errno, NULL, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->truncate,
loc, offset, xdata);
return 0;
}
int
error_gen_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FTRUNCATE];
if (enable)
op_errno = error_gen(this, GF_FOP_FTRUNCATE);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(ftruncate, frame, -1, op_errno, NULL, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->ftruncate, fd, offset, xdata);
return 0;
}
int
error_gen_access(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t mask,
dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_ACCESS];
if (enable)
op_errno = error_gen(this, GF_FOP_ACCESS);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(access, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->access,
loc, mask, xdata);
return 0;
}
int
error_gen_readlink(call_frame_t *frame, xlator_t *this, loc_t *loc, size_t size,
dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_READLINK];
if (enable)
op_errno = error_gen(this, GF_FOP_READLINK);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(readlink, frame, -1, op_errno, NULL, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->readlink,
loc, size, xdata);
return 0;
}
int
error_gen_mknod(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
dev_t rdev, mode_t umask, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_MKNOD];
if (enable)
op_errno = error_gen(this, GF_FOP_MKNOD);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(mknod, frame, -1, op_errno, NULL, NULL, NULL, NULL,
xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->mknod,
loc, mode, rdev, umask, xdata);
return 0;
}
int
error_gen_mkdir(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
mode_t umask, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_MKDIR];
if (enable)
op_errno = error_gen(this, GF_FOP_MKDIR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(mkdir, frame, -1, op_errno, NULL, NULL, NULL, NULL,
xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->mkdir,
loc, mode, umask, xdata);
return 0;
}
int
error_gen_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag,
dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_UNLINK];
if (enable)
op_errno = error_gen(this, GF_FOP_UNLINK);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(unlink, frame, -1, op_errno, NULL, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->unlink,
loc, xflag, xdata);
return 0;
}
int
error_gen_rmdir(call_frame_t *frame, xlator_t *this, loc_t *loc, int flags,
dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_RMDIR];
if (enable)
op_errno = error_gen(this, GF_FOP_RMDIR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(rmdir, frame, -1, op_errno, NULL, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->rmdir,
loc, flags, xdata);
return 0;
}
int
error_gen_symlink(call_frame_t *frame, xlator_t *this, const char *linkpath,
loc_t *loc, mode_t umask, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_SYMLINK];
if (enable)
op_errno = error_gen(this, GF_FOP_SYMLINK);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(symlink, frame, -1, op_errno, NULL, NULL, NULL,
NULL, NULL); /* pre & post parent attr */
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->symlink,
linkpath, loc, umask, xdata);
return 0;
}
int
error_gen_rename(call_frame_t *frame, xlator_t *this, loc_t *oldloc,
loc_t *newloc, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_RENAME];
if (enable)
op_errno = error_gen(this, GF_FOP_RENAME);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(rename, frame, -1, op_errno, NULL, NULL, NULL, NULL,
NULL, NULL);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->rename,
oldloc, newloc, xdata);
return 0;
}
int
error_gen_link(call_frame_t *frame, xlator_t *this, loc_t *oldloc,
loc_t *newloc, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_LINK];
if (enable)
op_errno = error_gen(this, GF_FOP_LINK);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(link, frame, -1, op_errno, NULL, NULL, NULL, NULL,
NULL);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->link,
oldloc, newloc, xdata);
return 0;
}
int
error_gen_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_CREATE];
if (enable)
op_errno = error_gen(this, GF_FOP_CREATE);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(create, frame, -1, op_errno, NULL, NULL, NULL, NULL,
NULL, NULL);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->create,
loc, flags, mode, umask, fd, xdata);
return 0;
}
int
error_gen_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
fd_t *fd, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_OPEN];
if (enable)
op_errno = error_gen(this, GF_FOP_OPEN);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(open, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->open,
loc, flags, fd, xdata);
return 0;
}
int
error_gen_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
off_t offset, uint32_t flags, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_READ];
if (enable)
op_errno = error_gen(this, GF_FOP_READ);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(readv, frame, -1, op_errno, NULL, 0, NULL, NULL,
xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->readv,
fd, size, offset, flags, xdata);
return 0;
}
int
error_gen_writev(call_frame_t *frame, xlator_t *this, fd_t *fd,
struct iovec *vector, int32_t count, off_t off, uint32_t flags,
struct iobref *iobref, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
struct iovec *shortvec = NULL;
egp = this->private;
enable = egp->enable[GF_FOP_WRITE];
if (enable)
op_errno = error_gen(this, GF_FOP_WRITE);
if (op_errno == GF_ERROR_SHORT_WRITE) {
/*
* A short write error returns some value less than what was
* requested from a write. To simulate this, replace the vector
* with one half the size;
*/
shortvec = iov_dup(vector, 1);
shortvec->iov_len /= 2;
goto wind;
} else if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(writev, frame, -1, op_errno, NULL, NULL, xdata);
return 0;
}
wind:
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->writev,
fd, shortvec ? shortvec : vector, count, off, flags, iobref,
xdata);
if (shortvec)
GF_FREE(shortvec);
return 0;
}
int
error_gen_flush(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FLUSH];
if (enable)
op_errno = error_gen(this, GF_FOP_FLUSH);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(flush, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->flush,
fd, xdata);
return 0;
}
int
error_gen_fsync(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags,
dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FSYNC];
if (enable)
op_errno = error_gen(this, GF_FOP_FSYNC);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(fsync, frame, -1, op_errno, NULL, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->fsync,
fd, flags, xdata);
return 0;
}
int
error_gen_fstat(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FSTAT];
if (enable)
op_errno = error_gen(this, GF_FOP_FSTAT);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(fstat, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->fstat,
fd, xdata);
return 0;
}
int
error_gen_opendir(call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd,
dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_OPENDIR];
if (enable)
op_errno = error_gen(this, GF_FOP_OPENDIR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(opendir, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->opendir,
loc, fd, xdata);
return 0;
}
int
error_gen_fsyncdir(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags,
dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FSYNCDIR];
if (enable)
op_errno = error_gen(this, GF_FOP_FSYNCDIR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(fsyncdir, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->fsyncdir,
fd, flags, xdata);
return 0;
}
int
error_gen_statfs(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_STATFS];
if (enable)
op_errno = error_gen(this, GF_FOP_STATFS);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(statfs, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->statfs,
loc, xdata);
return 0;
}
int
error_gen_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
dict_t *dict, int32_t flags, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_SETXATTR];
if (enable)
op_errno = error_gen(this, GF_FOP_SETXATTR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(setxattr, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->setxattr,
loc, dict, flags, xdata);
return 0;
}
int
error_gen_getxattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
const char *name, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_GETXATTR];
if (enable)
op_errno = error_gen(this, GF_FOP_GETXATTR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(getxattr, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->getxattr,
loc, name, xdata);
return 0;
}
int
error_gen_fsetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict,
int32_t flags, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FSETXATTR];
if (enable)
op_errno = error_gen(this, GF_FOP_FSETXATTR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(fsetxattr, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->fsetxattr, fd, dict, flags, xdata);
return 0;
}
int
error_gen_fgetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
const char *name, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FGETXATTR];
if (enable)
op_errno = error_gen(this, GF_FOP_FGETXATTR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(fgetxattr, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->fgetxattr, fd, name, xdata);
return 0;
}
int
error_gen_xattrop(call_frame_t *frame, xlator_t *this, loc_t *loc,
gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_XATTROP];
if (enable)
op_errno = error_gen(this, GF_FOP_XATTROP);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(xattrop, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->xattrop,
loc, flags, dict, xdata);
return 0;
}
int
error_gen_fxattrop(call_frame_t *frame, xlator_t *this, fd_t *fd,
gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FXATTROP];
if (enable)
op_errno = error_gen(this, GF_FOP_FXATTROP);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(fxattrop, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->fxattrop,
fd, flags, dict, xdata);
return 0;
}
int
error_gen_removexattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
const char *name, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_REMOVEXATTR];
if (enable)
op_errno = error_gen(this, GF_FOP_REMOVEXATTR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(removexattr, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->removexattr, loc, name, xdata);
return 0;
}
int
error_gen_fremovexattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
const char *name, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FREMOVEXATTR];
if (enable)
op_errno = error_gen(this, GF_FOP_FREMOVEXATTR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(fremovexattr, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->fremovexattr, fd, name, xdata);
return 0;
}
int
error_gen_lk(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd,
struct gf_flock *lock, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_LK];
if (enable)
op_errno = error_gen(this, GF_FOP_LK);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(lk, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->lk, fd,
cmd, lock, xdata);
return 0;
}
int
error_gen_inodelk(call_frame_t *frame, xlator_t *this, const char *volume,
loc_t *loc, int32_t cmd, struct gf_flock *lock, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_INODELK];
if (enable)
op_errno = error_gen(this, GF_FOP_INODELK);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(inodelk, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->inodelk,
volume, loc, cmd, lock, xdata);
return 0;
}
int
error_gen_finodelk(call_frame_t *frame, xlator_t *this, const char *volume,
fd_t *fd, int32_t cmd, struct gf_flock *lock, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FINODELK];
if (enable)
op_errno = error_gen(this, GF_FOP_FINODELK);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(finodelk, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->finodelk,
volume, fd, cmd, lock, xdata);
return 0;
}
int
error_gen_entrylk(call_frame_t *frame, xlator_t *this, const char *volume,
loc_t *loc, const char *basename, entrylk_cmd cmd,
entrylk_type type, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_ENTRYLK];
if (enable)
op_errno = error_gen(this, GF_FOP_ENTRYLK);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(entrylk, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->entrylk,
volume, loc, basename, cmd, type, xdata);
return 0;
}
int
error_gen_fentrylk(call_frame_t *frame, xlator_t *this, const char *volume,
fd_t *fd, const char *basename, entrylk_cmd cmd,
entrylk_type type, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_FENTRYLK];
if (enable)
op_errno = error_gen(this, GF_FOP_FENTRYLK);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(fentrylk, frame, -1, op_errno, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->fentrylk,
volume, fd, basename, cmd, type, xdata);
return 0;
}
int
error_gen_getspec(call_frame_t *frame, xlator_t *this, const char *key,
int32_t flags)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_GETSPEC];
if (enable)
op_errno = error_gen(this, GF_FOP_GETSPEC);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(getspec, frame, -1, op_errno, NULL);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->getspec,
key, flags);
return 0;
}
int
error_gen_readdir(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
off_t off, dict_t *xdata)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_READDIR];
if (enable)
op_errno = error_gen(this, GF_FOP_READDIR);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(readdir, frame, -1, op_errno, NULL, xdata);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->readdir,
fd, size, off, xdata);
return 0;
}
int
error_gen_readdirp(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
off_t off, dict_t *dict)
{
int op_errno = 0;
eg_t *egp = NULL;
int enable = 1;
egp = this->private;
enable = egp->enable[GF_FOP_READDIRP];
if (enable)
op_errno = error_gen(this, GF_FOP_READDIRP);
if (op_errno) {
GF_ERROR(this, "unwind(-1, %s)", strerror(op_errno));
STACK_UNWIND_STRICT(readdirp, frame, -1, op_errno, NULL, NULL);
return 0;
}
STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->readdirp,
fd, size, off, dict);
return 0;
}
static void
error_gen_set_failure(eg_t *pvt, double percent)
{
double ppm;
GF_ASSERT(pvt);
ppm = (percent / 100.0) * (double)FAILURE_GRANULARITY;
pvt->failure_iter_no = (int)ppm;
}
static void
error_gen_parse_fill_fops(eg_t *pvt, char *enable_fops)
{
char *op_no_str = NULL;
int op_no = -1;
int i = 0;
xlator_t *this = THIS;
char *saveptr = NULL;
GF_ASSERT(pvt);
GF_ASSERT(this);
for (i = 0; i < GF_FOP_MAXVALUE; i++)
pvt->enable[i] = 0;
if (!enable_fops) {
gf_log(this->name, GF_LOG_WARNING, "All fops are enabled.");
for (i = 0; i < GF_FOP_MAXVALUE; i++)
pvt->enable[i] = 1;
} else {
op_no_str = strtok_r(enable_fops, ",", &saveptr);
while (op_no_str) {
op_no = gf_fop_int(op_no_str);
if (op_no == -1) {
gf_log(this->name, GF_LOG_WARNING, "Wrong option value %s",
op_no_str);
} else
pvt->enable[op_no] = 1;
op_no_str = strtok_r(NULL, ",", &saveptr);
}
}
}
int32_t
error_gen_priv_dump(xlator_t *this)
{
char key_prefix[GF_DUMP_MAX_BUF_LEN];
int ret = -1;
eg_t *conf = NULL;
if (!this)
goto out;
conf = this->private;
if (!conf)
goto out;
ret = TRY_LOCK(&conf->lock);
if (ret != 0) {
return ret;
}
gf_proc_dump_add_section("xlator.debug.error-gen.%s.priv", this->name);
gf_proc_dump_build_key(key_prefix, "xlator.debug.error-gen", "%s.priv",
this->name);
gf_proc_dump_write("op_count", "%d", conf->op_count);
gf_proc_dump_write("failure_iter_no", "%d", conf->failure_iter_no);
gf_proc_dump_write("error_no", "%d", conf->error_no_int);
gf_proc_dump_write("random_failure", "%d", conf->random_failure);
UNLOCK(&conf->lock);
out:
return ret;
}
int32_t
mem_acct_init(xlator_t *this)
{
int ret = -1;
if (!this)
return ret;
ret = xlator_mem_acct_init(this, gf_error_gen_mt_end + 1);
if (ret != 0) {
gf_log(this->name, GF_LOG_ERROR,
"Memory accounting init"
" failed");
return ret;
}
return ret;
}
int
reconfigure(xlator_t *this, dict_t *options)
{
eg_t *pvt = NULL;
int32_t ret = 0;
char *error_enable_fops = NULL;
char *error_no = NULL;
double failure_percent_dbl = 0.0;
if (!this || !this->private)
goto out;
pvt = this->private;
ret = -1;
GF_OPTION_RECONF("error-no", error_no, options, str, out);
if (error_no)
pvt->error_no_int = conv_errno_to_int(&error_no);
GF_OPTION_RECONF("failure", failure_percent_dbl, options, percent, out);
GF_OPTION_RECONF("enable", error_enable_fops, options, str, out);
GF_OPTION_RECONF("random-failure", pvt->random_failure, options, bool, out);
error_gen_parse_fill_fops(pvt, error_enable_fops);
error_gen_set_failure(pvt, failure_percent_dbl);
ret = 0;
out:
gf_log(this ? this->name : "error-gen", GF_LOG_DEBUG,
"reconfigure returning %d", ret);
return ret;
}
int
init(xlator_t *this)
{
eg_t *pvt = NULL;
int32_t ret = 0;
char *error_enable_fops = NULL;
char *error_no = NULL;
double failure_percent_dbl = 0.0;
if (!this->children || this->children->next) {
gf_log(this->name, GF_LOG_ERROR,
"error-gen not configured with one subvolume");
ret = -1;
goto out;
}
if (!this->parents) {
gf_log(this->name, GF_LOG_WARNING, "dangling volume. check volfile ");
}
pvt = GF_CALLOC(1, sizeof(eg_t), gf_error_gen_mt_eg_t);
if (!pvt) {
ret = -1;
goto out;
}
LOCK_INIT(&pvt->lock);
ret = -1;
GF_OPTION_INIT("error-no", error_no, str, out);
if (error_no)
pvt->error_no_int = conv_errno_to_int(&error_no);
GF_OPTION_INIT("failure", failure_percent_dbl, percent, out);
GF_OPTION_INIT("enable", error_enable_fops, str, out);
GF_OPTION_INIT("random-failure", pvt->random_failure, bool, out);
error_gen_parse_fill_fops(pvt, error_enable_fops);
error_gen_set_failure(pvt, failure_percent_dbl);
this->private = pvt;
/* Give some seed value here */
srand(time(NULL));
ret = 0;
out:
if (ret)
GF_FREE(pvt);
return ret;
}
void
fini(xlator_t *this)
{
eg_t *pvt = NULL;
if (!this)
return;
pvt = this->private;
if (pvt) {
LOCK_DESTROY(&pvt->lock);
GF_FREE(pvt);
gf_log(this->name, GF_LOG_DEBUG, "fini called");
}
return;
}
struct xlator_dumpops dumpops = {
.priv = error_gen_priv_dump,
};
struct xlator_cbks cbks;
struct xlator_fops fops = {
.lookup = error_gen_lookup,
.stat = error_gen_stat,
.readlink = error_gen_readlink,
.mknod = error_gen_mknod,
.mkdir = error_gen_mkdir,
.unlink = error_gen_unlink,
.rmdir = error_gen_rmdir,
.symlink = error_gen_symlink,
.rename = error_gen_rename,
.link = error_gen_link,
.truncate = error_gen_truncate,
.create = error_gen_create,
.open = error_gen_open,
.readv = error_gen_readv,
.writev = error_gen_writev,
.statfs = error_gen_statfs,
.flush = error_gen_flush,
.fsync = error_gen_fsync,
.setxattr = error_gen_setxattr,
.getxattr = error_gen_getxattr,
.removexattr = error_gen_removexattr,
.fsetxattr = error_gen_fsetxattr,
.fgetxattr = error_gen_fgetxattr,
.fremovexattr = error_gen_fremovexattr,
.opendir = error_gen_opendir,
.readdir = error_gen_readdir,
.readdirp = error_gen_readdirp,
.fsyncdir = error_gen_fsyncdir,
.access = error_gen_access,
.ftruncate = error_gen_ftruncate,
.fstat = error_gen_fstat,
.lk = error_gen_lk,
.xattrop = error_gen_xattrop,
.fxattrop = error_gen_fxattrop,
.inodelk = error_gen_inodelk,
.finodelk = error_gen_finodelk,
.entrylk = error_gen_entrylk,
.fentrylk = error_gen_fentrylk,
.setattr = error_gen_setattr,
.fsetattr = error_gen_fsetattr,
.getspec = error_gen_getspec,
};
struct volume_options options[] = {
{
.key = {"failure"},
.type = GF_OPTION_TYPE_PERCENT,
.description = "Percentage failure of operations when enabled.",
},
{
.key = {"error-no"},
.value = {"ENOENT",
"ENOTDIR",
"ENAMETOOLONG",
"EACCES",
"EBADF",
"EFAULT",
"ENOMEM",
"EINVAL",
"EIO",
"EEXIST",
"ENOSPC",
"EPERM",
"EROFS",
"EBUSY",
"EISDIR",
"ENOTEMPTY",
"EMLINK"
"ENODEV",
"EXDEV",
"EMFILE",
"ENFILE",
"ENOSYS",
"EINTR",
"EFBIG",
"EAGAIN",
"GF_ERROR_SHORT_WRITE"},
.type = GF_OPTION_TYPE_STR,
.op_version = {3},
.tags = {"error-gen"},
.flags = OPT_FLAG_SETTABLE,
},
{
.key = {"random-failure"},
.type = GF_OPTION_TYPE_BOOL,
.default_value = "off",
.op_version = {3},
.tags = {"error-gen"},
.flags = OPT_FLAG_SETTABLE,
},
{
.key = {"enable", "error-fops"},
.type = GF_OPTION_TYPE_STR,
.description = "Accepts a string which takes ',' separated fop "
"strings to denote which fops are enabled for error",
.op_version = {3},
.tags = {"error-gen"},
.flags = OPT_FLAG_SETTABLE,
},
{.key = {NULL}},
};
xlator_api_t xlator_api = {
.init = init,
.fini = fini,
.reconfigure = reconfigure,
.mem_acct_init = mem_acct_init,
.op_version = {1},
.dumpops = &dumpops,
.fops = &fops,
.cbks = &cbks,
.options = options,
.identifier = "error-gen",
.category = GF_TECH_PREVIEW,
};