@@ -142,13 +142,11 @@ public:
_pending = c;
_issued |= c;
} else if (~_pending & c) {
- // adding bits only. remove obsolete revocations?
+ // note prior caps if there are pending revocations
+ if (!_revokes.empty())
+ _revokes.push_back(revoke_info(_pending, last_sent, last_issue));
_pending |= c;
_issued |= c;
- // drop old _revokes with no bits we don't have
- while (!_revokes.empty() &&
- (_revokes.back().before & ~_pending) == 0)
- _revokes.pop_back();
} else {
// no change.
assert(_pending == c);
@@ -169,16 +167,42 @@ public:
for (list<revoke_info>::iterator p = _revokes.begin(); p != _revokes.end(); ++p)
_issued |= p->before;
}
+ void _update_revokes(ceph_seq_t seq, unsigned caps) {
+ // can i forget any revocations?
+ while (!_revokes.empty() && _revokes.front().seq < seq)
+ _revokes.pop_front();
+
+ if (!_revokes.empty() && _revokes.front().seq == seq) {
+ list<revoke_info>::iterator p = _revokes.begin();
+ unsigned prev_pending = p->before;
+ p->before = caps;
+ // client actively released caps?
+ unsigned release = prev_pending & ~caps;
+ if (release) {
+ for (++p; p != _revokes.end(); ++p) {
+ // we issued new caps to client?
+ release &= prev_pending | ~(p->before);
+ if (release == 0)
+ break;
+ prev_pending = p->before;
+ p->before &= ~release;
+ }
+ if (release) {
+ // we issued new caps to client?
+ release &= prev_pending | ~_pending;
+ _pending &= ~release;
+ }
+ }
+ }
+ }
void confirm_receipt(ceph_seq_t seq, unsigned caps) {
if (seq == last_sent) {
- _pending = caps;
_revokes.clear();
_issued = caps;
+ // don't add bits
+ _pending &= caps;
} else {
- // can i forget any revocations?
- while (!_revokes.empty() &&
- _revokes.front().seq <= seq)
- _revokes.pop_front();
+ _update_revokes(seq, caps);
_calc_issued();
}
//check_rdcaps_list();