From 12f8b813b0118b13e0cdac15b19ba8a7e127730b Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 21 May 2019 17:50:25 +0800 Subject: [PATCH] mds: cleanup unneeded client_snap_caps when splitting snap inode Fixes: http://tracker.ceph.com/issues/39987 Signed-off-by: "Yan, Zheng" (cherry picked from commit df79944a773ee0d77babe343b0b7107d58e5a1cd) --- src/mds/CInode.cc | 17 +++++++++++------ src/mds/CInode.h | 2 +- src/mds/MDCache.cc | 41 +++++++++++++++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/mds/CInode.cc b/src/mds/CInode.cc index 97db2deb66dc6..f1c2682a0d220 100644 --- a/src/mds/CInode.cc +++ b/src/mds/CInode.cc @@ -335,23 +335,28 @@ void CInode::remove_need_snapflush(CInode *snapin, snapid_t snapid, client_t cli } } -bool CInode::split_need_snapflush(CInode *cowin, CInode *in) +pair CInode::split_need_snapflush(CInode *cowin, CInode *in) { dout(10) << __func__ << " [" << cowin->first << "," << cowin->last << "] for " << *cowin << dendl; - bool need_flush = false; - for (auto it = client_need_snapflush.lower_bound(cowin->first); - it != client_need_snapflush.end() && it->first < in->first; ) { + bool cowin_need_flush = false; + bool orig_need_flush = false; + auto it = client_need_snapflush.lower_bound(cowin->first); + while (it != client_need_snapflush.end() && it->first < in->first) { ceph_assert(!it->second.empty()); if (cowin->last >= it->first) { cowin->auth_pin(this); - need_flush = true; + cowin_need_flush = true; ++it; } else { it = client_need_snapflush.erase(it); } in->auth_unpin(this); } - return need_flush; + + if (it != client_need_snapflush.end() && it->first <= in->last) + orig_need_flush = true; + + return make_pair(cowin_need_flush, orig_need_flush); } void CInode::mark_dirty_rstat() diff --git a/src/mds/CInode.h b/src/mds/CInode.h index d609ab3037c25..2c48e3b2d9969 100644 --- a/src/mds/CInode.h +++ b/src/mds/CInode.h @@ -631,7 +631,7 @@ class CInode : public MDSCacheObject, public InodeStoreBase, public Counter split_need_snapflush(CInode *cowin, CInode *in); protected: diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index 5417ca2225351..5b6770689508d 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -1465,19 +1465,41 @@ CInode *MDCache::cow_inode(CInode *in, snapid_t last) if (in->last != CEPH_NOSNAP) { CInode *head_in = get_inode(in->ino()); ceph_assert(head_in); - if (head_in->split_need_snapflush(oldin, in)) { + auto ret = head_in->split_need_snapflush(oldin, in); + if (ret.first) { oldin->client_snap_caps = in->client_snap_caps; - for (const auto &p : in->client_snap_caps) { + for (const auto &p : oldin->client_snap_caps) { SimpleLock *lock = oldin->get_lock(p.first); ceph_assert(lock); for (const auto &q : p.second) { - oldin->auth_pin(lock); - lock->set_state(LOCK_SNAP_SYNC); // gathering + if (lock->get_state() != LOCK_SNAP_SYNC) { + ceph_assert(lock->is_stable()); + lock->set_state(LOCK_SNAP_SYNC); // gathering + oldin->auth_pin(lock); + } lock->get_wrlock(true); - (void)q; /* unused */ + (void)q; /* unused */ } } } + if (!ret.second) { + auto client_snap_caps = std::move(in->client_snap_caps); + in->client_snap_caps.clear(); + in->item_open_file.remove_myself(); + in->item_caps.remove_myself(); + for (const auto &p : client_snap_caps) { + SimpleLock *lock = in->get_lock(p.first); + ceph_assert(lock); + ceph_assert(lock->get_state() == LOCK_SNAP_SYNC); // gathering + for (const auto &q : p.second) { + lock->put_wrlock(); + (void)q; /* unused */ + } + ceph_assert(!lock->get_num_wrlocks()); + lock->set_state(LOCK_SYNC); + in->auth_unpin(lock); + } + } return oldin; } @@ -1496,10 +1518,13 @@ CInode *MDCache::cow_inode(CInode *in, snapid_t last) int lockid = cinode_lock_info[i].lock; SimpleLock *lock = oldin->get_lock(lockid); ceph_assert(lock); - oldin->client_snap_caps[lockid].insert(client); - oldin->auth_pin(lock); - lock->set_state(LOCK_SNAP_SYNC); // gathering + if (lock->get_state() != LOCK_SNAP_SYNC) { + ceph_assert(lock->is_stable()); + lock->set_state(LOCK_SNAP_SYNC); // gathering + oldin->auth_pin(lock); + } lock->get_wrlock(true); + oldin->client_snap_caps[lockid].insert(client); dout(10) << " client." << client << " cap " << ccap_string(issued & cinode_lock_info[i].wr_caps) << " wrlock lock " << *lock << " on " << *oldin << dendl; }