diff options
| -rwxr-xr-x | tests/bugs/bug-907072.t | 46 | ||||
| -rw-r--r-- | xlators/cluster/dht/src/dht-selfheal.c | 32 | 
2 files changed, 74 insertions, 4 deletions
diff --git a/tests/bugs/bug-907072.t b/tests/bugs/bug-907072.t new file mode 100755 index 00000000000..49b477767ac --- /dev/null +++ b/tests/bugs/bug-907072.t @@ -0,0 +1,46 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../fileio.rc +. $(dirname $0)/../dht.rc + +cleanup; + +TEST glusterd; +TEST pidof glusterd; + +TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1,2,3}; +TEST $CLI volume start $V0; + +TEST glusterfs -s $H0 --volfile-id $V0 $M0; + +TEST mkdir $M0/test; + +OLD_LAYOUT0=`get_layout $B0/${V0}0/test`; +OLD_LAYOUT1=`get_layout $B0/${V0}1/test`; +OLD_LAYOUT2=`get_layout $B0/${V0}2/test`; +OLD_LAYOUT3=`get_layout $B0/${V0}3/test`; + +TEST killall glusterfsd; + +# Delete directory on one brick +TEST rm -rf $B0/${V}1/test; + +# And only layout xattr on another brick +TEST setfattr -x trusted.glusterfs.dht $B0/${V0}2/test; + +TEST $CLI volume start $V0 force; + +TEST umount $M0; +TEST glusterfs -s $H0 --volfile-id $V0 $M0; +TEST stat $M0/test; + +NEW_LAYOUT0=`get_layout $B0/${V0}0/test`; +NEW_LAYOUT1=`get_layout $B0/${V0}1/test`; +NEW_LAYOUT2=`get_layout $B0/${V0}2/test`; +NEW_LAYOUT3=`get_layout $B0/${V0}3/test`; + +EXPECT $OLD_LAYOUT0 echo $NEW_LAYOUT0; +EXPECT $OLD_LAYOUT1 echo $NEW_LAYOUT1; +EXPECT $OLD_LAYOUT2 echo $NEW_LAYOUT2; +EXPECT $OLD_LAYOUT3 echo $NEW_LAYOUT3; diff --git a/xlators/cluster/dht/src/dht-selfheal.c b/xlators/cluster/dht/src/dht-selfheal.c index b220a0e25ac..76ed26e1a72 100644 --- a/xlators/cluster/dht/src/dht-selfheal.c +++ b/xlators/cluster/dht/src/dht-selfheal.c @@ -564,9 +564,33 @@ dht_get_layout_count (xlator_t *this, dht_layout_t *layout, int new_layout)          for (i = 0; i < layout->cnt; i++) {                  err = layout->list[i].err; -                if (err == -1 || err == 0) { -                        layout->list[i].err = -1; +                if (err == -1 || err == 0 || err == ENOENT) { +			/* Setting list[i].err = -1 is an indication for +			   dht_selfheal_layout_new_directory() to assign +			   a range. We set it to -1 based on any one of +			   the three criteria: + +			   - err == -1 already, which means directory +			     existed but layout was not set on it. + +			   - err == 0, which means directory exists and +			     has an old layout piece which will be +			     overwritten now. + +			   - err == ENOENT, which means directory does +			     not exist (possibly racing with mkdir or +			     finishing half done mkdir). The missing +			     directory will be attempted to be recreated. + +			     It is important to note that it is safe +			     to race with mkdir() as self-heal and +			     mkdir are idempotent operations. Both will +			     strive to set the directory and layouts to +			     the same final state. +			*/                          count++; +			if (!err) +				layout->list[i].err = -1;                  }          } @@ -776,7 +800,7 @@ dht_selfheal_layout_new_directory (call_frame_t *frame, loc_t *loc,          DHT_RESET_LAYOUT_RANGE (layout);          for (i = start_subvol; i < layout->cnt; i++) {                  err = layout->list[i].err; -                if (err == -1) { +                if (err == -1 || err == ENOENT) {                          DHT_SET_LAYOUT_RANGE(layout, i, start, chunk,                                               cnt, loc->path);                          if (--cnt == 0) { @@ -789,7 +813,7 @@ dht_selfheal_layout_new_directory (call_frame_t *frame, loc_t *loc,          for (i = 0; i < start_subvol; i++) {                  err = layout->list[i].err; -                if (err == -1) { +                if (err == -1 || err == ENOENT) {                          DHT_SET_LAYOUT_RANGE(layout, i, start, chunk,                                               cnt, loc->path);                          if (--cnt == 0) {  | 
