scoutfs: don't advance btree after wrapping

The btree writes its blocks to a fixed ring of preallocated blocks.  We
added a trigger to force the index to advance to the next half of the
ring to test conditions where the cached btree blocks are out of date
with respect to the blocks on disk.

We have to be careful to only advance the index once all the live blocks
are migrated out of the half that we're about to advance to.  The
trigger tested that condition.

But it missed the case where the normal btree block allocation *just*
advanced into the next ring.  In this case the migration needs to occur
to make it safe to advance *again* to the previous half.  But it missed
this case because the migration keys are reset after we test the
trigger.

This resulted in leaving live btree blocks in the half that we advance
to and start overwriting.  The server got -ESTALE as it tried to read
through blocks that had been overwritten and hilarity ensued.

This precise condition of having the trigger fire just as we wrapped was
amazingly caught by scoutfs/505 in xfstests.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2018-06-29 14:42:06 -07:00
committed by Zach Brown
parent 345721c933
commit e227c6446e
+2 -2
View File
@@ -758,8 +758,8 @@ retry:
if (le64_to_cpu(bring->next_block) == le64_to_cpu(bring->nr_blocks))
bring->next_block = 0;
/* advance to the next half when asked and migration made it safe */
if (all_roots_migrated(super) &&
/* force advancing if migration's done and we didn't just wrap */
if (all_roots_migrated(super) && !first_block_in_half(bring) &&
scoutfs_trigger(sb, BTREE_ADVANCE_RING_HALF))
advance_to_next_half(bring);