osdc/ObjectCacher: only return ENOENT if ObjectSet is flagged

The fs client can't handle ENOENT from the cache, but librbd wants it.
Also, the fs client will send down multiple ObjectExtents per io, but that
is incompatible with the ENOENT behavior.

Indicate which behavior we want via the ObjectSet, and update librbd to
explicitly ask for it.  This fixes the fs client, which is currently
broken (it returns ENOENT on read).

Signed-off-by: Sage Weil <sage@inktank.com>
This commit is contained in:
Sage Weil 2012-11-12 15:40:08 -08:00
parent bc398c0321
commit a11940f56a
3 changed files with 40 additions and 37 deletions

View File

@ -78,6 +78,7 @@ namespace librbd {
cct->_conf->rbd_cache_target_dirty,
cct->_conf->rbd_cache_max_dirty_age);
object_set = new ObjectCacher::ObjectSet(NULL, data_ctx.get_id(), 0);
object_set->return_enoent = true;
object_cacher->start();
}
}

View File

@ -926,53 +926,52 @@ int ObjectCacher::_readx(OSDRead *rd, ObjectSet *oset, Context *onfinish,
Object *o = get_object(soid, oset, ex_it->oloc);
// does not exist and no hits?
if (!o->exists) {
if (oset->return_enoent && !o->exists) {
// WARNING: we can only meaningfully return ENOENT if the read request
// passed in a single ObjectExtent. Any caller who wants ENOENT instead of
// zeroed buffers needs to feed single extents into readx().
if (rd->extents.size() == 1) {
ldout(cct, 10) << "readx object !exists, 1 extent..." << dendl;
assert(rd->extents.size() == 1);
ldout(cct, 10) << "readx object !exists, 1 extent..." << dendl;
// should we worry about COW underneaeth us?
if (writeback_handler.may_copy_on_write(soid.oid, ex_it->offset, ex_it->length, soid.snap)) {
ldout(cct, 20) << "readx may copy on write" << dendl;
bool wait = false;
for (map<loff_t, BufferHead*>::iterator bh_it = o->data.begin();
bh_it != o->data.end();
bh_it++) {
BufferHead *bh = bh_it->second;
if (bh->is_dirty() || bh->is_tx()) {
ldout(cct, 10) << "readx flushing " << *bh << dendl;
wait = true;
if (bh->is_dirty())
bh_write(bh);
}
}
if (wait) {
ldout(cct, 10) << "readx waiting on tid " << o->last_write_tid << " on " << *o << dendl;
o->waitfor_commit[o->last_write_tid].push_back(new C_RetryRead(this, rd, oset, onfinish));
// FIXME: perfcounter!
return 0;
}
}
// can we return ENOENT?
bool allzero = true;
// should we worry about COW underneaeth us?
if (writeback_handler.may_copy_on_write(soid.oid, ex_it->offset, ex_it->length, soid.snap)) {
ldout(cct, 20) << "readx may copy on write" << dendl;
bool wait = false;
for (map<loff_t, BufferHead*>::iterator bh_it = o->data.begin();
bh_it != o->data.end();
bh_it++) {
ldout(cct, 20) << "readx ob has bh " << *bh_it->second << dendl;
if (!bh_it->second->is_zero() && !bh_it->second->is_rx()) {
allzero = false;
break;
BufferHead *bh = bh_it->second;
if (bh->is_dirty() || bh->is_tx()) {
ldout(cct, 10) << "readx flushing " << *bh << dendl;
wait = true;
if (bh->is_dirty())
bh_write(bh);
}
}
if (allzero) {
ldout(cct, 10) << "readx ob has all zero|rx, returning ENOENT" << dendl;
delete rd;
return -ENOENT;
if (wait) {
ldout(cct, 10) << "readx waiting on tid " << o->last_write_tid << " on " << *o << dendl;
o->waitfor_commit[o->last_write_tid].push_back(new C_RetryRead(this, rd, oset, onfinish));
// FIXME: perfcounter!
return 0;
}
}
// can we return ENOENT?
bool allzero = true;
for (map<loff_t, BufferHead*>::iterator bh_it = o->data.begin();
bh_it != o->data.end();
bh_it++) {
ldout(cct, 20) << "readx ob has bh " << *bh_it->second << dendl;
if (!bh_it->second->is_zero() && !bh_it->second->is_rx()) {
allzero = false;
break;
}
}
if (allzero) {
ldout(cct, 10) << "readx ob has all zero|rx, returning ENOENT" << dendl;
delete rd;
return -ENOENT;
}
}
// map extent into bufferheads

View File

@ -300,10 +300,13 @@ class ObjectCacher {
xlist<Object*> objects;
int dirty_or_tx;
bool return_enoent;
ObjectSet(void *p, int64_t _poolid, inodeno_t i)
: parent(p), ino(i), truncate_seq(0),
truncate_size(0), poolid(_poolid), dirty_or_tx(0) {}
truncate_size(0), poolid(_poolid), dirty_or_tx(0),
return_enoent(false) {}
};