diff options
| author | Ravishankar N <ravishankar@redhat.com> | 2014-09-03 20:49:53 +0000 | 
|---|---|---|
| committer | Pranith Kumar Karampuri <pkarampu@redhat.com> | 2014-09-05 22:19:33 -0700 | 
| commit | 15a2088da508539a292f2a1863377dc40d264c8c (patch) | |
| tree | ed4d10aa233ff14f901a5071cbad994fd20303c5 | |
| parent | d2600dfda2b8f87b5f08d96abfb2abc0677151e0 (diff) | |
cluster/afr: perform list-xattr during lookup
Detect and heal mismatching user extended attributes during lookup.
'Forward' port of http://review.gluster.org/#/c/7444/
Change-Id: Id03c9746f083ffd3014711d0b3a2e5a71a45eed4
BUG: 1134691
Signed-off-by: Ravishankar N <ravishankar@redhat.com>
Reviewed-on: http://review.gluster.org/8558
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
Tested-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
| -rw-r--r-- | tests/bugs/bug-1130892.t | 2 | ||||
| -rw-r--r-- | tests/bugs/bug-1134691-afr-lookup-metadata-heal.t | 50 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-common.c | 198 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-metadata.c | 30 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-self-heal.h | 2 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr.h | 3 | 
6 files changed, 273 insertions, 12 deletions
diff --git a/tests/bugs/bug-1130892.t b/tests/bugs/bug-1130892.t index 438e795d571..206778f2938 100644 --- a/tests/bugs/bug-1130892.t +++ b/tests/bugs/bug-1130892.t @@ -49,7 +49,7 @@ TEST stat $M0/one  # Check pending xattrs  EXPECT "00000000" afr_get_specific_changelog_xattr $B0/${V0}-0/one trusted.afr.$V0-client-1 data  EXPECT_NOT "00000000" afr_get_specific_changelog_xattr $B0/${V0}-0/one trusted.afr.$V0-client-1 entry -EXPECT_NOT "00000000" afr_get_specific_changelog_xattr $B0/${V0}-0/one trusted.afr.$V0-client-1 metadata +EXPECT "00000000" afr_get_specific_changelog_xattr $B0/${V0}-0/one trusted.afr.$V0-client-1 metadata  TEST gluster volume set $V0 self-heal-daemon on  EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status diff --git a/tests/bugs/bug-1134691-afr-lookup-metadata-heal.t b/tests/bugs/bug-1134691-afr-lookup-metadata-heal.t new file mode 100644 index 00000000000..1fb1732a33f --- /dev/null +++ b/tests/bugs/bug-1134691-afr-lookup-metadata-heal.t @@ -0,0 +1,50 @@ +#!/bin/bash +#### Test iatt and user xattr heal from lookup code path #### + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/brick{0,1,2} +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 + +cd $M0 +TEST touch file +TEST setfattr -n user.attribute1 -v "value" $B0/brick0/file +TEST kill_brick $V0 $H0 $B0/brick2 +TEST chmod +x file +iatt=$(stat -c "%g:%u:%A" file) + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 + +#Trigger metadataheal +TEST stat file + +#iattrs must be matching +iatt1=$(stat -c "%g:%u:%A" $B0/brick0/file) +iatt2=$(stat -c "%g:%u:%A" $B0/brick1/file) +iatt3=$(stat -c "%g:%u:%A" $B0/brick2/file) +EXPECT $iatt echo $iatt1 +EXPECT $iatt echo $iatt2 +EXPECT $iatt echo $iatt3 + +#xattrs must be matching +xatt1_cnt=$(getfattr -d $B0/brick0/file|wc|awk '{print $1}') +xatt2_cnt=$(getfattr -d $B0/brick1/file|wc|awk '{print $1}') +xatt3_cnt=$(getfattr -d $B0/brick2/file|wc|awk '{print $1}') +EXPECT "$xatt1_cnt" echo $xatt2_cnt +EXPECT "$xatt1_cnt" echo $xatt3_cnt + +#changelogs must be zero +xattr1=$(get_hex_xattr trusted.afr.$V0-client-2 $B0/brick0/file) +xattr2=$(get_hex_xattr trusted.afr.$V0-client-2 $B0/brick1/file) +EXPECT "000000000000000000000000" echo $xattr1 +EXPECT "000000000000000000000000" echo $xattr2 + +cd - +cleanup; diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c index e9a05de2546..f290c1f8d1c 100644 --- a/xlators/cluster/afr/src/afr-common.c +++ b/xlators/cluster/afr/src/afr-common.c @@ -670,6 +670,12 @@ afr_xattr_req_prepare (xlator_t *this, dict_t *xattr_req)                          "query flag");          } +        ret = dict_set_int32 (xattr_req, "list-xattr", 1); +        if (ret) { +                gf_log (this->name, GF_LOG_DEBUG, +                        "Unable to set list-xattr in dict "); +        } +  	return ret;  } @@ -1140,6 +1146,73 @@ afr_handle_quota_size (call_frame_t *frame, xlator_t *this)  	}  } +static char *afr_ignore_xattrs[] = { +        GLUSTERFS_OPEN_FD_COUNT, +        GLUSTERFS_PARENT_ENTRYLK, +        GLUSTERFS_ENTRYLK_COUNT, +        GLUSTERFS_INODELK_COUNT, +        GF_SELINUX_XATTR_KEY, +        QUOTA_SIZE_KEY, +        NULL +}; + +static  gf_boolean_t +afr_lookup_xattr_ignorable (char *key) +{ +        int i = 0; + +        if (!strncmp (key, AFR_XATTR_PREFIX, strlen(AFR_XATTR_PREFIX))) +                return _gf_true; +        for (i = 0; afr_ignore_xattrs[i]; i++) { +                if (!strcmp (key, afr_ignore_xattrs[i])) +                       return _gf_true; +        } +        return _gf_false; +} + +int +xattr_is_equal (dict_t *this, char *key1, data_t *value1, void *data) +{ +        dict_t *xattr2 = (dict_t *)data; +        data_t *value2 = NULL; + +        if (afr_lookup_xattr_ignorable (key1)) +                return 0; + +        value2 = dict_get (xattr2, key1); +        if (!value2) +                return -1; + +        if (value1->len != value2->len) +                return -1; +        if(memcmp(value1->data, value2->data, value1->len)) +                return -1; +        else +                return 0; + +} + +/* To conclude that both dicts are equal, we need to check if + * 1) For every key-val pair in dict1, a match is present in dict2 + * 2) For every key-val pair in dict2, a match is present in dict1 + * We need to do both because ignoring glusterfs' internal xattrs + * happens only in xattr_is_equal(). + */ +static gf_boolean_t +dicts_are_equal (dict_t *dict1, dict_t *dict2) +{ +        int ret = 0; + +        ret = dict_foreach (dict1, xattr_is_equal, dict2); +        if (ret == -1) +                return _gf_false; + +        ret = dict_foreach (dict2, xattr_is_equal, dict1); +        if (ret == -1) +                 return _gf_false; + +        return _gf_true; +}  static void  afr_lookup_done (call_frame_t *frame, xlator_t *this) @@ -1437,6 +1510,121 @@ afr_attempt_local_discovery (xlator_t *this, int32_t child_index)                             &tmploc, GF_XATTR_PATHINFO_KEY, NULL);  } +int +afr_lookup_sh_metadata_wrap (void *opaque) +{ +        call_frame_t *frame       = opaque; +        afr_local_t  *local       = NULL; +        xlator_t     *this        = NULL; +        inode_t      *inode       = NULL; +        afr_private_t *priv       = NULL; +        struct afr_reply *replies = NULL; +        int i= 0, first = -1; + +        local = frame->local; +        this  = frame->this; +        priv  = this->private; +        replies = local->replies; + +        for (i =0; i < priv->child_count; i++) { +                if(!replies[i].valid || replies[i].op_ret == -1) +                        continue; +                first = i; +                break; +        } +        if (first == -1) +                goto out; + +        inode = afr_inode_link (local->inode,&replies[first].poststat); +        if(!inode) +                goto out; + +        afr_selfheal_metadata (frame, this, inode); +        inode_forget (inode, 1); +        inode_unref (inode); + +        afr_local_replies_wipe (local, this->private); +        inode = afr_selfheal_unlocked_lookup_on (frame, local->loc.parent, +                                                 local->loc.name, local->replies, +                                                 local->child_up, NULL); +        if (inode) +                inode_unref (inode); +out: +        afr_lookup_done (frame, this); + +        return 0; +} + +static gf_boolean_t +afr_can_start_metadata_self_heal(call_frame_t *frame, xlator_t *this) +{ +        afr_local_t *local = NULL; +        afr_private_t *priv = NULL; +        struct afr_reply *replies = NULL; +        int i = 0, first = -1; +        gf_boolean_t start = _gf_false; +        struct iatt stbuf = {0, }; + +        local = frame->local; +        replies = local->replies; +        priv = this->private; + +        for (i = 0; i < priv->child_count; i++) { +                if(!replies[i].valid || replies[i].op_ret == -1) +                        continue; +                if (first == -1) { +                        first = i; +                        stbuf = replies[i].poststat; +                        continue; +                } + +                if (uuid_compare (stbuf.ia_gfid, replies[i].poststat.ia_gfid)) { +                        start = _gf_false; +                        break; +                } +                if (!IA_EQUAL (stbuf, replies[i].poststat, type)) { +                        start = _gf_false; +                        break; +                } + +                /*Check if iattrs need heal*/ +                if ((!IA_EQUAL (stbuf, replies[i].poststat, uid)) || +                    (!IA_EQUAL (stbuf, replies[i].poststat, gid)) || +                    (!IA_EQUAL (stbuf, replies[i].poststat, prot))) { +                        start = _gf_true; +                        continue; +                } + +                /*Check if xattrs need heal*/ +                if (!dicts_are_equal (replies[first].xdata, replies[i].xdata)) +                        start = _gf_true; +        } + +        return start; +} + +int +afr_lookup_metadata_heal_check (call_frame_t *frame, xlator_t *this) + +{ +        call_frame_t *heal = NULL; +        int ret            = 0; + +        if (!afr_can_start_metadata_self_heal (frame, this)) +                goto out; + +        heal = copy_frame (frame); +        if (heal) +                heal->root->pid = GF_CLIENT_PID_AFR_SELF_HEALD; +        ret = synctask_new (this->ctx->env, afr_lookup_sh_metadata_wrap, +                            afr_refresh_selfheal_done, heal, frame); +        if(ret) +                goto out; +        return ret; +out: +        afr_lookup_done (frame, this); +        return ret; +}  int  afr_lookup_selfheal_wrap (void *opaque) @@ -1463,7 +1651,7 @@ afr_lookup_selfheal_wrap (void *opaque)  	if (inode)  		inode_unref (inode); -	afr_lookup_done (frame, this); +        afr_lookup_metadata_heal_check(frame, this);          return 0;  unwind: @@ -1519,11 +1707,11 @@ afr_lookup_entry_heal (call_frame_t *frame, xlator_t *this)  		ret = synctask_new (this->ctx->env, afr_lookup_selfheal_wrap,  				    afr_refresh_selfheal_done, heal, frame);  		if (ret) -			goto lookup_done; -	} else { -	lookup_done: -		afr_lookup_done (frame, this); +			goto metadata_heal; +                return ret;  	} +metadata_heal: +        ret = afr_lookup_metadata_heal_check (frame, this);  	return ret;  } diff --git a/xlators/cluster/afr/src/afr-self-heal-metadata.c b/xlators/cluster/afr/src/afr-self-heal-metadata.c index dc7825d3d16..e98728ba54f 100644 --- a/xlators/cluster/afr/src/afr-self-heal-metadata.c +++ b/xlators/cluster/afr/src/afr-self-heal-metadata.c @@ -82,12 +82,12 @@ __afr_selfheal_metadata_do (call_frame_t *frame, xlator_t *this, inode_t *inode,  /* - * Look for mismatching uid/gid or mode even if xattrs don't say so, and - * pick one arbitrarily as winner. - */ + * Look for mismatching uid/gid or mode or user xattrs even if + * AFR xattrs don't say so, and pick one arbitrarily as winner. */  static int -__afr_selfheal_metadata_finalize_source (xlator_t *this, unsigned char *sources, +__afr_selfheal_metadata_finalize_source (call_frame_t *frame, xlator_t *this, +                                         unsigned char *sources,  					 unsigned char *healed_sinks,  					 unsigned char *locked_on,  					 struct afr_reply *replies) @@ -97,6 +97,7 @@ __afr_selfheal_metadata_finalize_source (xlator_t *this, unsigned char *sources,  	struct iatt first = {0, };  	int source = -1;  	int sources_count = 0; +        int ret = 0;  	priv = this->private; @@ -124,11 +125,12 @@ __afr_selfheal_metadata_finalize_source (xlator_t *this, unsigned char *sources,  		if (source == -1) {  			source = i;  			first = replies[i].poststat; +                        break;  		}  	}  	for (i = 0; i < priv->child_count; i++) { -		if (!sources[i]) +		if (!sources[i] || i == source)  			continue;  		if (!IA_EQUAL (first, replies[i].poststat, type) ||  		    !IA_EQUAL (first, replies[i].poststat, uid) || @@ -139,6 +141,22 @@ __afr_selfheal_metadata_finalize_source (xlator_t *this, unsigned char *sources,  		}  	} +        for (i =0; i < priv->child_count; i++) { +		if (!sources[i] || i == source) +			continue; +                if (replies[source].xdata->count != replies[i].xdata->count) { +                        sources[i] = 0; +                        healed_sinks[i] = 1; +                        continue; +                } +                ret = dict_foreach(replies[source].xdata, xattr_is_equal, +                                        (void*)replies[i].xdata); +                if  (ret == -1) { +                        sources[i] = 0; +                        healed_sinks[i] = 1; +                } +        } +  	return source;  } @@ -176,7 +194,7 @@ __afr_selfheal_metadata_prepare (call_frame_t *frame, xlator_t *this, inode_t *i          */          AFR_INTERSECT (healed_sinks, sinks, locked_on, priv->child_count); -	source = __afr_selfheal_metadata_finalize_source (this, sources, +	source = __afr_selfheal_metadata_finalize_source (frame, this, sources,                                                            healed_sinks,  							  locked_on, replies);  	if (source < 0) diff --git a/xlators/cluster/afr/src/afr-self-heal.h b/xlators/cluster/afr/src/afr-self-heal.h index 2713ffa09bf..31f12a4e74a 100644 --- a/xlators/cluster/afr/src/afr-self-heal.h +++ b/xlators/cluster/afr/src/afr-self-heal.h @@ -179,4 +179,6 @@ afr_selfheal_newentry_mark (call_frame_t *frame, xlator_t *this, inode_t *inode,                              int source, struct afr_reply *replies,                              unsigned char *sources, unsigned char *newentry); +inode_t* +afr_inode_link (inode_t *inode, struct iatt *iatt);  #endif /* !_AFR_SELFHEAL_H */ diff --git a/xlators/cluster/afr/src/afr.h b/xlators/cluster/afr/src/afr.h index 4adbd5d5c83..c8224e16ab7 100644 --- a/xlators/cluster/afr/src/afr.h +++ b/xlators/cluster/afr/src/afr.h @@ -776,6 +776,9 @@ int32_t  afr_notify (xlator_t *this, int32_t event, void *data, void *data2);  int +xattr_is_equal (dict_t *this, char *key1, data_t *value1, void *data); + +int  afr_init_entry_lockee (afr_entry_lockee_t *lockee, afr_local_t *local,                         loc_t *loc, char *basename, int child_count);  | 
