osdc/Objecter: preserve read-into-existing-buffer behavior

The libradosstriper::RadosStriperImpl::aio_read populates the target
outbl with a static buffer and relies on us reading into it.  This was
actually not reliable in the past (it could fail if the rx_buffers
optimization failed due to a retransmit or something else) but nevertheless
libradosstriper requires it to work *at all*.

Resolve this by modifying Objecter to copy the result into any provided
buffer at the lowest layer.  This should capture any other such user who
needed this behavior.

On the other hand, it will break any user who inadvertantly reads into a
non-empty bufferlist.  Given that any such user would already previously
have seen bad behavior due to the rx_buffers optimization, we expect
there to be 0 such instances.

Signed-off-by: Sage Weil <sage@redhat.com>
This commit is contained in:
Sage Weil 2019-03-01 14:12:42 -06:00
parent 18ff587f1a
commit aae0e8c0c0

View File

@ -3458,6 +3458,26 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m)
if (op->con)
op->con->revoke_rx_buffer(op->tid);
#endif
auto& bl = m->get_data();
if (op->outbl->length() == bl.length() &&
bl.get_num_buffers() <= 1) {
// this is here to keep previous users to *relied* on getting data
// read into existing buffers happy. Notably,
// libradosstriper::RadosStriperImpl::aio_read().
ldout(cct,10) << __func__ << " copying resulting " << bl.length()
<< " into existing buffer of length " << op->outbl->length()
<< dendl;
bufferlist t;
t.claim(*op->outbl);
t.invalidate_crc(); // we're overwriting the raw buffers via c_str()
bl.copy(0, bl.length(), t.c_str());
op->outbl->substr_of(t, 0, bl.length());
} else {
m->claim_data(*op->outbl);
}
lderr(cct) << __func__ << " data:\n";
op->outbl->hexdump(*_dout);
*_dout << dendl;
op->outbl = 0;
}