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>

Sage Weil e8e1ba96 42961d23

+10 -4
+10 -4
fs/ceph/snap.c
··· 584 584 if (lastinode) 585 585 iput(lastinode); 586 586 587 - dout("queue_realm_cap_snaps %p %llx children\n", realm, realm->ino); 588 - list_for_each_entry(child, &realm->children, child_item) 589 - queue_realm_cap_snaps(child); 587 + list_for_each_entry(child, &realm->children, child_item) { 588 + dout("queue_realm_cap_snaps %p %llx queue child %p %llx\n", 589 + realm, realm->ino, child, child->ino); 590 + list_del_init(&child->dirty_item); 591 + list_add(&child->dirty_item, &realm->dirty_item); 592 + } 590 593 594 + list_del_init(&realm->dirty_item); 591 595 dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino); 592 596 } 593 597 ··· 687 683 * queue cap snaps _after_ we've built the new snap contexts, 688 684 * so that i_head_snapc can be set appropriately. 689 685 */ 690 - list_for_each_entry(realm, &dirty_realms, dirty_item) { 686 + while (!list_empty(&dirty_realms)) { 687 + realm = list_first_entry(&dirty_realms, struct ceph_snap_realm, 688 + dirty_item); 691 689 queue_realm_cap_snaps(realm); 692 690 } 693 691