diff --git a/kmod/src/btree.c b/kmod/src/btree.c index 9e5effd0..104b4e54 100644 --- a/kmod/src/btree.c +++ b/kmod/src/btree.c @@ -324,6 +324,25 @@ static bool first_block_in_half(struct scoutfs_btree_ring *bring) return block == 0 || block == (le64_to_cpu(bring->nr_blocks) / 2); } +/* Set next_block to the start of the other half */ +static void advance_to_next_half(struct scoutfs_btree_ring *bring) +{ + u64 block = le64_to_cpu(bring->next_block); + u64 half = le64_to_cpu(bring->nr_blocks) / 2; + u64 offset; + + if (block >= half) { + offset = le64_to_cpu(bring->nr_blocks) - block; + block = 0; + } else { + offset = half - block; + block = half; + } + + bring->next_block = cpu_to_le64(block); + le64_add_cpu(&bring->next_seq, offset); +} + static size_t super_root_offsets[] = { offsetof(struct scoutfs_super_block, alloc_root), offsetof(struct scoutfs_super_block, manifest.root), @@ -334,6 +353,19 @@ static size_t super_root_offsets[] = { (root = ((void *)super + super_root_offsets[i]), 1);\ i++) +static bool all_roots_migrated(struct scoutfs_super_block *super) +{ + struct scoutfs_btree_root *root; + int i; + + for_each_super_root(super, i, root) { + if (root->migration_key_len) + return false; + } + + return true; +} + static int cmp_hdr_item_key(void *priv, const void *a_ptr, const void *b_ptr) { struct scoutfs_btree_block *bt = priv; @@ -711,10 +743,16 @@ retry: bti->old_dirtied++; /* wrap next block and increase next seq */ + le64_add_cpu(&bring->next_block, 1); + le64_add_cpu(&bring->next_seq, 1); + if (le64_to_cpu(bring->next_block) == le64_to_cpu(bring->nr_blocks)) bring->next_block = 0; - else - le64_add_cpu(&bring->next_block, 1); + + /* advance to the next half when asked and migration made it safe */ + if (all_roots_migrated(super) && + scoutfs_trigger(sb, BTREE_ADVANCE_RING_HALF)) + advance_to_next_half(bring); /* reset the migration keys if we've just entered a new half */ if (first_block_in_half(bring)) { @@ -725,8 +763,6 @@ retry: } } - le64_add_cpu(&bring->next_seq, 1); - mutex_unlock(&bti->mutex); if (bt) { diff --git a/kmod/src/triggers.c b/kmod/src/triggers.c index 67cef0e6..a94f2b65 100644 --- a/kmod/src/triggers.c +++ b/kmod/src/triggers.c @@ -39,6 +39,7 @@ struct scoutfs_triggers { static char *names[] = { [SCOUTFS_TRIGGER_BTREE_STALE_READ] = "btree_stale_read", + [SCOUTFS_TRIGGER_BTREE_ADVANCE_RING_HALF] = "btree_advance_ring_half", [SCOUTFS_TRIGGER_HARD_STALE_ERROR] = "hard_stale_error", [SCOUTFS_TRIGGER_SEG_STALE_READ] = "seg_stale_read", [SCOUTFS_TRIGGER_STATFS_LOCK_PURGE] = "statfs_lock_purge", diff --git a/kmod/src/triggers.h b/kmod/src/triggers.h index 900e433f..d1fa9e71 100644 --- a/kmod/src/triggers.h +++ b/kmod/src/triggers.h @@ -3,6 +3,7 @@ enum { SCOUTFS_TRIGGER_BTREE_STALE_READ, + SCOUTFS_TRIGGER_BTREE_ADVANCE_RING_HALF, SCOUTFS_TRIGGER_HARD_STALE_ERROR, SCOUTFS_TRIGGER_SEG_STALE_READ, SCOUTFS_TRIGGER_STATFS_LOCK_PURGE,