When invalidating lock cache, current code detach lock cache from all
its locks immediately. So diri->filelock.is_cached() only tells us if
there is active (not being invalidated) lock cache on a dir.
But MDCache::path_traverse() and Server::_dir_is_nonempty_unlocked() use
diri->filelock.is_cached() to check if there is any lock cache on a dir.
This bug can result in processing async requests and normal requests out
of order.
The fix is detaching lock cache from its locks when lock cache is
completely invalidated .
Fixes: https://tracker.ceph.com/issues/44448
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
(cherry picked from commit
20d21cff89e1bb2bd6d7af311b4cc3272ce5fe65)
ceph_assert(lock_cache->invalidating);
+ lock_cache->detach_locks();
+
CInode *diri = lock_cache->get_dir_inode();
for (auto dir : lock_cache->auth_pinned_dirfrags) {
if (dir->get_inode() != diri)
ceph_assert(!lock_cache->client_cap);
} else {
lock_cache->invalidating = true;
- lock_cache->detach_all();
+ lock_cache->detach_dirfrags();
}
Capability *cap = lock_cache->client_cap;
void Locker::invalidate_lock_caches(SimpleLock *lock)
{
dout(10) << "invalidate_lock_caches " << *lock << " on " << *lock->get_parent() << dendl;
- while (lock->is_cached()) {
- invalidate_lock_cache(lock->get_first_cache());
+ if (lock->is_cached()) {
+ auto&& lock_caches = lock->get_active_caches();
+ for (auto& lc : lock_caches)
+ invalidate_lock_cache(lc);
}
}
}
}
-void MDLockCache::detach_all()
+void MDLockCache::detach_locks()
{
ceph_assert(items_lock);
int i = 0;
++i;
}
items_lock.reset();
+}
+void MDLockCache::detach_dirfrags()
+{
ceph_assert(items_dir);
- i = 0;
+ int i = 0;
for (auto dir : auth_pinned_dirfrags) {
(void)dir;
items_dir[i].item_dir.remove_myself();
void attach_locks();
void attach_dirfrags(std::vector<CDir*>&& dfv);
- void detach_all();
+ void detach_locks();
+ void detach_dirfrags();
CInode *diri;
Capability *client_cap;
}
}
-MDLockCache* SimpleLock::get_first_cache() {
+std::vector<MDLockCache*> SimpleLock::get_active_caches() {
+ std::vector<MDLockCache*> result;
if (have_more()) {
- auto& lock_caches = more()->lock_caches;
- if (!lock_caches.empty()) {
- return lock_caches.front()->parent;
+ for (auto it = more()->lock_caches.begin_use_current(); !it.end(); ++it) {
+ auto lock_cache = (*it)->parent;
+ if (!lock_cache->invalidating)
+ result.push_back(lock_cache);
}
}
- return nullptr;
+ return result;
}
}
void add_cache(MDLockCacheItem& item);
void remove_cache(MDLockCacheItem& item);
- MDLockCache* get_first_cache();
+ std::vector<MDLockCache*> get_active_caches();
// state
int get_state() const { return state; }