/*
Copyright (c) 2007-2011 Gluster, Inc. <http://www.gluster.com>
This file is part of GlusterFS.
GlusterFS 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 3 of the License,
or (at your option) any later version.
GlusterFS 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, see
<http://www.gnu.org/licenses/>.
*/
#include <libgen.h>
#include <unistd.h>
#include <fnmatch.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "glusterfs.h"
#include "afr.h"
#include "dict.h"
#include "xlator.h"
#include "hashfn.h"
#include "logging.h"
#include "stack.h"
#include "list.h"
#include "call-stub.h"
#include "defaults.h"
#include "common-utils.h"
#include "compat-errno.h"
#include "compat.h"
#include "byte-order.h"
#include "statedump.h"
#include "fd.h"
#include "afr-inode-read.h"
#include "afr-inode-write.h"
#include "afr-dir-read.h"
#include "afr-dir-write.h"
#include "afr-transaction.h"
#include "afr-self-heal.h"
#include "afr-self-heal-common.h"
#include "pump.h"
#define AFR_ICTX_OPENDIR_DONE_MASK 0x0000000200000000ULL
#define AFR_ICTX_SPLIT_BRAIN_MASK 0x0000000100000000ULL
#define AFR_ICTX_READ_CHILD_MASK 0x00000000FFFFFFFFULL
int
afr_lookup_done_success_action (call_frame_t *frame, xlator_t *this,
gf_boolean_t fail_conflict);
gf_boolean_t
afr_is_child_present (int32_t *success_children, int32_t child_count,
int32_t child)
{
gf_boolean_t success_child = _gf_false;
int i = 0;
GF_ASSERT (child < child_count);
for (i = 0; i < child_count; i++) {
if (success_children[i] == -1)
break;
if (child == success_children[i]) {
success_child = _gf_true;
break;
}
}
return success_child;
}
gf_boolean_t
afr_is_source_child (int32_t *sources, int32_t child_count, int32_t child)
{
gf_boolean_t source_xattrs = _gf_false;
GF_ASSERT (child < child_count);
if ((child >= 0) && (child < child_count) &&
sources[child]) {
source_xattrs = _gf_true;
}
return source_xattrs;
}
gf_boolean_t
afr_is_read_child (int32_t *success_children, int32_t *sources,
int32_t child_count, int32_t child)
{
gf_boolean_t success_child = _gf_false;
gf_boolean_t source = _gf_false;
GF_ASSERT (success_children);
GF_ASSERT (child_count > 0);
success_child = afr_is_child_present (success_children, child_count,
child);
if (!success_child)
goto out;
if (NULL == sources) {
source = _gf_true;
goto out;
}
source = afr_is_source_child (sources, child_count, child);
out:
return (success_child && source);
}
void
afr_children_copy (int32_t *dst, int32_t *src, unsigned int child_count)
{
int i = 0;
for (i = 0; i < child_count; i++)
dst[i] = src[i];
}
void
afr_xattr_req_prepare (xlator_t *this, dict_t *xattr_req, const char *path)
{
int i = 0;
afr_private_t *priv = NULL;
int ret = 0;
priv = this->private;
for (i = 0; i < priv->child_count; i++) {
ret = dict_set_uint64 (xattr_req, priv->pending_key[i],
3 * sizeof(int32_t));
if (ret < 0)
gf_log (this->name, GF_LOG_WARNING,
"%s: Unable to set dict value for %s",
path, priv->pending_key[i]);
/* 3 = data+metadata+entry */
}
}
int
afr_errno_count (int32_t *children, int *child_errno,
unsigned int child_count, int32_t op_errno)
{
int i = 0;
int errno_count = 0;
int child = 0;
for (i = 0; i < child_count; i++) {
if (children) {
child = children[i];
if (child == -1)
break;
} else {
child = i;
}
if (child_errno[child] == op_errno)
errno_count++;
}
return errno_count;
}
int32_t
afr_set_dict_gfid (dict_t *dict, uuid_t gfid)
{
int ret = 0;
uuid_t *pgfid = NULL;
GF_ASSERT (gfid);
pgfid = GF_CALLOC (1, sizeof (uuid_t), gf_common_mt_char);
if (!pgfid) {
ret = -1;
gf_log (THIS->name, GF_LOG_ERROR, "Out of memory");
goto out;
}
uuid_copy (*pgfid, gfid);
ret = dict_set_dynptr (dict, "gfid-req", pgfid, 16);
if (ret) {
GF_FREE (pgfid);
gf_log (THIS->name, GF_LOG_DEBUG, "gfid set failed");
}
out:
return ret;
}
uint64_t
afr_is_split_brain (xlator_t *this, inode_t *inode)
{
int ret = 0;
uint64_t ctx = 0;
uint64_t split_brain = 0;
VALIDATE_OR_GOTO (inode, out);
LOCK (&inode->lock);
{
ret = __inode_ctx_get (inode, this, &ctx);
if (ret < 0)
goto unlock;
split_brain = ctx & AFR_ICTX_SPLIT_BRAIN_MASK;
}
unlock:
UNLOCK (&inode->lock);
out:
return split_brain;
}
void
afr_set_split_brain (xlator_t *this, inode_t *inode, gf_boolean_t set)
{
uint64_t ctx = 0;
int ret = 0;
VALIDATE_OR_GOTO (inode, out);
LOCK (&inode->lock);
{
ret = __inode_ctx_get (inode, this, &ctx);
if (ret < 0) {
ctx = 0;
}
if (set) {
ctx = (~AFR_ICTX_SPLIT_BRAIN_MASK & ctx)
| (0xFFFFFFFFFFFFFFFFULL & AFR_ICTX_SPLIT_BRAIN_MASK);
} else {
ctx = (~AFR_ICTX_SPLIT_BRAIN_MASK & ctx);
}
ret = __inode_ctx_put (inode, this, ctx);
if (ret) {
gf_log_callingfn (this->name, GF_LOG_INFO,
"failed to set the inode ctx (%s)",
uuid_utoa (inode->gfid));
}
}
UNLOCK (&inode->lock);
out:
return;
}
uint64_t
afr_is_opendir_done (xlator_t *this, inode_t *inode)
{
int ret = 0;
uint64_t ctx = 0;
uint64_t opendir_done = 0;
VALIDATE_OR_GOTO (inode, out);
LOCK (&inode->lock);
{
ret = __inode_ctx_get (inode, this, &ctx);
if (ret < 0)
goto unlock;
opendir_done = ctx & AFR_ICTX_OPENDIR_DONE_MASK;
}
unlock:
UNLOCK (&inode->lock);
out:
return opendir_done;
}
void
afr_set_opendir_done (xlator_t *this, inode_t *inode)
{
|