|
Packit Service |
e080da |
/*
|
|
Packit Service |
e080da |
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
|
|
Packit Service |
e080da |
This file is part of GlusterFS.
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
This file is licensed to you under your choice of the GNU Lesser
|
|
Packit Service |
e080da |
General Public License, version 3 or any later version (LGPLv3 or
|
|
Packit Service |
e080da |
later), or the GNU General Public License, version 2 (GPLv2), in all
|
|
Packit Service |
e080da |
cases as published by the Free Software Foundation.
|
|
Packit Service |
e080da |
*/
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
#include "afr.h"
|
|
Packit Service |
e080da |
#include "afr-self-heal.h"
|
|
Packit Service |
e080da |
#include <glusterfs/byte-order.h>
|
|
Packit Service |
e080da |
#include "protocol-common.h"
|
|
Packit Service |
e080da |
#include <glusterfs/events.h>
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
#define AFR_HEAL_ATTR (GF_SET_ATTR_UID | GF_SET_ATTR_GID | GF_SET_ATTR_MODE)
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
static gf_boolean_t
|
|
Packit Service |
e080da |
_afr_ignorable_key_match(dict_t *d, char *k, data_t *val, void *mdata)
|
|
Packit Service |
e080da |
{
|
|
Packit Service |
e080da |
return afr_is_xattr_ignorable(k);
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
void
|
|
Packit Service |
e080da |
afr_delete_ignorable_xattrs(dict_t *xattr)
|
|
Packit Service |
e080da |
{
|
|
Packit Service |
e080da |
dict_foreach_match(xattr, _afr_ignorable_key_match, NULL,
|
|
Packit Service |
e080da |
dict_remove_foreach_fn, NULL);
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
int
|
|
Packit Service |
e080da |
__afr_selfheal_metadata_do(call_frame_t *frame, xlator_t *this, inode_t *inode,
|
|
Packit Service |
e080da |
int source, unsigned char *healed_sinks,
|
|
Packit Service |
e080da |
struct afr_reply *locked_replies)
|
|
Packit Service |
e080da |
{
|
|
Packit Service |
e080da |
int ret = -1;
|
|
Packit Service |
e080da |
loc_t loc = {
|
|
Packit Service |
e080da |
0,
|
|
Packit Service |
e080da |
};
|
|
Packit Service |
e080da |
dict_t *xattr = NULL;
|
|
Packit Service |
e080da |
dict_t *old_xattr = NULL;
|
|
Packit Service |
e080da |
afr_private_t *priv = NULL;
|
|
Packit Service |
e080da |
int i = 0;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
priv = this->private;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
loc.inode = inode_ref(inode);
|
|
Packit Service |
e080da |
gf_uuid_copy(loc.gfid, inode->gfid);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
gf_msg(this->name, GF_LOG_INFO, 0, AFR_MSG_SELF_HEAL_INFO,
|
|
Packit Service |
e080da |
"performing metadata selfheal on %s", uuid_utoa(inode->gfid));
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = syncop_getxattr(priv->children[source], &loc, &xattr, NULL, NULL,
|
|
Packit Service |
e080da |
NULL);
|
|
Packit Service |
e080da |
if (ret < 0) {
|
|
Packit Service |
e080da |
ret = -EIO;
|
|
Packit Service |
e080da |
goto out;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
afr_delete_ignorable_xattrs(xattr);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
for (i = 0; i < priv->child_count; i++) {
|
|
Packit Service |
e080da |
if (old_xattr) {
|
|
Packit Service |
e080da |
dict_unref(old_xattr);
|
|
Packit Service |
e080da |
old_xattr = NULL;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (!healed_sinks[i])
|
|
Packit Service |
e080da |
continue;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = syncop_setattr(priv->children[i], &loc,
|
|
Packit Service |
e080da |
&locked_replies[source].poststat, AFR_HEAL_ATTR,
|
|
Packit Service |
e080da |
NULL, NULL, NULL, NULL);
|
|
Packit Service |
e080da |
if (ret)
|
|
Packit Service |
e080da |
healed_sinks[i] = 0;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = syncop_getxattr(priv->children[i], &loc, &old_xattr, 0, NULL,
|
|
Packit Service |
e080da |
NULL);
|
|
Packit Service |
e080da |
if (old_xattr) {
|
|
Packit Service |
e080da |
afr_delete_ignorable_xattrs(old_xattr);
|
|
Packit Service |
e080da |
ret = syncop_removexattr(priv->children[i], &loc, "", old_xattr,
|
|
Packit Service |
e080da |
NULL);
|
|
Packit Service |
e080da |
if (ret)
|
|
Packit Service |
e080da |
healed_sinks[i] = 0;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = syncop_setxattr(priv->children[i], &loc, xattr, 0, NULL, NULL);
|
|
Packit Service |
e080da |
if (ret)
|
|
Packit Service |
e080da |
healed_sinks[i] = 0;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
ret = 0;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
out:
|
|
Packit Service |
e080da |
loc_wipe(&loc;;
|
|
Packit Service |
e080da |
if (xattr)
|
|
Packit Service |
e080da |
dict_unref(xattr);
|
|
Packit Service |
e080da |
if (old_xattr)
|
|
Packit Service |
e080da |
dict_unref(old_xattr);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
return ret;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
static uint64_t
|
|
Packit Service |
e080da |
mtime_ns(struct iatt *ia)
|
|
Packit Service |
e080da |
{
|
|
Packit Service |
e080da |
uint64_t ret;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = (((uint64_t)(ia->ia_mtime)) * 1000000000) +
|
|
Packit Service |
e080da |
(uint64_t)(ia->ia_mtime_nsec);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
return ret;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
/*
|
|
Packit Service |
e080da |
* When directory content is modified, [mc]time is updated. On
|
|
Packit Service |
e080da |
* Linux, the filesystem does it, while at least on NetBSD, the
|
|
Packit Service |
e080da |
* kernel file-system independent code does it. This means that
|
|
Packit Service |
e080da |
* when entries are added while bricks are down, the kernel sends
|
|
Packit Service |
e080da |
* a SETATTR [mc]time which will cause metadata split brain for
|
|
Packit Service |
e080da |
* the directory. In this case, clear the split brain by finding
|
|
Packit Service |
e080da |
* the source with the most recent modification date.
|
|
Packit Service |
e080da |
*/
|
|
Packit Service |
e080da |
static int
|
|
Packit Service |
e080da |
afr_dirtime_splitbrain_source(call_frame_t *frame, xlator_t *this,
|
|
Packit Service |
e080da |
struct afr_reply *replies,
|
|
Packit Service |
e080da |
unsigned char *locked_on)
|
|
Packit Service |
e080da |
{
|
|
Packit Service |
e080da |
afr_private_t *priv = NULL;
|
|
Packit Service |
e080da |
int source = -1;
|
|
Packit Service |
e080da |
struct iatt source_ia;
|
|
Packit Service |
e080da |
struct iatt child_ia;
|
|
Packit Service |
e080da |
uint64_t mtime = 0;
|
|
Packit Service |
e080da |
int i;
|
|
Packit Service |
e080da |
int ret = -1;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
priv = this->private;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
for (i = 0; i < priv->child_count; i++) {
|
|
Packit Service |
e080da |
if (!locked_on[i])
|
|
Packit Service |
e080da |
continue;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (!replies[i].valid)
|
|
Packit Service |
e080da |
continue;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (replies[i].op_ret != 0)
|
|
Packit Service |
e080da |
continue;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (mtime_ns(&replies[i].poststat) <= mtime)
|
|
Packit Service |
e080da |
continue;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
mtime = mtime_ns(&replies[i].poststat);
|
|
Packit Service |
e080da |
source = i;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (source == -1)
|
|
Packit Service |
e080da |
goto out;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
source_ia = replies[source].poststat;
|
|
Packit Service |
e080da |
if (source_ia.ia_type != IA_IFDIR)
|
|
Packit Service |
e080da |
goto out;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
for (i = 0; i < priv->child_count; i++) {
|
|
Packit Service |
e080da |
if (i == source)
|
|
Packit Service |
e080da |
continue;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (!replies[i].valid)
|
|
Packit Service |
e080da |
continue;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (replies[i].op_ret != 0)
|
|
Packit Service |
e080da |
continue;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
child_ia = replies[i].poststat;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (!IA_EQUAL(source_ia, child_ia, gfid) ||
|
|
Packit Service |
e080da |
!IA_EQUAL(source_ia, child_ia, type) ||
|
|
Packit Service |
e080da |
!IA_EQUAL(source_ia, child_ia, prot) ||
|
|
Packit Service |
e080da |
!IA_EQUAL(source_ia, child_ia, uid) ||
|
|
Packit Service |
e080da |
!IA_EQUAL(source_ia, child_ia, gid) ||
|
|
Packit Service |
e080da |
!afr_xattrs_are_equal(replies[source].xdata, replies[i].xdata))
|
|
Packit Service |
e080da |
goto out;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
/*
|
|
Packit Service |
e080da |
* Metadata split brain is just about [amc]time
|
|
Packit Service |
e080da |
* We return our source.
|
|
Packit Service |
e080da |
*/
|
|
Packit Service |
e080da |
ret = source;
|
|
Packit Service |
e080da |
out:
|
|
Packit Service |
e080da |
return ret;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
/*
|
|
Packit Service |
e080da |
* Look for mismatching uid/gid or mode or user xattrs even if
|
|
Packit Service |
e080da |
* AFR xattrs don't say so, and pick one arbitrarily as winner. */
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
static int
|
|
Packit Service |
e080da |
__afr_selfheal_metadata_finalize_source(call_frame_t *frame, xlator_t *this,
|
|
Packit Service |
e080da |
inode_t *inode, unsigned char *sources,
|
|
Packit Service |
e080da |
unsigned char *sinks,
|
|
Packit Service |
e080da |
unsigned char *healed_sinks,
|
|
Packit Service |
e080da |
unsigned char *undid_pending,
|
|
Packit Service |
e080da |
unsigned char *locked_on,
|
|
Packit Service |
e080da |
struct afr_reply *replies)
|
|
Packit Service |
e080da |
{
|
|
Packit Service |
e080da |
int i = 0;
|
|
Packit Service |
e080da |
afr_private_t *priv = NULL;
|
|
Packit Service |
e080da |
struct iatt srcstat = {
|
|
Packit Service |
e080da |
0,
|
|
Packit Service |
e080da |
};
|
|
Packit Service |
e080da |
int source = -1;
|
|
Packit Service |
e080da |
int sources_count = 0;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
priv = this->private;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
sources_count = AFR_COUNT(sources, priv->child_count);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if ((AFR_CMP(locked_on, healed_sinks, priv->child_count) == 0) ||
|
|
Packit Service |
e080da |
!sources_count) {
|
|
Packit Service |
e080da |
source = afr_mark_split_brain_source_sinks(
|
|
Packit Service |
e080da |
frame, this, inode, sources, sinks, healed_sinks, locked_on,
|
|
Packit Service |
e080da |
replies, AFR_METADATA_TRANSACTION);
|
|
Packit Service |
e080da |
if (source >= 0) {
|
|
Packit Service |
e080da |
_afr_fav_child_reset_sink_xattrs(
|
|
Packit Service |
e080da |
frame, this, inode, source, healed_sinks, undid_pending,
|
|
Packit Service |
e080da |
AFR_METADATA_TRANSACTION, locked_on, replies);
|
|
Packit Service |
e080da |
goto out;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
/* If this is a directory mtime/ctime only split brain
|
|
Packit Service |
e080da |
use the most recent */
|
|
Packit Service |
e080da |
source = afr_dirtime_splitbrain_source(frame, this, replies, locked_on);
|
|
Packit Service |
e080da |
if (source != -1) {
|
|
Packit Service |
e080da |
gf_msg(this->name, GF_LOG_INFO, 0, AFR_MSG_SPLIT_BRAIN,
|
|
Packit Service |
e080da |
"clear time "
|
|
Packit Service |
e080da |
"split brain on %s",
|
|
Packit Service |
e080da |
uuid_utoa(replies[source].poststat.ia_gfid));
|
|
Packit Service |
e080da |
sources[source] = 1;
|
|
Packit Service |
e080da |
healed_sinks[source] = 0;
|
|
Packit Service |
e080da |
goto out;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (!priv->metadata_splitbrain_forced_heal) {
|
|
Packit Service |
e080da |
gf_event(EVENT_AFR_SPLIT_BRAIN,
|
|
Packit Service |
e080da |
"subvol=%s;"
|
|
Packit Service |
e080da |
"type=metadata;file=%s",
|
|
Packit Service |
35f350 |
this->name, uuid_utoa(inode->gfid));
|
|
Packit Service |
e080da |
return -EIO;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
/* Metadata split brain, select one subvol
|
|
Packit Service |
e080da |
arbitrarily */
|
|
Packit Service |
e080da |
for (i = 0; i < priv->child_count; i++) {
|
|
Packit Service |
e080da |
if (locked_on[i] && healed_sinks[i]) {
|
|
Packit Service |
e080da |
sources[i] = 1;
|
|
Packit Service |
e080da |
healed_sinks[i] = 0;
|
|
Packit Service |
e080da |
break;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
/* No split brain at this point. If we were called from
|
|
Packit Service |
e080da |
* afr_heal_splitbrain_file(), abort.*/
|
|
Packit Service |
e080da |
if (afr_dict_contains_heal_op(frame))
|
|
Packit Service |
e080da |
return -EIO;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
source = afr_choose_source_by_policy(priv, sources,
|
|
Packit Service |
e080da |
AFR_METADATA_TRANSACTION);
|
|
Packit Service |
e080da |
srcstat = replies[source].poststat;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
for (i = 0; i < priv->child_count; i++) {
|
|
Packit Service |
e080da |
if (!sources[i] || i == source)
|
|
Packit Service |
e080da |
continue;
|
|
Packit Service |
e080da |
if (!IA_EQUAL(srcstat, replies[i].poststat, type) ||
|
|
Packit Service |
e080da |
!IA_EQUAL(srcstat, replies[i].poststat, uid) ||
|
|
Packit Service |
e080da |
!IA_EQUAL(srcstat, replies[i].poststat, gid) ||
|
|
Packit Service |
e080da |
!IA_EQUAL(srcstat, replies[i].poststat, prot)) {
|
|
Packit Service |
e080da |
gf_msg_debug(this->name, 0,
|
|
Packit Service |
e080da |
"%s: iatt mismatch "
|
|
Packit Service |
e080da |
"for source(%d) vs (%d)",
|
|
Packit Service |
e080da |
uuid_utoa(replies[source].poststat.ia_gfid), source,
|
|
Packit Service |
e080da |
i);
|
|
Packit Service |
e080da |
sources[i] = 0;
|
|
Packit Service |
e080da |
healed_sinks[i] = 1;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
for (i = 0; i < priv->child_count; i++) {
|
|
Packit Service |
e080da |
if (!sources[i] || i == source)
|
|
Packit Service |
e080da |
continue;
|
|
Packit Service |
e080da |
if (!afr_xattrs_are_equal(replies[source].xdata, replies[i].xdata)) {
|
|
Packit Service |
e080da |
gf_msg_debug(this->name, 0,
|
|
Packit Service |
e080da |
"%s: xattr mismatch "
|
|
Packit Service |
e080da |
"for source(%d) vs (%d)",
|
|
Packit Service |
e080da |
uuid_utoa(replies[source].poststat.ia_gfid), source,
|
|
Packit Service |
e080da |
i);
|
|
Packit Service |
e080da |
sources[i] = 0;
|
|
Packit Service |
e080da |
healed_sinks[i] = 1;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
out:
|
|
Packit Service |
e080da |
afr_mark_active_sinks(this, sources, locked_on, healed_sinks);
|
|
Packit Service |
e080da |
return source;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
int
|
|
Packit Service |
e080da |
__afr_selfheal_metadata_prepare(call_frame_t *frame, xlator_t *this,
|
|
Packit Service |
e080da |
inode_t *inode, unsigned char *locked_on,
|
|
Packit Service |
e080da |
unsigned char *sources, unsigned char *sinks,
|
|
Packit Service |
e080da |
unsigned char *healed_sinks,
|
|
Packit Service |
e080da |
unsigned char *undid_pending,
|
|
Packit Service |
e080da |
struct afr_reply *replies, unsigned char *pflag)
|
|
Packit Service |
e080da |
{
|
|
Packit Service |
e080da |
int ret = -1;
|
|
Packit Service |
e080da |
int source = -1;
|
|
Packit Service |
e080da |
afr_private_t *priv = NULL;
|
|
Packit Service |
e080da |
int i = 0;
|
|
Packit Service |
e080da |
uint64_t *witness = NULL;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
priv = this->private;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = afr_selfheal_unlocked_discover(frame, inode, inode->gfid, replies);
|
|
Packit Service |
e080da |
if (ret)
|
|
Packit Service |
e080da |
return ret;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
witness = alloca0(sizeof(*witness) * priv->child_count);
|
|
Packit Service |
e080da |
ret = afr_selfheal_find_direction(frame, this, replies,
|
|
Packit Service |
e080da |
AFR_METADATA_TRANSACTION, locked_on,
|
|
Packit Service |
e080da |
sources, sinks, witness, pflag);
|
|
Packit Service |
e080da |
if (ret)
|
|
Packit Service |
e080da |
return ret;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
/* Initialize the healed_sinks[] array optimistically to
|
|
Packit Service |
e080da |
the intersection of to-be-healed (i.e sinks[]) and
|
|
Packit Service |
e080da |
the list of servers which are up (i.e locked_on[]).
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
As we encounter failures in the healing process, we
|
|
Packit Service |
e080da |
will unmark the respective servers in the healed_sinks[]
|
|
Packit Service |
e080da |
array.
|
|
Packit Service |
e080da |
*/
|
|
Packit Service |
e080da |
AFR_INTERSECT(healed_sinks, sinks, locked_on, priv->child_count);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
/* If any source has witness, pick first
|
|
Packit Service |
e080da |
* witness source and make everybody else sinks */
|
|
Packit Service |
e080da |
for (i = 0; i < priv->child_count; i++) {
|
|
Packit Service |
e080da |
if (sources[i] && witness[i]) {
|
|
Packit Service |
e080da |
source = i;
|
|
Packit Service |
e080da |
break;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (source != -1) {
|
|
Packit Service |
e080da |
for (i = 0; i < priv->child_count; i++) {
|
|
Packit Service |
e080da |
if (i != source && sources[i]) {
|
|
Packit Service |
e080da |
sources[i] = 0;
|
|
Packit Service |
e080da |
healed_sinks[i] = 1;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
source = __afr_selfheal_metadata_finalize_source(
|
|
Packit Service |
e080da |
frame, this, inode, sources, sinks, healed_sinks, undid_pending,
|
|
Packit Service |
e080da |
locked_on, replies);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (source < 0)
|
|
Packit Service |
e080da |
return -EIO;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
return source;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
int
|
|
Packit Service |
e080da |
afr_selfheal_metadata(call_frame_t *frame, xlator_t *this, inode_t *inode)
|
|
Packit Service |
e080da |
{
|
|
Packit Service |
e080da |
afr_private_t *priv = NULL;
|
|
Packit Service |
e080da |
int ret = -1;
|
|
Packit Service |
e080da |
unsigned char *sources = NULL;
|
|
Packit Service |
e080da |
unsigned char *sinks = NULL;
|
|
Packit Service |
e080da |
unsigned char *data_lock = NULL;
|
|
Packit Service |
e080da |
unsigned char *healed_sinks = NULL;
|
|
Packit Service |
e080da |
unsigned char *undid_pending = NULL;
|
|
Packit Service |
e080da |
struct afr_reply *locked_replies = NULL;
|
|
Packit Service |
e080da |
gf_boolean_t did_sh = _gf_true;
|
|
Packit Service |
e080da |
int source = -1;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
priv = this->private;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
sources = alloca0(priv->child_count);
|
|
Packit Service |
e080da |
sinks = alloca0(priv->child_count);
|
|
Packit Service |
e080da |
healed_sinks = alloca0(priv->child_count);
|
|
Packit Service |
e080da |
undid_pending = alloca0(priv->child_count);
|
|
Packit Service |
e080da |
data_lock = alloca0(priv->child_count);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
locked_replies = alloca0(sizeof(*locked_replies) * priv->child_count);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = afr_selfheal_inodelk(frame, this, inode, this->name, LLONG_MAX - 1, 0,
|
|
Packit Service |
e080da |
data_lock);
|
|
Packit Service |
e080da |
{
|
|
Packit Service |
35f350 |
if (ret < AFR_SH_MIN_PARTICIPANTS) {
|
|
Packit Service |
e080da |
ret = -ENOTCONN;
|
|
Packit Service |
e080da |
goto unlock;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = __afr_selfheal_metadata_prepare(
|
|
Packit Service |
e080da |
frame, this, inode, data_lock, sources, sinks, healed_sinks,
|
|
Packit Service |
e080da |
undid_pending, locked_replies, NULL);
|
|
Packit Service |
e080da |
if (ret < 0)
|
|
Packit Service |
e080da |
goto unlock;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
source = ret;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (AFR_COUNT(healed_sinks, priv->child_count) == 0) {
|
|
Packit Service |
e080da |
did_sh = _gf_false;
|
|
Packit Service |
e080da |
goto unlock;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = __afr_selfheal_metadata_do(frame, this, inode, source,
|
|
Packit Service |
e080da |
healed_sinks, locked_replies);
|
|
Packit Service |
e080da |
if (ret)
|
|
Packit Service |
e080da |
goto unlock;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
/* Restore atime/mtime for files that don't need data heal as
|
|
Packit Service |
e080da |
* restoring timestamps happens only as a part of data-heal.
|
|
Packit Service |
e080da |
*/
|
|
Packit Service |
e080da |
if (!IA_ISREG(locked_replies[source].poststat.ia_type))
|
|
Packit Service |
e080da |
afr_selfheal_restore_time(frame, this, inode, source, healed_sinks,
|
|
Packit Service |
e080da |
locked_replies);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = afr_selfheal_undo_pending(
|
|
Packit Service |
e080da |
frame, this, inode, sources, sinks, healed_sinks, undid_pending,
|
|
Packit Service |
e080da |
AFR_METADATA_TRANSACTION, locked_replies, data_lock);
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
unlock:
|
|
Packit Service |
e080da |
afr_selfheal_uninodelk(frame, this, inode, this->name, LLONG_MAX - 1, 0,
|
|
Packit Service |
e080da |
data_lock);
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (did_sh)
|
|
Packit Service |
e080da |
afr_log_selfheal(inode->gfid, this, ret, "metadata", source, sources,
|
|
Packit Service |
e080da |
healed_sinks);
|
|
Packit Service |
e080da |
else
|
|
Packit Service |
e080da |
ret = 1;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (locked_replies)
|
|
Packit Service |
e080da |
afr_replies_wipe(locked_replies, priv->child_count);
|
|
Packit Service |
e080da |
return ret;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
int
|
|
Packit Service |
e080da |
afr_selfheal_metadata_by_stbuf(xlator_t *this, struct iatt *stbuf)
|
|
Packit Service |
e080da |
{
|
|
Packit Service |
e080da |
inode_t *inode = NULL;
|
|
Packit Service |
e080da |
inode_t *link_inode = NULL;
|
|
Packit Service |
e080da |
call_frame_t *frame = NULL;
|
|
Packit Service |
e080da |
int ret = 0;
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
if (gf_uuid_is_null(stbuf->ia_gfid)) {
|
|
Packit Service |
e080da |
ret = -EINVAL;
|
|
Packit Service |
e080da |
goto out;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
inode = inode_new(this->itable);
|
|
Packit Service |
e080da |
if (!inode) {
|
|
Packit Service |
e080da |
ret = -ENOMEM;
|
|
Packit Service |
e080da |
goto out;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
link_inode = inode_link(inode, NULL, NULL, stbuf);
|
|
Packit Service |
e080da |
if (!link_inode) {
|
|
Packit Service |
e080da |
ret = -ENOMEM;
|
|
Packit Service |
e080da |
goto out;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
frame = afr_frame_create(this, &ret;;
|
|
Packit Service |
e080da |
if (!frame) {
|
|
Packit Service |
e080da |
ret = -ret;
|
|
Packit Service |
e080da |
goto out;
|
|
Packit Service |
e080da |
}
|
|
Packit Service |
e080da |
|
|
Packit Service |
e080da |
ret = afr_selfheal_metadata(frame, this, link_inode);
|
|
Packit Service |
e080da |
out:
|
|
Packit Service |
e080da |
if (inode)
|
|
Packit Service |
e080da |
inode_unref(inode);
|
|
Packit Service |
e080da |
if (link_inode)
|
|
Packit Service |
e080da |
inode_unref(link_inode);
|
|
Packit Service |
e080da |
if (frame)
|
|
Packit Service |
e080da |
AFR_STACK_DESTROY(frame);
|
|
Packit Service |
e080da |
return ret;
|
|
Packit Service |
e080da |
}
|