scoutfs: more reliably set btree parent item bits

Most paths correctly calculated the bits to set in a parent item by
combining the bits set in the child with the half bit of the child
block's position in the ring.

With the exception of fixing up the parent item bits after descent by
walking the path.  This mistake caused the parent item half bits to be
zero and prevented migrating of blocks from the old half of the ring.

Fix it by introducing a helper function to calculate the parent ref item
bits and consistently using it.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2017-09-20 10:26:40 -07:00
committed by Mark Fasheh
parent 42b33d616e
commit 215ba7d4ad
+24 -15
View File
@@ -409,6 +409,18 @@ static u8 bits_from_counts(struct scoutfs_btree_block *bt)
return bits;
}
/*
* The bits set in a parent's ref item include the half bit for the
* child blkno so that we can search for blocks in a specific half of
* the ring.
*/
static u8 ref_item_bits(struct scoutfs_btree_ring *bring,
struct scoutfs_btree_block *child)
{
return bits_from_counts(child) |
half_bit(bring, le64_to_cpu(child->blkno));
}
/*
* Store the new bits and update the counts to match the difference from
* the previously set bits. Callers use this to keep item bits in sync
@@ -432,7 +444,6 @@ static void store_pos_bits(struct scoutfs_btree_block *bt, int pos, u8 bits)
bt->item_hdrs[pos].bits = bits;
}
/*
* The caller has descended through parents to a final block. Each
* block may have had item bits modified and counts updated but they
@@ -441,8 +452,9 @@ static void store_pos_bits(struct scoutfs_btree_block *bt, int pos, u8 bits)
* bits to the union of all the bits down through the path to the final
* block.
*/
static void path_repair_reset(struct btree_path *path)
static void path_repair_reset(struct super_block *sb, struct btree_path *path)
{
struct scoutfs_btree_ring *bring = &SCOUTFS_SB(sb)->super.bring;
struct scoutfs_btree_block *parent;
struct scoutfs_btree_block *bt;
u8 bits;
@@ -451,7 +463,7 @@ static void path_repair_reset(struct btree_path *path)
bt = path_pop(path, &pos);
while ((parent = path_pop(path, &pos))) {
bits = bits_from_counts(bt);
bits = ref_item_bits(bring, bt);
store_pos_bits(parent, pos, bits);
bt = parent;
}
@@ -898,8 +910,7 @@ static int get_parent_ref_block(struct super_block *sb, int flags,
ret = get_ref_block(sb, flags, ref, bt_ret);
if (ret == 0) {
bits = bits_from_counts(*bt_ret) |
half_bit(bring, le64_to_cpu(ref->blkno));
bits = ref_item_bits(bring, *bt_ret);
store_pos_bits(parent, pos, bits);
}
@@ -919,8 +930,7 @@ static void create_parent_item(struct scoutfs_btree_ring *bring,
.blkno = child->blkno,
.seq = child->seq,
};
u8 bits = bits_from_counts(child) |
half_bit(bring, le64_to_cpu(ref.blkno));
u8 bits = ref_item_bits(bring, child);
create_item(parent, pos, bits, key, key_len, &ref, sizeof(ref));
}
@@ -946,8 +956,7 @@ static void update_parent_bits(struct scoutfs_btree_ring *bring,
struct scoutfs_btree_block *parent,
unsigned pos, struct scoutfs_btree_block *child)
{
u8 bits = bits_from_counts(child) |
half_bit(bring, le64_to_cpu(child->blkno));
u8 bits = ref_item_bits(bring, child);
store_pos_bits(parent, pos, bits);
}
@@ -1284,7 +1293,7 @@ static int btree_walk(struct super_block *sb, struct scoutfs_btree_root *root,
return -EINVAL;
restart:
path_repair_reset(path);
path_repair_reset(sb, path);
put_btree_block(parent);
parent = NULL;
put_btree_block(bt);
@@ -1516,7 +1525,7 @@ int scoutfs_btree_insert(struct super_block *sb, struct scoutfs_btree_root *root
put_btree_block(bt);
}
path_repair_reset(&path);
path_repair_reset(sb, &path);
return ret;
}
@@ -1560,7 +1569,7 @@ int scoutfs_btree_update(struct super_block *sb, struct scoutfs_btree_root *root
put_btree_block(bt);
}
path_repair_reset(&path);
path_repair_reset(sb, &path);
return ret;
}
@@ -1598,7 +1607,7 @@ int scoutfs_btree_delete(struct super_block *sb, struct scoutfs_btree_root *root
put_btree_block(bt);
}
path_repair_reset(&path);
path_repair_reset(sb, &path);
return ret;
}
@@ -1737,7 +1746,7 @@ int scoutfs_btree_dirty(struct super_block *sb, struct scoutfs_btree_root *root,
put_btree_block(bt);
}
path_repair_reset(&path);
path_repair_reset(sb, &path);
return ret;
}
@@ -1815,7 +1824,7 @@ int scoutfs_btree_write_dirty(struct super_block *sb)
ret = btree_walk(sb, root, &path,
BTW_DIRTY | BTW_BIT | BTW_DIRTY_OLD,
NULL, 0, 0, bit, NULL, NULL, NULL);
path_repair_reset(&path);
path_repair_reset(sb, &path);
if (ret == -ENOENT) {
root = roots[next_root++];
continue;