summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2025-07-22 18:57:26 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2025-07-25 12:03:10 -0400
commit77058295d7c60e660f5253e743201b0e87add908 (patch)
tree07302e34c7caa119a2a9bcd17be50ce806438e46
parentf9d8f265859de4ff331960ea4f6dd385ff8dfedb (diff)
bcachefs: live_child() no longer uses recursion
We already had helpers for doing a snapshot tree walk without recursion - this fixes a stack overflow for a user with lots of snapshots. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/snapshot.c38
1 files changed, 11 insertions, 27 deletions
diff --git a/fs/bcachefs/snapshot.c b/fs/bcachefs/snapshot.c
index 8c24e2a93041..5370ccb85d2d 100644
--- a/fs/bcachefs/snapshot.c
+++ b/fs/bcachefs/snapshot.c
@@ -1431,40 +1431,24 @@ static inline u32 interior_delete_has_id(interior_delete_list *l, u32 id)
return i ? i->live_child : 0;
}
-static unsigned __live_child(struct snapshot_table *t, u32 id,
- snapshot_id_list *delete_leaves,
- interior_delete_list *delete_interior)
+static unsigned live_child(struct bch_fs *c, u32 start)
{
- struct snapshot_t *s = __snapshot_t(t, id);
- if (!s)
- return 0;
+ struct snapshot_delete *d = &c->snapshot_delete;
- for (unsigned i = 0; i < ARRAY_SIZE(s->children); i++)
- if (s->children[i] &&
- !snapshot_list_has_id(delete_leaves, s->children[i]) &&
- !interior_delete_has_id(delete_interior, s->children[i]))
- return s->children[i];
+ guard(rcu)();
+ struct snapshot_table *t = rcu_dereference(c->snapshots);
- for (unsigned i = 0; i < ARRAY_SIZE(s->children); i++) {
- u32 live_child = s->children[i]
- ? __live_child(t, s->children[i], delete_leaves, delete_interior)
- : 0;
- if (live_child)
- return live_child;
- }
+ for (u32 id = bch2_snapshot_tree_next(t, start);
+ id && id != start;
+ id = bch2_snapshot_tree_next(t, id))
+ if (bch2_snapshot_is_leaf(c, id) &&
+ !snapshot_list_has_id(&d->delete_leaves, id) &&
+ !interior_delete_has_id(&d->delete_interior, id))
+ return id;
return 0;
}
-static unsigned live_child(struct bch_fs *c, u32 id)
-{
- struct snapshot_delete *d = &c->snapshot_delete;
-
- guard(rcu)();
- return __live_child(rcu_dereference(c->snapshots), id,
- &d->delete_leaves, &d->delete_interior);
-}
-
static bool snapshot_id_dying(struct snapshot_delete *d, unsigned id)
{
return snapshot_list_has_id(&d->delete_leaves, id) ||