diff options
Diffstat (limited to 'xlators/cluster/afr')
-rw-r--r-- | xlators/cluster/afr/src/afr-dir-read.c | 192 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-common.c | 13 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-entry.c | 9 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr.c | 67 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr.h | 10 |
5 files changed, 281 insertions, 10 deletions
diff --git a/xlators/cluster/afr/src/afr-dir-read.c b/xlators/cluster/afr/src/afr-dir-read.c index fe1f4dadf73..3bfb29e5a0e 100644 --- a/xlators/cluster/afr/src/afr-dir-read.c +++ b/xlators/cluster/afr/src/afr-dir-read.c @@ -42,8 +42,173 @@ #include "common-utils.h" #include "compat-errno.h" #include "compat.h" +#include "checksum.h" #include "afr.h" +#include "afr-self-heal.h" + + +int +afr_examine_dir_completion_cbk (call_frame_t *frame, xlator_t *this) +{ + afr_local_t *local = NULL; + afr_self_heal_t *sh = NULL; + + local = frame->local; + sh = &local->self_heal; + + afr_set_opendir_done (this, local->fd->inode, 1); + + AFR_STACK_UNWIND (opendir, sh->orig_frame, local->op_ret, + local->op_errno, local->fd); + + return 0; +} + + +gf_boolean_t +__checksums_differ (uint32_t *checksum, int child_count) +{ + int ret = _gf_false; + int i = 0; + + uint32_t cksum; + + cksum = checksum[0]; + + while (i < child_count) { + if (cksum != checksum[i]) { + ret = _gf_true; + break; + } + + cksum = checksum[i]; + i++; + } + + return ret; +} + + +int32_t +afr_examine_dir_readdir_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno, + gf_dirent_t *entries) +{ + afr_private_t * priv = NULL; + afr_local_t * local = NULL; + + gf_dirent_t * entry = NULL; + gf_dirent_t * tmp = NULL; + + int child_index = 0; + + uint32_t entry_cksum; + + int call_count = 0; + off_t last_offset = 0; + + priv = this->private; + local = frame->local; + + child_index = (long) cookie; + + if (op_ret == -1) { + local->op_ret = -1; + goto out; + } + + if (op_ret == 0) + goto out; + + list_for_each_entry_safe (entry, tmp, &entries->list, list) { + entry_cksum = gf_rsync_weak_checksum (entry->d_name, + strlen (entry->d_name)); + local->cont.opendir.checksum[child_index] ^= entry_cksum; + } + + list_for_each_entry (entry, &entries->list, list) { + last_offset = entry->d_off; + } + + /* read more entries */ + + STACK_WIND_COOKIE (frame, afr_examine_dir_readdir_cbk, + (void *) (long) child_index, + priv->children[child_index], + priv->children[child_index]->fops->readdir, + local->fd, 131072, last_offset); + +out: + if ((op_ret == 0) || (op_ret == -1)) { + call_count = afr_frame_return (frame); + + if (call_count == 0) { + if (__checksums_differ (local->cont.opendir.checksum, + priv->child_count)) { + + local->need_entry_self_heal = _gf_true; + local->self_heal.forced_merge = _gf_true; + + local->cont.lookup.buf.st_mode = local->fd->inode->st_mode; + + local->child_count = afr_up_children_count (priv->child_count, + local->child_up); + + gf_log (this->name, GF_LOG_DEBUG, + "checksums of directory %s differ," + " triggering forced merge", + local->loc.path); + + afr_self_heal (frame, this, + afr_examine_dir_completion_cbk); + } else { + afr_set_opendir_done (this, local->fd->inode, 1); + + AFR_STACK_UNWIND (opendir, frame, local->op_ret, + local->op_errno, local->fd); + } + } + } + + return 0; +} + + +int +afr_examine_dir (call_frame_t *frame, xlator_t *this) +{ + afr_private_t * priv = NULL; + afr_local_t * local = NULL; + + int i; + int call_count = 0; + + local = frame->local; + priv = this->private; + + local->cont.opendir.checksum = CALLOC (priv->child_count, + sizeof (*local->cont.opendir.checksum)); + + call_count = afr_up_children_count (priv->child_count, local->child_up); + + local->call_count = call_count; + + for (i = 0; i < priv->child_count; i++) { + if (local->child_up[i]) { + STACK_WIND_COOKIE (frame, afr_examine_dir_readdir_cbk, + (void *) (long) i, + priv->children[i], + priv->children[i]->fops->readdir, + local->fd, 131072, 0); + + if (!--call_count) + break; + } + } + + return 0; +} int32_t @@ -69,8 +234,29 @@ afr_opendir_cbk (call_frame_t *frame, void *cookie, call_count = afr_frame_return (frame); if (call_count == 0) { - AFR_STACK_UNWIND (opendir, frame, local->op_ret, - local->op_errno, local->fd); + if ((local->op_ret == 0) && + !afr_is_opendir_done (this, fd->inode)) { + + /* + * This is the first opendir on this inode. We need + * to check if the directory's entries are the same + * on all subvolumes. This is needed in addition + * to regular entry self-heal because the readdir + * call is sent only to the first subvolume, and + * thus files that exist only there will never be healed + * otherwise (assuming changelog shows no anamolies). + */ + + gf_log (this->name, GF_LOG_TRACE, + "reading contents of directory %s looking for mismatch", + local->loc.path); + + afr_examine_dir (frame, this); + + } else { + AFR_STACK_UNWIND (opendir, frame, local->op_ret, + local->op_errno, local->fd); + } } return 0; @@ -108,6 +294,8 @@ afr_opendir (call_frame_t *frame, xlator_t *this, goto out; } + loc_copy (&local->loc, loc); + frame->local = local; local->fd = fd_ref (fd); diff --git a/xlators/cluster/afr/src/afr-self-heal-common.c b/xlators/cluster/afr/src/afr-self-heal-common.c index b23eea391be..8142bdf1de1 100644 --- a/xlators/cluster/afr/src/afr-self-heal-common.c +++ b/xlators/cluster/afr/src/afr-self-heal-common.c @@ -1382,10 +1382,12 @@ afr_local_t *afr_local_copy (afr_local_t *l, xlator_t *this) loc_copy (&lc->loc, &l->loc); lc->child_up = memdup (l->child_up, priv->child_count); - lc->xattr_req = dict_copy_with_ref (l->xattr_req, NULL); + if (l->xattr_req) + lc->xattr_req = dict_copy_with_ref (l->xattr_req, NULL); lc->cont.lookup.inode = l->cont.lookup.inode; - lc->cont.lookup.xattr = dict_copy_with_ref (l->cont.lookup.xattr, NULL); + if (l->cont.lookup.xattr) + lc->cont.lookup.xattr = dict_copy_with_ref (l->cont.lookup.xattr, NULL); return lc; } @@ -1502,7 +1504,12 @@ afr_self_heal (call_frame_t *frame, xlator_t *this, sh->background = _gf_true; sh->orig_frame = frame; - sh->completion_cbk = afr_bgsh_completion_cbk; + + if (completion_cbk == NULL) + sh->completion_cbk = afr_bgsh_completion_cbk; + else + sh->completion_cbk = completion_cbk; + sh->unwind = afr_bgsh_unwind; sh->buf = CALLOC (priv->child_count, sizeof (struct stat)); diff --git a/xlators/cluster/afr/src/afr-self-heal-entry.c b/xlators/cluster/afr/src/afr-self-heal-entry.c index d952865a18f..5c47d887e52 100644 --- a/xlators/cluster/afr/src/afr-self-heal-entry.c +++ b/xlators/cluster/afr/src/afr-self-heal-entry.c @@ -2317,6 +2317,11 @@ afr_sh_entry_fix (call_frame_t *frame, xlator_t *this) sh = &local->self_heal; priv = this->private; + if (sh->forced_merge) { + sh->source = -1; + goto heal; + } + afr_sh_build_pending_matrix (priv, sh->pending_matrix, sh->xattr, priv->child_count, AFR_ENTRY_TRANSACTION); @@ -2338,12 +2343,14 @@ afr_sh_entry_fix (call_frame_t *frame, xlator_t *this) priv->child_count); source = afr_sh_select_source (sh->sources, priv->child_count); - sh->source = source; + + sh->source = source; if (sh->background) { sh->unwind (frame, this); } +heal: afr_sh_entry_sync_prepare (frame, this); return 0; diff --git a/xlators/cluster/afr/src/afr.c b/xlators/cluster/afr/src/afr.c index c56ce314a07..a0441bfb0bd 100644 --- a/xlators/cluster/afr/src/afr.c +++ b/xlators/cluster/afr/src/afr.c @@ -55,9 +55,9 @@ #include "afr-self-heal.h" - -#define AFR_ICTX_SPLIT_BRAIN_MASK 0x0000000100000000ULL -#define AFR_ICTX_READ_CHILD_MASK 0x00000000FFFFFFFFULL +#define AFR_ICTX_OPENDIR_DONE_MASK 0x0000000200000000ULL +#define AFR_ICTX_SPLIT_BRAIN_MASK 0x0000000100000000ULL +#define AFR_ICTX_READ_CHILD_MASK 0x00000000FFFFFFFFULL uint64_t @@ -115,6 +115,60 @@ out: 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, int32_t opendir_done) +{ + 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; + } + + ctx = (~AFR_ICTX_OPENDIR_DONE_MASK & ctx) + | (opendir_done & AFR_ICTX_OPENDIR_DONE_MASK); + + __inode_ctx_put (inode, this, ctx); + } + UNLOCK (&inode->lock); +out: + return; +} + + +uint64_t afr_read_child (xlator_t *this, inode_t *inode) { int ret = 0; @@ -320,6 +374,11 @@ afr_local_cleanup (afr_local_t *local, xlator_t *this) { /* symlink */ FREE (local->cont.symlink.linkpath); } + + { /* opendir */ + if (local->cont.opendir.checksum) + FREE (local->cont.opendir.checksum); + } } @@ -642,7 +701,7 @@ unlock: lookup_buf->st_mode; } - afr_self_heal (frame, this, afr_self_heal_cbk); + afr_self_heal (frame, this, NULL); } else { AFR_STACK_UNWIND (lookup, frame, local->op_ret, local->op_errno, diff --git a/xlators/cluster/afr/src/afr.h b/xlators/cluster/afr/src/afr.h index 45a1c986348..bde151866bf 100644 --- a/xlators/cluster/afr/src/afr.h +++ b/xlators/cluster/afr/src/afr.h @@ -72,6 +72,10 @@ typedef struct _afr_private { } afr_private_t; typedef struct { + /* Is this a self-heal triggered to forcibly merge the + directories? */ + gf_boolean_t forced_merge; + /* array of stat's, one for each child */ struct stat *buf; struct stat parentbuf; @@ -273,6 +277,8 @@ typedef struct _afr_local { int success_count; int32_t op_ret; int32_t op_errno; + + uint32_t *checksum; } opendir; struct { @@ -546,7 +552,11 @@ afr_frame_return (call_frame_t *frame); void afr_set_split_brain (xlator_t *this, inode_t *inode, int32_t split_brain); +void +afr_set_opendir_done (xlator_t *this, inode_t *inode, int32_t opendir_done); +uint64_t +afr_is_opendir_done (xlator_t *this, inode_t *inode); #define AFR_STACK_UNWIND(fop, frame, params ...) \ do { \ |