* Caller should be holding s_mutex.
*/
static void send_cap_msg(struct ceph_mds_client *mdsc, u64 ino, u64 cid, int op,
- int caps, int wanted, int dirty, u64 seq, u64 mseq,
+ int caps, int wanted, int dirty,
+ u32 seq, u32 issue_seq, u32 mseq,
u64 size, u64 max_size,
struct timespec *mtime, struct timespec *atime,
u64 time_warp_seq,
struct ceph_msg *msg;
dout(10, "send_cap_msg %s %llx %llx caps %s wanted %s dirty %s"
- " seq %llu/%llu follows %lld size %llu"
+ " seq %u/%u mseq %u follows %lld size %llu"
" xattr_ver %llu xattr_len %d\n", ceph_cap_op_name(op),
cid, ino, ceph_cap_string(caps), ceph_cap_string(wanted),
ceph_cap_string(dirty),
- seq, mseq, follows, size,
+ seq, issue_seq, mseq, follows, size,
xattr_version, xattrs_blob_size);
- msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, sizeof(*fc) + xattrs_blob_size, 0, 0, NULL);
+ msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, sizeof(*fc) + xattrs_blob_size,
+ 0, 0, NULL);
if (IS_ERR(msg))
return;
fc->cap_id = cpu_to_le64(cid);
fc->op = cpu_to_le32(op);
fc->seq = cpu_to_le32(seq);
+ fc->issue_seq = cpu_to_le32(issue_seq);
fc->migrate_seq = cpu_to_le32(mseq);
fc->caps = cpu_to_le32(caps);
fc->wanted = cpu_to_le32(wanted);
int revoking = cap->implemented & ~cap->issued;
int dropping = cap->issued & ~retain;
int keep;
- u64 seq, mseq, time_warp_seq, follows;
+ u64 seq, issue_seq, mseq, time_warp_seq, follows;
u64 size, max_size;
struct timespec mtime, atime;
int wake = 0;
keep = cap->implemented;
seq = cap->seq;
+ issue_seq = cap->issue_seq;
mseq = cap->mseq;
size = inode->i_size;
ci->i_reported_size = size;
}
send_cap_msg(mdsc, ceph_vino(inode).ino, cap_id,
- op, keep, want, flushing, seq, mseq,
+ op, keep, want, flushing, seq, issue_seq, mseq,
size, max_size, &mtime, &atime, time_warp_seq,
uid, gid, mode,
xattr_version,
inode, capsnap, next_follows, capsnap->size);
send_cap_msg(mdsc, ceph_vino(inode).ino, 0,
CEPH_CAP_OP_FLUSHSNAP, capsnap->issued, 0,
- capsnap->dirty, 0, mseq,
+ capsnap->dirty, 0, 0, mseq,
capsnap->size, 0,
&capsnap->mtime, &capsnap->atime,
capsnap->time_warp_seq,
bool Locker::eval_caps(CInode *in)
{
bool need_issue = false;
+
+ dout(10) << "eval_caps " << *in << dendl;
if (!in->filelock.is_stable())
eval_gather(&in->filelock, false, &need_issue);
if (need_issue)
issue_caps(in);
+
+ dout(10) << "eval_caps done" << dendl;
return need_issue;
}
mut->cleanup();
delete mut;
- if (cap && cap->wanted() & ~cap->pending())
+ bool sup = false; // avoid sending two caps msgs, one for cap expansion, one for file_max change.
+ if (cap && (cap->wanted() & ~cap->pending())) {
issue_caps(in, cap);
-
+ cap->inc_suppress();
+ sup = true;
+ }
if (share && in->is_auth() && in->filelock.is_stable())
share_inode_max_size(in);
+ if (sup)
+ cap->dec_suppress();
}
Capability* Locker::issue_new_caps(CInode *in,
it++) {
const int client = it->first;
Capability *cap = it->second;
+ if (cap->is_suppress())
+ continue;
if (cap->pending() & (CEPH_CAP_GWR<<CEPH_CAP_SFILE)) {
dout(10) << "share_inode_max_size with client" << client << dendl;
MClientCaps *m = new MClientCaps(CEPH_CAP_OP_GRANT,
if (!in->filelock.is_stable())
mds->mdlog->flush();
}
- if (ceph_seq_cmp(m->get_seq(), cap->get_last_issue()) == 0) {
+ if (ceph_seq_cmp(m->get_issue_seq(), cap->get_last_issue()) == 0) {
dout(10) << " wanted " << ccap_string(cap->wanted())
<< " -> " << ccap_string(wanted) << dendl;
cap->set_wanted(wanted);
} else {
dout(10) << " NOT changing wanted " << ccap_string(cap->wanted())
<< " -> " << ccap_string(wanted)
- << " (seq " << m->get_seq() << " != last_issue " << cap->get_last_issue() << ")" << dendl;
+ << " (issue_seq " << m->get_issue_seq() << " != last_issue "
+ << cap->get_last_issue() << ")" << dendl;
}
}
if (m->get_op() == CEPH_CAP_OP_DROP)
can_issue = false;
- if (!_do_cap_update(in, cap, m->get_dirty(), m->get_wanted(), follows, m, ack)) {
+ if (_do_cap_update(in, cap, m->get_dirty(), m->get_wanted(), follows, m, ack)) {
+ // updated, cap msg is delayed
+ cap->inc_suppress();
+ eval_caps(in);
+ cap->dec_suppress();
+
+ if (cap->wanted() & ~cap->pending())
+ mds->mdlog->flush();
+ } else {
// no update, ack now.
if (ack)
mds->send_message_client(ack, client);
- }
- bool did_issue = eval_caps(in);
- if (!did_issue &&
- cap->wanted() & ~cap->pending())
- issue_caps(in, cap);
+ bool did_issue = eval_caps(in);
+ if (!did_issue && (cap->wanted() & ~cap->pending()))
+ issue_caps(in, cap);
+ }
}
// done?
dout(10) << " i want to change file_max, but lock won't allow it (yet)" << dendl;
in->state_set(CInode::STATE_NO_SIZE_CHECK);
if (in->filelock.is_stable()) {
- if (in->get_loner() >= 0)
- file_excl(&in->filelock);
- else
- simple_lock(&in->filelock);
+ bool need_issue = false;
+ cap->inc_suppress();
+ if (in->get_loner() >= 0 || in->try_choose_loner()) {
+ file_excl(&in->filelock, &need_issue);
+ need_issue = false; // loner!
+ } else
+ simple_lock(&in->filelock, &need_issue);
+ if (need_issue)
+ issue_caps(in);
+ cap->dec_suppress();
}
in->state_clear(CInode::STATE_NO_SIZE_CHECK);
if (!in->filelock.can_wrlock(client)) {