const static unsigned STATE_STALE = (1<<0);
const static unsigned STATE_NEW = (1<<1);
const static unsigned STATE_IMPORTING = (1<<2);
+ const static unsigned STATE_NEEDSNAPFLUSH = (1<<3);
Capability(CInode *i = NULL, uint64_t id = 0, client_t c = 0) :
bool is_importing() { return state & STATE_IMPORTING; }
void mark_importing() { state |= STATE_IMPORTING; }
void clear_importing() { state &= ~STATE_IMPORTING; }
+ bool need_snapflush() { return state & STATE_NEEDSNAPFLUSH; }
+ void mark_needsnapflush() { state |= STATE_NEEDSNAPFLUSH; }
+ void clear_needsnapflush() { state &= ~STATE_NEEDSNAPFLUSH; }
CInode *get_inode() { return inode; }
client_t get_client() const { return client; }
m->put();
return;
}
- if (mds->is_reconnect() &&
+ if ((mds->is_reconnect() || mds->get_want_state() == MDSMap::STATE_RECONNECT) &&
m->get_dirty() && m->get_client_tid() > 0 &&
!session->have_completed_flush(m->get_client_tid())) {
- mdcache->set_reconnected_dirty_caps(client, m->get_ino(), m->get_dirty());
+ mdcache->set_reconnected_dirty_caps(client, m->get_ino(), m->get_dirty(),
+ m->get_op() == CEPH_CAP_OP_FLUSHSNAP);
}
mds->wait_for_replay(new C_MDS_RetryMessage(mds, m));
return;
dout(10) << " revocation in progress, not making any conclusions about null snapflushes" << dendl;
}
}
+ if (cap->need_snapflush() && (m->flags & MClientCaps::FLAG_NO_CAPSNAP))
+ cap->clear_needsnapflush();
if (m->get_dirty() && in->is_auth()) {
dout(7) << " flush client." << client << " dirty " << ccap_string(m->get_dirty())
for (auto p : in->client_caps) {
client_t client = p.first;
Capability *cap = p.second;
- int issued = cap->issued();
+ int issued = cap->need_snapflush() ? CEPH_CAP_ANY_WR : cap->issued();
if ((issued & CEPH_CAP_ANY_WR) &&
cap->client_follows < last) {
// note in oldin
auto q = reconnected_caps.find(child->ino());
assert(q != reconnected_caps.end());
for (auto r = q->second.begin(); r != q->second.end(); ++r) {
- if (r->second.snap_follows > 0 && r->second.snap_follows < in->first - 1) {
- rebuild_need_snapflush(child, in->snaprealm, r->first, r->second.snap_follows);
+ if (r->second.snap_follows > 0) {
+ if (r->second.snap_follows < child->first - 1) {
+ rebuild_need_snapflush(child, in->snaprealm, r->first, r->second.snap_follows);
+ } else if (r->second.snapflush) {
+ // When processing a cap flush message that is re-sent, it's possble
+ // that the sender has already released all WR caps. So we should
+ // force MDCache::cow_inode() to setup CInode::client_need_snapflush.
+ Capability *cap = child->get_client_cap(r->first);
+ if (cap)
+ cap->mark_needsnapflush();
+ }
}
// make sure client's cap is in the correct snaprealm.
if (r->second.realm_ino != in->ino()) {
inodeno_t realm_ino;
snapid_t snap_follows;
int dirty_caps;
+ bool snapflush;
reconnected_cap_info_t() :
- realm_ino(0), snap_follows(0), dirty_caps(0) {}
+ realm_ino(0), snap_follows(0), dirty_caps(0), snapflush(false) {}
};
map<inodeno_t,map<client_t, reconnected_cap_info_t> > reconnected_caps; // inode -> client -> snap_follows,realmino
map<inodeno_t,map<client_t, snapid_t> > reconnected_snaprealms; // realmino -> client -> realmseq
info.realm_ino = inodeno_t(icr.capinfo.snaprealm);
info.snap_follows = icr.snap_follows;
}
- void set_reconnected_dirty_caps(client_t client, inodeno_t ino, int dirty) {
+ void set_reconnected_dirty_caps(client_t client, inodeno_t ino, int dirty, bool snapflush) {
reconnected_cap_info_t &info = reconnected_caps[ino][client];
info.dirty_caps |= dirty;
+ if (snapflush)
+ info.snapflush = snapflush;
}
void add_reconnected_snaprealm(client_t client, inodeno_t ino, snapid_t seq) {
reconnected_snaprealms[ino][client] = seq;