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: Sage Weil <sage@newdream.net>
This commit is contained in:
parent
42961d2333
commit
e8e1ba96b2
|
@ -584,10 +584,14 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm)
|
|||
if (lastinode)
|
||||
iput(lastinode);
|
||||
|
||||
dout("queue_realm_cap_snaps %p %llx children\n", realm, realm->ino);
|
||||
list_for_each_entry(child, &realm->children, child_item)
|
||||
queue_realm_cap_snaps(child);
|
||||
list_for_each_entry(child, &realm->children, child_item) {
|
||||
dout("queue_realm_cap_snaps %p %llx queue child %p %llx\n",
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -683,7 +687,9 @@ more:
|
|||
* queue cap snaps _after_ we've built the new snap contexts,
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue