We can't always issue_caps in file_eval or cap releases won't work.
Sometimes the client wanted shrink is missed, though, and a wanted
expansion is sent that doesn't actually change wanted. In those
cases, we DO need to issue caps. Use a separate cap op WANTED so
the mds knows when the client is asking for caps.
CEPH_CAP_OP_EXPORT, /* mds has exported the cap */
CEPH_CAP_OP_IMPORT, /* mds has imported the cap from specified mds */
CEPH_CAP_OP_UPDATE, /* client->mds update */
+ CEPH_CAP_OP_WANT, /* client->mds wanted update */
CEPH_CAP_OP_FLUSH_ACK, /* mds->client flushed. if caps=0, cap also released. */
CEPH_CAP_OP_FLUSHSNAP, /* client->mds flush snapped metadata */
CEPH_CAP_OP_FLUSHSNAP_ACK, /* mds->client flushed snapped metadata */
case CEPH_CAP_OP_EXPORT: return "export";
case CEPH_CAP_OP_IMPORT: return "import";
case CEPH_CAP_OP_UPDATE: return "update";
+ case CEPH_CAP_OP_WANT: return "want";
case CEPH_CAP_OP_FLUSH_ACK: return "flush_ack";
case CEPH_CAP_OP_FLUSHSNAP: return "flushsnap";
case CEPH_CAP_OP_FLUSHSNAP_ACK: return "flushsnap_ack";
to avoid an infinite loop on retry */
struct rb_node *p;
int tried_invalidate = 0;
+ int op;
/* if we are unmounting, flush any unused caps immediately. */
if (mdsc->stopping)
if (drop)
want = cap->mds_wanted;
+ if (want & ~cap->mds_wanted)
+ op = CEPH_CAP_OP_WANT;
+ else
+ op = CEPH_CAP_OP_UPDATE;
+
mds = cap->mds; /* remember mds, so we don't repeat */
/* __send_cap drops i_lock */
- __send_cap(mdsc, cap, CEPH_CAP_OP_UPDATE, used, want, retain,
- flushing);
+ __send_cap(mdsc, cap, op, used, want, retain, flushing);
goto retry; /* retake i_lock and restart our cap scan. */
}
}
int op = m->get_op();
+ bool do_issue = false;
if (op == CEPH_CAP_OP_RENEW) {
if (cap->touch()) {
<< " (seq " << m->get_seq() << " != last_issue " << cap->get_last_issue() << ")" << dendl;
}
}
+ if (m->get_op() == CEPH_CAP_OP_WANT && (wanted & ~cap->pending()))
+ do_issue = true;
if (!_do_cap_update(in, cap, m->get_dirty(), m->get_wanted(), follows, m, ack)) {
// no update, ack now.
eval_cap_gather(in);
if (in->filelock.is_stable())
- file_eval(&in->filelock);
+ file_eval(&in->filelock, do_issue);
if (in->authlock.is_stable())
eval(&in->authlock);
}
-void Locker::file_eval(ScatterLock *lock)
+void Locker::file_eval(ScatterLock *lock, bool do_issue)
{
CInode *in = (CInode*)lock->get_parent();
int loner_wanted, other_wanted;
file_mixed(lock);
else
simple_sync(lock);
- return;
}
}
}
dout(7) << "file_eval stable, bump to loner " << *lock
<< " on " << *lock->get_parent() << dendl;
file_excl(lock);
- return;
}
// * -> mixed?
dout(7) << "file_eval stable, bump to mixed " << *lock
<< " on " << *lock->get_parent() << dendl;
file_mixed(lock);
- return;
}
// * -> sync?
simple_sync(lock);
}
- if (in->is_any_caps())
+ else
+ do_issue = true;
+
+ if (in->is_any_caps() && do_issue)
issue_caps(in);
}
// file
public:
void try_file_eval(ScatterLock *lock);
- void file_eval(ScatterLock *lock);
+ void file_eval(ScatterLock *lock, bool do_issue=false);
protected:
void handle_file_lock(ScatterLock *lock, MLock *m);
void file_mixed(ScatterLock *lock);