if (!revoking && unmounting && (cap_used == 0))
goto ack;
- if (wanted == cap->wanted && // mds knows what we want.
- ((cap->issued & ~retain) == 0) &&// and we don't have anything we wouldn't like
- !in->dirty_caps) // and we have no dirty caps
+ if ((cap->issued & ~retain) == 0 && // and we don't have anything we wouldn't like
+ !in->dirty_caps) // and we have no dirty caps
continue;
if (now < in->hold_caps_until) {
const int old_caps = cap->issued;
const int new_caps = m->get_caps();
+ const bool was_stale = session->cap_gen > cap->gen;
ldout(cct, 5) << "handle_cap_grant on in " << m->get_ino()
<< " mds." << mds << " seq " << m->get_seq()
<< " caps now " << ccap_string(new_caps)
}
bool check = false;
- if (m->get_op() == CEPH_CAP_OP_IMPORT && m->get_wanted() != wanted)
+ if ((was_stale || m->get_op() == CEPH_CAP_OP_IMPORT) &&
+ (wanted & ~(cap->wanted | new_caps))) {
+ // If mds is importing cap, prior cap messages that update 'wanted'
+ // may get dropped by mds (migrate seq mismatch).
+ //
+ // We don't send cap message to update 'wanted' if what we want are
+ // already issued. If mds revokes caps, cap message that releases caps
+ // also tells mds what we want. But if caps got revoked by mds forcedly
+ // (session stale). We may haven't told mds what we want.
check = true;
+ }
check_cap_issue(in, cap, new_caps);