diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2025-07-22 18:57:26 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2025-07-25 12:03:10 -0400 |
commit | 77058295d7c60e660f5253e743201b0e87add908 (patch) | |
tree | 07302e34c7caa119a2a9bcd17be50ce806438e46 | |
parent | f9d8f265859de4ff331960ea4f6dd385ff8dfedb (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.c | 38 |
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) || |