ldout(cct, 5) << "get_cap_ref got first FILE_BUFFER ref on " << *in << dendl;
in->get();
}
+ if ((cap & CEPH_CAP_FILE_CACHE) &&
+ in->cap_refs[CEPH_CAP_FILE_CACHE] == 0) {
+ ldout(cct, 5) << "get_cap_ref got first FILE_CACHE ref on " << *in << dendl;
+ in->get();
+ }
in->get_cap_ref(cap);
}
void Client::put_cap_ref(Inode *in, int cap)
{
- bool last = in->put_cap_ref(cap);
+ int last = in->put_cap_ref(cap);
if (last) {
+ int put_nref = 0;
+ int drop = last & ~in->caps_issued();
if (in->snapid == CEPH_NOSNAP) {
- if ((cap & CEPH_CAP_FILE_WR) &&
+ if ((last & CEPH_CAP_FILE_WR) &&
!in->cap_snaps.empty() &&
in->cap_snaps.rbegin()->second->writing) {
ldout(cct, 10) << "put_cap_ref finishing pending cap_snap on " << *in << dendl;
in->cap_snaps.rbegin()->second->writing = 0;
- finish_cap_snap(in, in->cap_snaps.rbegin()->second, in->caps_used());
+ finish_cap_snap(in, in->cap_snaps.rbegin()->second, get_caps_used(in));
signal_cond_list(in->waitfor_caps); // wake up blocked sync writers
}
- if (cap & CEPH_CAP_FILE_BUFFER) {
+ if (last & CEPH_CAP_FILE_BUFFER) {
for (map<snapid_t,CapSnap*>::iterator p = in->cap_snaps.begin();
p != in->cap_snaps.end();
++p)
p->second->dirty_data = 0;
- check_caps(in, false);
signal_cond_list(in->waitfor_commit);
ldout(cct, 5) << "put_cap_ref dropped last FILE_BUFFER ref on " << *in << dendl;
- put_inode(in);
+ ++put_nref;
}
}
- if (cap & CEPH_CAP_FILE_CACHE) {
- check_caps(in, false);
+ if (last & CEPH_CAP_FILE_CACHE) {
ldout(cct, 5) << "put_cap_ref dropped last FILE_CACHE ref on " << *in << dendl;
+ ++put_nref;
+ }
+ if (drop) {
+ if (drop & CEPH_CAP_FILE_CACHE)
+ _invalidate_inode_cache(in, false);
+ else
+ check_caps(in, false);
}
+ if (put_nref)
+ put_inode(in, put_nref);
}
}
-
int Client::get_caps(Inode *in, int need, int want, int *phave, loff_t endoff)
{
while (1) {
}
}
+int Client::get_caps_used(Inode *in)
+{
+ unsigned used = in->caps_used();
+ if (!(used & CEPH_CAP_FILE_CACHE) &&
+ !objectcacher->set_is_empty(&in->oset))
+ used |= CEPH_CAP_FILE_CACHE;
+ return used;
+}
void Client::cap_delay_requeue(Inode *in)
{
void Client::check_caps(Inode *in, bool is_delayed)
{
unsigned wanted = in->caps_wanted();
- unsigned used = in->caps_used();
+ unsigned used = get_caps_used(in);
unsigned cap_used;
int retain = wanted | CEPH_CAP_PIN;
void Client::queue_cap_snap(Inode *in, snapid_t seq)
{
- int used = in->caps_used();
+ int used = get_caps_used(in);
int dirty = in->caps_dirty();
ldout(cct, 10) << "queue_cap_snap " << *in << " seq " << seq << " used " << ccap_string(used) << dendl;
ino_invalidate_cb(ino_invalidate_cb_handle, in->vino(), off, len);
client_lock.Lock();
- if (!keep_caps) {
- put_cap_ref(in, CEPH_CAP_FILE_CACHE);
- }
+ if (!keep_caps)
+ check_caps(in, false);
put_inode(in);
client_lock.Unlock();
ldout(cct, 10) << "_async_invalidate " << off << "~" << len << (keep_caps ? " keep_caps" : "") << " done" << dendl;
// we queue the invalidate, which calls the callback and decrements the ref
async_ino_invalidator.queue(new C_Client_CacheInvalidate(this, in, off, len, keep_caps));
else if (!keep_caps)
- // if not set, we just decrement the cap ref here
- in->put_cap_ref(CEPH_CAP_FILE_CACHE);
+ check_caps(in, false);
}
void Client::_invalidate_inode_cache(Inode *in, bool keep_caps)
void Client::_release(Inode *in)
{
ldout(cct, 20) << "_release " << *in << dendl;
- if (in->cap_refs[CEPH_CAP_FILE_CACHE]) {
+ if (in->cap_refs[CEPH_CAP_FILE_CACHE] == 0) {
_invalidate_inode_cache(in, false);
}
}
{
ldout(cct, 10) << "_flushed " << *in << dendl;
- // release clean pages too, if we dont hold RDCACHE reference
- if (in->cap_refs[CEPH_CAP_FILE_CACHE] == 0) {
- _invalidate_inode_cache(in, true);
- }
-
- put_cap_ref(in, CEPH_CAP_FILE_BUFFER);
+ put_cap_ref(in, CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_BUFFER);
}
int mine = cap->issued | cap->implemented;
int oissued = in->auth_cap ? in->auth_cap->issued : 0;
// disposable non-auth cap
- if (!(in->caps_used() & ~oissued & mine)) {
+ if (!(get_caps_used(in) & ~oissued & mine)) {
ldout(cct, 20) << " removing unused, unneeded non-auth cap on " << *in << dendl;
remove_cap(cap, true);
trimmed++;
int wanted = in->caps_wanted();
int retain = wanted | CEPH_CAP_PIN;
- send_cap(in, session, cap, in->caps_used(), wanted, retain, in->flushing_caps);
+ send_cap(in, session, cap, get_caps_used(in), wanted, retain, in->flushing_caps);
}
void Client::wait_sync_caps(uint64_t want)
void Client::handle_cap_grant(MetaSession *session, Inode *in, Cap *cap, MClientCaps *m)
{
int mds = session->mds_num;
- int used = in->caps_used();
+ int used = get_caps_used(in);
int wanted = in->caps_wanted();
const int old_caps = cap->issued;
cap->issued = new_caps;
cap->implemented |= new_caps;
- if ((~cap->issued & old_caps) & CEPH_CAP_FILE_CACHE)
- _release(in);
if (((used & ~new_caps) & CEPH_CAP_FILE_BUFFER) &&
!_flush(in)) {
// waitin' for flush
+ } else if ((old_caps & ~new_caps) & CEPH_CAP_FILE_CACHE) {
+ _release(in);
} else {
cap->wanted = 0; // don't let check_caps skip sending a response to MDS
check = true;
}
if (check)
- check_caps(in, true);
+ check_caps(in, false);
// wake up waiters
if (new_caps)
readahead = false;
}
- // we will populate the cache here
- if (in->cap_refs[CEPH_CAP_FILE_CACHE] == 0)
- in->get_cap_ref(CEPH_CAP_FILE_CACHE);
-
ldout(cct, 10) << "readahead=" << readahead << " nr_consec=" << f->nr_consec_read
<< " max_byes=" << conf->client_readahead_max_bytes
<< " max_periods=" << conf->client_readahead_max_periods << dendl;
if (cct->_conf->client_oc && (have & CEPH_CAP_FILE_BUFFER)) {
// do buffered write
if (!in->oset.dirty_or_tx)
- get_cap_ref(in, CEPH_CAP_FILE_BUFFER);
+ get_cap_ref(in, CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_BUFFER);
get_cap_ref(in, CEPH_CAP_FILE_BUFFER);