Client may flush and drop caps at the same time. If client need to
send cap reconnect before the caps get flushed. The issued caps in
the cap reconnect does not include the flushing caps. When choosing
lock states, MDS only consider the issued caps in cap reconnect, it
may choose wrong states.
Fixes: #11482
Signed-off-by: Yan, Zheng <zyan@redhat.com>
(cherry picked from commit
ce9a596dcaf95dd4af0a3a9e28871462a6bcb930)
}
}
-void CInode::choose_lock_states()
+void CInode::choose_lock_states(int dirty_caps)
{
- int issued = get_caps_issued();
+ int issued = get_caps_issued() | dirty_caps;
if (is_auth() && (issued & (CEPH_CAP_ANY_EXCL|CEPH_CAP_ANY_WR)) &&
choose_ideal_loner() >= 0)
try_set_loner();
// choose new lock state during recovery, based on issued caps
void choose_lock_state(SimpleLock *lock, int allissued);
- void choose_lock_states();
+ void choose_lock_states(int dirty_caps);
int count_nonstale_caps() {
int n = 0;
<< " op " << ceph_cap_op_name(m->get_op()) << dendl;
if (!mds->is_clientreplay() && !mds->is_active() && !mds->is_stopping()) {
+ if (mds->is_reconnect() &&
+ m->get_dirty() && m->get_client_tid() > 0 &&
+ session->have_completed_flush(m->get_client_tid())) {
+ mdcache->set_reconnect_dirty_caps(m->get_ino(), m->get_dirty());
+ }
mds->wait_for_replay(new C_MDS_RetryMessage(mds, m));
return;
}
if (in->is_auth() && !in->is_base() && in->inode.is_dirty_rstat())
in->mark_dirty_rstat();
- in->choose_lock_states();
+ int dirty_caps = 0;
+ map<inodeno_t, int>::iterator it = cap_imports_dirty.find(in->ino());
+ if (it != cap_imports_dirty.end())
+ dirty_caps = it->second;
+ in->choose_lock_states(dirty_caps);
dout(15) << " chose lock states on " << *in << dendl;
SnapRealm *realm = in->find_snaprealm();
}
cap_imports.clear();
+ cap_imports_dirty.clear();
if (warn_str.peek() != EOF) {
mds->clog->warn() << "failed to reconnect caps for missing inodes:" << "\n";
if (in->is_replicated()) {
mds->locker->try_eval(in, CEPH_CAP_LOCKS);
} else {
- in->choose_lock_states();
+ int dirty_caps = 0;
+ map<inodeno_t, int>::iterator it = cap_imports_dirty.find(in->ino());
+ if (it != cap_imports_dirty.end())
+ dirty_caps = it->second;
+ in->choose_lock_states(dirty_caps);
dout(15) << " chose lock states on " << *in << dendl;
}
}
map<inodeno_t,map<client_t,map<mds_rank_t,ceph_mds_cap_reconnect> > > cap_imports; // ino -> client -> frommds -> capex
map<inodeno_t,filepath> cap_import_paths;
+ map<inodeno_t,int> cap_imports_dirty;
set<inodeno_t> cap_imports_missing;
int cap_imports_num_opening;
assert(cap_imports[ino][client].size() == 1);
cap_imports.erase(ino);
}
+ void set_reconnect_dirty_caps(inodeno_t ino, int dirty) {
+ cap_imports_dirty[ino] |= dirty;
+ }
// [reconnect/rejoin caps]
map<CInode*,map<client_t, inodeno_t> > reconnected_caps; // inode -> client -> realmino