Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8e1ba96 authored by Sage Weil's avatar Sage Weil
Browse files

ceph: queue cap_snaps once per realm



We were forming a dirty list, and then queueing cap_snaps for each realm
_and_ its children, regardless of whether the children were already in the
dirty list.  This meant we did it twice for some realms.  Which in turn
meant we corrupted mdsc->snap_flush_list when the cap_snap was re-added to
the list it was already on, and could trigger an infinite loop.

We were also using recursion to do reach all the children, a no-no when
stack is limited.

Instead, (re)queue any children on the dirty list, avoiding processing
anything twice and avoiding any recursion.

Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent 42961d23
Loading
Loading
Loading
Loading
+10 −4
Original line number Original line Diff line number Diff line
@@ -584,10 +584,14 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm)
	if (lastinode)
	if (lastinode)
		iput(lastinode);
		iput(lastinode);


	dout("queue_realm_cap_snaps %p %llx children\n", realm, realm->ino);
	list_for_each_entry(child, &realm->children, child_item) {
	list_for_each_entry(child, &realm->children, child_item)
		dout("queue_realm_cap_snaps %p %llx queue child %p %llx\n",
		queue_realm_cap_snaps(child);
		     realm, realm->ino, child, child->ino);
		list_del_init(&child->dirty_item);
		list_add(&child->dirty_item, &realm->dirty_item);
	}


	list_del_init(&realm->dirty_item);
	dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino);
	dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino);
}
}


@@ -683,7 +687,9 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc,
	 * queue cap snaps _after_ we've built the new snap contexts,
	 * queue cap snaps _after_ we've built the new snap contexts,
	 * so that i_head_snapc can be set appropriately.
	 * so that i_head_snapc can be set appropriately.
	 */
	 */
	list_for_each_entry(realm, &dirty_realms, dirty_item) {
	while (!list_empty(&dirty_realms)) {
		realm = list_first_entry(&dirty_realms, struct ceph_snap_realm,
					 dirty_item);
		queue_realm_cap_snaps(realm);
		queue_realm_cap_snaps(realm);
	}
	}