Skip to content
Permalink
Browse files
ceph: eliminate the recursion when rebuilding the snap context
Use a list instead of recursion to avoid possible stack overflow.

Signed-off-by: Xiubo Li <xiubli@redhat.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
  • Loading branch information
lxbsz authored and jtlayton committed Feb 16, 2022
1 parent ed89258 commit 7c7e63bc9910b15ffd1f791838ff0a919058f97c
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 9 deletions.
@@ -320,7 +320,8 @@ static int cmpu64_rev(const void *a, const void *b)
* build the snap context for a given realm.
*/
static int build_snap_context(struct ceph_snap_realm *realm,
struct list_head* dirty_realms)
struct list_head *realm_queue,
struct list_head *dirty_realms)
{
struct ceph_snap_realm *parent = realm->parent;
struct ceph_snap_context *snapc;
@@ -334,9 +335,9 @@ static int build_snap_context(struct ceph_snap_realm *realm,
*/
if (parent) {
if (!parent->cached_context) {
err = build_snap_context(parent, dirty_realms);
if (err)
goto fail;
/* add to the queue head */
list_add(&parent->rebuild_item, realm_queue);
return 1;
}
num += parent->cached_context->num_snaps;
}
@@ -420,13 +421,38 @@ static int build_snap_context(struct ceph_snap_realm *realm,
static void rebuild_snap_realms(struct ceph_snap_realm *realm,
struct list_head *dirty_realms)
{
struct ceph_snap_realm *child;
LIST_HEAD(realm_queue);
int last = 0;

dout("rebuild_snap_realms %llx %p\n", realm->ino, realm);
build_snap_context(realm, dirty_realms);
list_add_tail(&realm->rebuild_item, &realm_queue);

list_for_each_entry(child, &realm->children, child_item)
rebuild_snap_realms(child, dirty_realms);
while (!list_empty(&realm_queue)) {
struct ceph_snap_realm *_realm, *child;

/*
* If the last building failed dues to memory
* issue, just empty the realm_queue and return
* to avoid infinite loop.
*/
if (last < 0) {
list_del(&_realm->rebuild_item);
continue;
}

_realm = list_first_entry(&realm_queue,
struct ceph_snap_realm,
rebuild_item);
last = build_snap_context(_realm, &realm_queue, dirty_realms);
dout("rebuild_snap_realms %llx %p, %s\n", _realm->ino, _realm,
last > 0 ? "is deferred" : !last ? "succeeded" : "failed");

list_for_each_entry(child, &_realm->children, child_item)
list_add_tail(&child->rebuild_item, &realm_queue);

/* last == 1 means need to build parent first */
if (last <= 0)
list_del(&_realm->rebuild_item);
}
}


@@ -885,6 +885,8 @@ struct ceph_snap_realm {

struct list_head dirty_item; /* if realm needs new context */

struct list_head rebuild_item; /* rebuild snap realms _downward_ in hierarchy */

/* the current set of snaps for this realm */
struct ceph_snap_context *cached_context;

0 comments on commit 7c7e63b

Please sign in to comment.