template <typename I>
bool ObjectCacherObjectDispatch<I>::read(
uint64_t object_no, const io::Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, io::Extents* extent_map, uint64_t* version,
int* object_dispatch_flags, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
on_dispatched = util::create_async_context_callback(*m_image_ctx,
on_dispatched);
+ // embed the RBD-internal read flags in the genenric RADOS op_flags and
+ op_flags = ((op_flags & ~ObjectCacherWriteback::READ_FLAGS_MASK) |
+ ((read_flags << ObjectCacherWriteback::READ_FLAGS_SHIFT) &
+ ObjectCacherWriteback::READ_FLAGS_MASK));
+
m_image_ctx->image_lock.lock_shared();
auto rd = m_object_cacher->prepare_read(
io_context->read_snap().value_or(CEPH_NOSNAP), read_data, op_flags);
bool read(
uint64_t object_no, const io::Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, io::Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
io::DispatchResult* dispatch_result, Context** on_finish,
io_context->read_snap(snapid);
}
+ // extract the embedded RBD read flags from the op_flags
+ int read_flags = (op_flags & READ_FLAGS_MASK) >> READ_FLAGS_SHIFT;
+ op_flags &= ~READ_FLAGS_MASK;
+
auto req = io::ObjectDispatchSpec::create_read(
m_ictx, io::OBJECT_DISPATCH_LAYER_CACHE, object_no, {{off, len}},
- io_context, op_flags, trace, &req_comp->bl,
+ io_context, op_flags, read_flags, trace, &req_comp->bl,
&req_comp->extent_map, nullptr, req_comp);
req->send();
}
class ObjectCacherWriteback : public WritebackHandler {
public:
+ static const int READ_FLAGS_MASK = 0xF000;
+ static const int READ_FLAGS_SHIFT = 24;
+
ObjectCacherWriteback(ImageCtx *ictx, ceph::mutex& lock);
// Note that oloc, trunc_size, and trunc_seq are ignored
template <typename I>
bool ParentCacheObjectDispatch<I>::read(
uint64_t object_no, const io::Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, io::Extents* extent_map, uint64_t* version,
int* object_dispatch_flags, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
bool read(
uint64_t object_no, const io::Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, io::Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
io::DispatchResult* dispatch_result, Context** on_finish,
template <typename I>
bool WriteAroundObjectDispatch<I>::read(
uint64_t object_no, const io::Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, io::Extents* extent_map, uint64_t* version,
int* object_dispatch_flags, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
bool read(
uint64_t object_no, const io::Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, io::Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
io::DispatchResult* dispatch_result, Context** on_finish,
C_EncryptedObjectReadRequest(
I* image_ctx, CryptoInterface* crypto, uint64_t object_no,
uint64_t object_off, uint64_t object_len, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, int* object_dispatch_flags,
Context** on_finish,
Context* on_dispatched) : image_ctx(image_ctx),
req = io::ObjectDispatchSpec::create_read(
image_ctx, io::OBJECT_DISPATCH_LAYER_CRYPTO, object_no,
- {{object_off, object_len}}, io_context, op_flags, parent_trace,
- &req_comp->bl, &req_comp->extent_map, nullptr, req_comp);
+ {{object_off, object_len}}, io_context, op_flags, read_flags,
+ parent_trace, &req_comp->bl, &req_comp->extent_map, nullptr,
+ req_comp);
}
void send() {
template <typename I>
bool CryptoObjectDispatch<I>::read(
- uint64_t object_no, const io::Extents &extents,
- IOContext io_context, int op_flags, const ZTracer::Trace &parent_trace,
+ uint64_t object_no, const io::Extents &extents, IOContext io_context,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, io::Extents* extent_map, uint64_t* version,
int* object_dispatch_flags, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
*dispatch_result = io::DISPATCH_RESULT_COMPLETE;
auto req = new C_EncryptedObjectReadRequest<I>(
m_image_ctx, m_crypto, object_no, object_off, object_len, io_context,
- op_flags, parent_trace, read_data, object_dispatch_flags, on_finish,
- on_dispatched);
+ op_flags, read_flags, parent_trace, read_data, object_dispatch_flags,
+ on_finish, on_dispatched);
req->send();
return true;
}
bool read(
uint64_t object_no, const io::Extents &extents,
- IOContext io_context, int op_flags,
+ IOContext io_context, int op_flags, int read_flags,
const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
io::Extents* extent_map, uint64_t* version, int* object_dispatch_flags,
io::DispatchResult* dispatch_result, Context** on_finish,
object_extent.length);
auto req = io::ObjectDispatchSpec::create_read(
ictx, io::OBJECT_DISPATCH_LAYER_NONE, object_extent.object_no,
- {{object_extent.offset, object_extent.length}}, io_context, 0, {},
+ {{object_extent.offset, object_extent.length}}, io_context, 0, 0, {},
&req_comp->read_data, &req_comp->extent_map, nullptr, req_comp);
req->send();
}
aio_comp, oe.offset, oe.length, std::move(oe.buffer_extents));
auto req = ObjectDispatchSpec::create_read(
&image_ctx, OBJECT_DISPATCH_LAYER_NONE, oe.object_no,
- {{oe.offset, oe.length}}, this->m_io_context, m_op_flags, this->m_trace,
+ {{oe.offset, oe.length}}, this->m_io_context, m_op_flags, 0, this->m_trace,
&req_comp->bl, &req_comp->extent_map, nullptr, req_comp);
req->send();
}
template <typename I>
bool ObjectDispatch<I>::read(
uint64_t object_no, const Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
int* object_dispatch_flags, DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
*dispatch_result = DISPATCH_RESULT_COMPLETE;
auto req = new ObjectReadRequest<I>(m_image_ctx, object_no, extents,
- io_context, op_flags, parent_trace,
- read_data, extent_map, version,
- on_dispatched);
+ io_context, op_flags, read_flags,
+ parent_trace, read_data, extent_map,
+ version, on_dispatched);
req->send();
return true;
}
bool read(
uint64_t object_no, const Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
DispatchResult* dispatch_result, Context** on_finish,
virtual bool read(
uint64_t object_no, const Extents &extents,
- IOContext io_context, int op_flags,
+ IOContext io_context, int op_flags, int read_flags,
const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
Extents* extent_map, uint64_t* version, int* object_dispatch_flags,
DispatchResult* dispatch_result, Context** on_finish,
struct ReadRequest : public RequestBase {
const Extents extents;
+ int read_flags;
ceph::bufferlist* read_data;
Extents* extent_map;
uint64_t* version;
ReadRequest(uint64_t object_no, const Extents &extents,
- ceph::bufferlist* read_data, Extents* extent_map,
- uint64_t* version)
- : RequestBase(object_no), extents(extents), read_data(read_data),
- extent_map(extent_map), version(version) {
+ int read_flags, ceph::bufferlist* read_data,
+ Extents* extent_map, uint64_t* version)
+ : RequestBase(object_no), extents(extents), read_flags(read_flags),
+ read_data(read_data), extent_map(extent_map), version(version) {
}
};
static ObjectDispatchSpec* create_read(
ImageCtxT* image_ctx, ObjectDispatchLayer object_dispatch_layer,
uint64_t object_no, const Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
Context* on_finish) {
return new ObjectDispatchSpec(image_ctx->io_object_dispatcher,
object_dispatch_layer,
ReadRequest{object_no, extents,
- read_data, extent_map, version},
+ read_flags, read_data, extent_map,
+ version},
io_context, op_flags, parent_trace,
on_finish);
}
bool operator()(ObjectDispatchSpec::ReadRequest& read) const {
return object_dispatch->read(
read.object_no, read.extents, object_dispatch_spec->io_context,
- object_dispatch_spec->op_flags, object_dispatch_spec->parent_trace,
+ object_dispatch_spec->op_flags, read.read_flags,
+ object_dispatch_spec->parent_trace,
read.read_data, read.extent_map, read.version,
&object_dispatch_spec->object_dispatch_flags,
&object_dispatch_spec->dispatch_result,
template <typename I>
ObjectReadRequest<I>::ObjectReadRequest(
I *ictx, uint64_t objectno, const Extents &extents,
- IOContext io_context, int op_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
- Context *completion)
- : ObjectRequest<I>(ictx, objectno, io_context, "read", parent_trace,
- completion),
- m_extents(extents), m_op_flags(op_flags), m_read_data(read_data),
- m_extent_map(extent_map), m_version(version) {
+ IOContext io_context, int op_flags, int read_flags,
+ const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
+ Extents* extent_map, uint64_t* version, Context *completion)
+ : ObjectRequest<I>(ictx, objectno, io_context, "read",
+ parent_trace, completion),
+ m_extents(extents), m_op_flags(op_flags), m_read_flags(read_flags),
+ m_read_data(read_data), m_extent_map(extent_map), m_version(version) {
}
template <typename I>
template <typename I>
void ObjectReadRequest<I>::read_parent() {
+ if ((m_read_flags & READ_FLAG_DISABLE_READ_FROM_PARENT) != 0) {
+ this->finish(-ENOENT);
+ return;
+ }
+
I *image_ctx = this->m_ictx;
ldout(image_ctx->cct, 20) << dendl;
public:
static ObjectReadRequest* create(
ImageCtxT *ictx, uint64_t objectno, const Extents &extents,
- IOContext io_context, int op_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
- Context *completion) {
+ IOContext io_context, int op_flags, int read_flags,
+ const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
+ Extents* extent_map, uint64_t* version, Context *completion) {
return new ObjectReadRequest(ictx, objectno, extents, io_context, op_flags,
- parent_trace, read_data, extent_map, version,
- completion);
+ read_flags, parent_trace, read_data,
+ extent_map, version, completion);
}
ObjectReadRequest(
ImageCtxT *ictx, uint64_t objectno, const Extents &extents,
- IOContext io_context, int op_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
- Context *completion);
+ IOContext io_context, int op_flags, int read_flags,
+ const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
+ Extents* extent_map, uint64_t* version, Context *completion);
void send() override;
typedef std::vector<ExtentResult> ExtentResults;
ExtentResults m_extent_results;
int m_op_flags;
+ int m_read_flags;
ceph::bufferlist* m_read_data;
Extents* m_extent_map;
template <typename I>
bool SimpleSchedulerObjectDispatch<I>::read(
uint64_t object_no, const Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
int* object_dispatch_flags, DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
bool read(
uint64_t object_no, const Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
DispatchResult* dispatch_result, Context** on_finish,
OBJECT_DISPATCH_LAYER_LAST
};
+enum {
+ READ_FLAG_DISABLE_READ_FROM_PARENT = 1UL << 0,
+};
+
enum {
OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE = 1UL << 0
};
bool read(
uint64_t object_no, const io::Extents &extents, IOContext io_context,
- int op_flags, const ZTracer::Trace &parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
ceph::bufferlist* read_data, io::Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
io::DispatchResult* dispatch_result, Context** on_finish,
io::DispatchResult dispatch_result;
ceph::bufferlist read_data;
mock_parent_image_cache->read(
- 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0, {}, &read_data,
+ 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0, 0, {}, &read_data,
nullptr, nullptr, nullptr, &dispatch_result, nullptr, &on_dispatched);
ASSERT_EQ(0, on_dispatched.wait());
C_SaferCond on_dispatched;
io::DispatchResult dispatch_result;
mock_parent_image_cache->read(
- 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0, {}, nullptr,
+ 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr,
nullptr, nullptr, nullptr, &dispatch_result, nullptr, &on_dispatched);
ASSERT_EQ(0, on_dispatched.wait());
TEST_F(TestMockCryptoCryptoObjectDispatch, ReadFail) {
expect_object_read();
ASSERT_TRUE(mock_crypto_object_dispatch->read(
- 0, {{0, 4096}}, mock_image_ctx->get_data_io_context(), 0, {}, &data,
+ 0, {{0, 4096}}, mock_image_ctx->get_data_io_context(), 0, 0, {}, &data,
&extent_map, nullptr, &object_dispatch_flags, &dispatch_result,
&on_finish, on_dispatched));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
TEST_F(TestMockCryptoCryptoObjectDispatch, Read) {
expect_object_read();
ASSERT_TRUE(mock_crypto_object_dispatch->read(
- 0, {{0, 4096}}, mock_image_ctx->get_data_io_context(), 0, {}, &data,
- &extent_map, nullptr, &object_dispatch_flags, &dispatch_result,
+ 0, {{0, 4096}}, mock_image_ctx->get_data_io_context(), 0, 0, {},
+ &data, &extent_map, nullptr, &object_dispatch_flags, &dispatch_result,
&on_finish, on_dispatched));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish, &finished_cond);
uint64_t version;
auto req = MockObjectReadRequest::create(
&mock_image_ctx, 0, {{0, 4096}, {8192, 4096}},
- mock_image_ctx.get_data_io_context(), 0, {},
+ mock_image_ctx.get_data_io_context(), 0, 0, {},
&bl, &extent_map, &version, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
auto req = MockObjectReadRequest::create(
&mock_image_ctx, 0,
{{0, ictx->sparse_read_threshold_bytes}},
- mock_image_ctx.get_data_io_context(), 0, {}, &bl,
+ mock_image_ctx.get_data_io_context(), 0, 0, {}, &bl,
&extent_map, nullptr, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
C_SaferCond ctx;
auto req = MockObjectReadRequest::create(
&mock_image_ctx, 0, {{0, 4096}},
- mock_image_ctx.get_data_io_context(), 0, {}, &bl, &extent_map,
+ mock_image_ctx.get_data_io_context(), 0, 0, {}, &bl, &extent_map,
nullptr, &ctx);
req->send();
ASSERT_EQ(-EPERM, ctx.wait());
C_SaferCond ctx;
auto req = MockObjectReadRequest::create(
&mock_image_ctx, 0, {{0, 4096}},
- mock_image_ctx.get_data_io_context(), 0, {}, &bl, &extent_map,
+ mock_image_ctx.get_data_io_context(), 0, 0, {}, &bl, &extent_map,
nullptr, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
C_SaferCond ctx;
auto req = MockObjectReadRequest::create(
&mock_image_ctx, 0, {{0, 4096}},
- mock_image_ctx.get_data_io_context(), 0, {}, &bl, &extent_map,
+ mock_image_ctx.get_data_io_context(), 0, 0, {}, &bl, &extent_map,
nullptr, &ctx);
req->send();
ASSERT_EQ(-EPERM, ctx.wait());
}
+TEST_F(TestMockIoObjectRequest, SkipParentRead) {
+ REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+
+ librbd::Image image;
+ librbd::RBD rbd;
+ ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
+ ASSERT_EQ(0, image.snap_create("one"));
+ ASSERT_EQ(0, image.snap_protect("one"));
+ image.close();
+
+ std::string clone_name = get_temp_image_name();
+ int order = 0;
+ ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
+ clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(clone_name, &ictx));
+ ictx->sparse_read_threshold_bytes = 8096;
+ ictx->clone_copy_on_read = false;
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ mock_image_ctx.parent = &mock_image_ctx;
+
+ MockObjectMap mock_object_map;
+ if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+ mock_image_ctx.object_map = &mock_object_map;
+ }
+
+ InSequence seq;
+ expect_object_may_exist(mock_image_ctx, 0, true);
+ expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
+ expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
+
+ bufferlist bl;
+ Extents extent_map;
+ C_SaferCond ctx;
+ auto req = MockObjectReadRequest::create(
+ &mock_image_ctx, 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0,
+ READ_FLAG_DISABLE_READ_FROM_PARENT, {}, &bl, &extent_map,
+ nullptr, &ctx);
+ req->send();
+ ASSERT_EQ(-ENOENT, ctx.wait());
+}
+
TEST_F(TestMockIoObjectRequest, CopyOnRead) {
REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
C_SaferCond ctx;
auto req = MockObjectReadRequest::create(
&mock_image_ctx, 0, {{0, 4096}},
- mock_image_ctx.get_data_io_context(), 0, {}, &bl, &extent_map,
+ mock_image_ctx.get_data_io_context(), 0, 0, {}, &bl, &extent_map,
nullptr, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
C_SaferCond cond;
Context *on_finish = &cond;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.read(
- 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0, {}, nullptr,
+ 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr,
nullptr, nullptr, nullptr, nullptr, &on_finish, nullptr));
ASSERT_EQ(on_finish, &cond); // not modified
on_finish->complete(0);
DispatchResult*, Context*));
bool read(
uint64_t object_no, const Extents& extents, IOContext io_context,
- int op_flags, const ZTracer::Trace& parent_trace,
+ int op_flags, int read_flags, const ZTracer::Trace& parent_trace,
ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
int* dispatch_flags, DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {