// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_IO_IMAGE_REQUEST_H #define CEPH_LIBRBD_IO_IMAGE_REQUEST_H #include "include/int_types.h" #include "include/buffer_fwd.h" #include "common/snap_types.h" #include "common/zipkin_trace.h" #include "osd/osd_types.h" #include "librbd/Utils.h" #include "librbd/io/Types.h" #include #include #include namespace librbd { class ImageCtx; namespace io { class AioCompletion; class ObjectRequestHandle; class ReadResult; template class ImageRequest { public: typedef std::vector > Extents; virtual ~ImageRequest() { m_trace.event("finish"); } static ImageRequest* create_read_request(ImageCtxT &image_ctx, AioCompletion *aio_comp, Extents &&image_extents, ReadResult &&read_result, int op_flags, const ZTracer::Trace &parent_trace); static ImageRequest* create_write_request(ImageCtxT &image_ctx, AioCompletion *aio_comp, Extents &&image_extents, bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace); static ImageRequest* create_discard_request(ImageCtxT &image_ctx, AioCompletion *aio_comp, uint64_t off, uint64_t len, bool skip_partial_discard, const ZTracer::Trace &parent_trace); static ImageRequest* create_flush_request(ImageCtxT &image_ctx, AioCompletion *aio_comp, const ZTracer::Trace &parent_trace); static ImageRequest* create_writesame_request(ImageCtxT &image_ctx, AioCompletion *aio_comp, uint64_t off, uint64_t len, bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace); static ImageRequest* create_compare_and_write_request( ImageCtxT &image_ctx, AioCompletion *c, Extents &&image_extents, bufferlist &&cmp_bl, bufferlist &&bl, uint64_t *mismatch_offset, int op_flags, const ZTracer::Trace &parent_trace); static void aio_read(ImageCtxT *ictx, AioCompletion *c, Extents &&image_extents, ReadResult &&read_result, int op_flags, const ZTracer::Trace &parent_trace); static void aio_write(ImageCtxT *ictx, AioCompletion *c, Extents &&image_extents, bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace); static void aio_discard(ImageCtxT *ictx, AioCompletion *c, uint64_t off, uint64_t len, bool skip_partial_discard, const ZTracer::Trace &parent_trace); static void aio_flush(ImageCtxT *ictx, AioCompletion *c, const ZTracer::Trace &parent_trace); static void aio_writesame(ImageCtxT *ictx, AioCompletion *c, uint64_t off, uint64_t len, bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace); static void aio_compare_and_write(ImageCtxT *ictx, AioCompletion *c, Extents &&image_extents, bufferlist &&cmp_bl, bufferlist &&bl, uint64_t *mismatch_offset, int op_flags, const ZTracer::Trace &parent_trace); virtual bool is_write_op() const { return false; } void start_op(); void send(); void fail(int r); void set_bypass_image_cache() { m_bypass_image_cache = true; } inline const ZTracer::Trace &get_trace() const { return m_trace; } protected: typedef std::list ObjectRequests; ImageCtxT &m_image_ctx; AioCompletion *m_aio_comp; Extents m_image_extents; ZTracer::Trace m_trace; bool m_bypass_image_cache = false; ImageRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp, Extents &&image_extents, const char *trace_name, const ZTracer::Trace &parent_trace) : m_image_ctx(image_ctx), m_aio_comp(aio_comp), m_image_extents(std::move(image_extents)), m_trace(util::create_trace(image_ctx, trace_name, parent_trace)) { m_trace.event("start"); } virtual int clip_request(); virtual void send_request() = 0; virtual void send_image_cache_request() = 0; virtual aio_type_t get_aio_type() const = 0; virtual const char *get_request_type() const = 0; }; template class ImageReadRequest : public ImageRequest { public: using typename ImageRequest::Extents; ImageReadRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp, Extents &&image_extents, ReadResult &&read_result, int op_flags, const ZTracer::Trace &parent_trace); protected: int clip_request() override; void send_request() override; void send_image_cache_request() override; aio_type_t get_aio_type() const override { return AIO_TYPE_READ; } const char *get_request_type() const override { return "aio_read"; } private: char *m_buf; bufferlist *m_pbl; int m_op_flags; }; template class AbstractImageWriteRequest : public ImageRequest { public: bool is_write_op() const override { return true; } inline void flag_synchronous() { m_synchronous = true; } protected: using typename ImageRequest::ObjectRequests; using typename ImageRequest::Extents; typedef std::vector ObjectExtents; AbstractImageWriteRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp, Extents &&image_extents, const char *trace_name, const ZTracer::Trace &parent_trace) : ImageRequest(image_ctx, aio_comp, std::move(image_extents), trace_name, parent_trace), m_synchronous(false) { } void send_request() override; virtual int prune_object_extents(ObjectExtents &object_extents) { return 0; } virtual uint32_t get_object_cache_request_count(bool journaling) const { return 0; } virtual void send_object_cache_requests(const ObjectExtents &object_extents, uint64_t journal_tid) = 0; virtual void send_object_requests(const ObjectExtents &object_extents, const ::SnapContext &snapc, ObjectRequests *object_requests); virtual ObjectRequestHandle *create_object_request( const ObjectExtent &object_extent, const ::SnapContext &snapc, Context *on_finish) = 0; virtual uint64_t append_journal_event(const ObjectRequests &requests, bool synchronous) = 0; virtual void update_stats(size_t length) = 0; private: bool m_synchronous; }; template class ImageWriteRequest : public AbstractImageWriteRequest { public: using typename ImageRequest::Extents; ImageWriteRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp, Extents &&image_extents, bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace) : AbstractImageWriteRequest( image_ctx, aio_comp, std::move(image_extents), "write", parent_trace), m_bl(std::move(bl)), m_op_flags(op_flags) { } protected: using typename ImageRequest::ObjectRequests; using typename AbstractImageWriteRequest::ObjectExtents; aio_type_t get_aio_type() const override { return AIO_TYPE_WRITE; } const char *get_request_type() const override { return "aio_write"; } void assemble_extent(const ObjectExtent &object_extent, bufferlist *bl); void send_image_cache_request() override; void send_object_cache_requests(const ObjectExtents &object_extents, uint64_t journal_tid) override; void send_object_requests(const ObjectExtents &object_extents, const ::SnapContext &snapc, ObjectRequests *aio_object_requests) override; ObjectRequestHandle *create_object_request( const ObjectExtent &object_extent, const ::SnapContext &snapc, Context *on_finish) override; uint64_t append_journal_event(const ObjectRequests &requests, bool synchronous) override; void update_stats(size_t length) override; private: bufferlist m_bl; int m_op_flags; }; template class ImageDiscardRequest : public AbstractImageWriteRequest { public: ImageDiscardRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp, uint64_t off, uint64_t len, bool skip_partial_discard, const ZTracer::Trace &parent_trace) : AbstractImageWriteRequest( image_ctx, aio_comp, {{off, len}}, "discard", parent_trace), m_skip_partial_discard(skip_partial_discard) { } protected: using typename ImageRequest::ObjectRequests; using typename AbstractImageWriteRequest::ObjectExtents; aio_type_t get_aio_type() const override { return AIO_TYPE_DISCARD; } const char *get_request_type() const override { return "aio_discard"; } int prune_object_extents(ObjectExtents &object_extents) override; void send_image_cache_request() override; uint32_t get_object_cache_request_count(bool journaling) const override; void send_object_cache_requests(const ObjectExtents &object_extents, uint64_t journal_tid) override; ObjectRequestHandle *create_object_request( const ObjectExtent &object_extent, const ::SnapContext &snapc, Context *on_finish) override; uint64_t append_journal_event(const ObjectRequests &requests, bool synchronous) override; void update_stats(size_t length) override; private: bool m_skip_partial_discard; }; template class ImageFlushRequest : public ImageRequest { public: ImageFlushRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp, const ZTracer::Trace &parent_trace) : ImageRequest(image_ctx, aio_comp, {}, "flush", parent_trace) { } bool is_write_op() const override { return true; } protected: using typename ImageRequest::ObjectRequests; int clip_request() override { return 0; } void send_request() override; void send_image_cache_request() override; aio_type_t get_aio_type() const override { return AIO_TYPE_FLUSH; } const char *get_request_type() const override { return "aio_flush"; } }; template class ImageWriteSameRequest : public AbstractImageWriteRequest { public: ImageWriteSameRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp, uint64_t off, uint64_t len, bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace) : AbstractImageWriteRequest( image_ctx, aio_comp, {{off, len}}, "writesame", parent_trace), m_data_bl(std::move(bl)), m_op_flags(op_flags) { } protected: using typename ImageRequest::ObjectRequests; using typename AbstractImageWriteRequest::ObjectExtents; aio_type_t get_aio_type() const override { return AIO_TYPE_WRITESAME; } const char *get_request_type() const override { return "aio_writesame"; } bool assemble_writesame_extent(const ObjectExtent &object_extent, bufferlist *bl, bool force_write); void send_image_cache_request() override; void send_object_cache_requests(const ObjectExtents &object_extents, uint64_t journal_tid) override; void send_object_requests(const ObjectExtents &object_extents, const ::SnapContext &snapc, ObjectRequests *object_requests) override; ObjectRequestHandle *create_object_request( const ObjectExtent &object_extent, const ::SnapContext &snapc, Context *on_finish) override; uint64_t append_journal_event(const ObjectRequests &requests, bool synchronous) override; void update_stats(size_t length) override; private: bufferlist m_data_bl; int m_op_flags; }; template class ImageCompareAndWriteRequest : public AbstractImageWriteRequest { public: using typename ImageRequest::ObjectRequests; using typename AbstractImageWriteRequest::ObjectExtents; ImageCompareAndWriteRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp, Extents &&image_extents, bufferlist &&cmp_bl, bufferlist &&bl, uint64_t *mismatch_offset, int op_flags, const ZTracer::Trace &parent_trace) : AbstractImageWriteRequest( image_ctx, aio_comp, std::move(image_extents), "compare_and_write", parent_trace), m_cmp_bl(std::move(cmp_bl)), m_bl(std::move(bl)), m_mismatch_offset(mismatch_offset), m_op_flags(op_flags) { } protected: void send_image_cache_request() override; void send_object_cache_requests(const ObjectExtents &object_extents, uint64_t journal_tid) override; void assemble_extent(const ObjectExtent &object_extent, bufferlist *bl); ObjectRequestHandle *create_object_request(const ObjectExtent &object_extent, const ::SnapContext &snapc, Context *on_finish) override; uint64_t append_journal_event(const ObjectRequests &requests, bool synchronous) override; void update_stats(size_t length) override; aio_type_t get_aio_type() const override { return AIO_TYPE_COMPARE_AND_WRITE; } const char *get_request_type() const override { return "aio_compare_and_write"; } int prune_object_extents(ObjectExtents &object_extents) override; private: bufferlist m_cmp_bl; bufferlist m_bl; uint64_t *m_mismatch_offset; int m_op_flags; }; } // namespace io } // namespace librbd extern template class librbd::io::ImageRequest; extern template class librbd::io::ImageReadRequest; extern template class librbd::io::AbstractImageWriteRequest; extern template class librbd::io::ImageWriteRequest; extern template class librbd::io::ImageDiscardRequest; extern template class librbd::io::ImageFlushRequest; extern template class librbd::io::ImageWriteSameRequest; extern template class librbd::io::ImageCompareAndWriteRequest; #endif // CEPH_LIBRBD_IO_IMAGE_REQUEST_H