virtual void aio_writesame(uint64_t offset, uint64_t length,
ceph::bufferlist&& bl,
int fadvise_flags, Context *on_finish) = 0;
+ virtual void aio_compare_and_write(Extents&& image_extents,
+ ceph::bufferlist&& cmp_bl,
+ ceph::bufferlist&& bl,
+ uint64_t *mismatch_offset,
+ int fadvise_flags,
+ Context *on_finish) = 0;
/// internal state methods
virtual void init(Context *on_finish) = 0;
req.send();
}
+template <typename I>
+void ImageWriteback<I>::aio_compare_and_write(Extents &&image_extents,
+ ceph::bufferlist&& cmp_bl,
+ ceph::bufferlist&& bl,
+ uint64_t *mismatch_offset,
+ int fadvise_flags,
+ Context *on_finish) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << "image_extents=" << image_extents << ", "
+ << "on_finish=" << on_finish << dendl;
+
+ auto aio_comp = io::AioCompletion::create_and_start(on_finish, &m_image_ctx,
+ io::AIO_TYPE_COMPARE_AND_WRITE);
+ io::ImageCompareAndWriteRequest<I> req(m_image_ctx, aio_comp,
+ std::move(image_extents),
+ std::move(cmp_bl), std::move(bl),
+ mismatch_offset, fadvise_flags, {});
+ req.set_bypass_image_cache();
+ req.send();
+}
+
} // namespace cache
} // namespace librbd
void aio_writesame(uint64_t offset, uint64_t length,
ceph::bufferlist&& bl,
int fadvise_flags, Context *on_finish);
-
+ void aio_compare_and_write(Extents &&image_extents,
+ ceph::bufferlist&& cmp_bl,
+ ceph::bufferlist&& bl,
+ uint64_t *mismatch_offset,
+ int fadvise_flags, Context *on_finish);
private:
ImageCtxT &m_image_ctx;
on_finish);
}
+template <typename I>
+void PassthroughImageCache<I>::aio_compare_and_write(Extents &&image_extents,
+ bufferlist&& cmp_bl,
+ bufferlist&& bl,
+ uint64_t *mismatch_offset,
+ int fadvise_flags,
+ Context *on_finish) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << "image_extents=" << image_extents << ", "
+ << "on_finish=" << on_finish << dendl;
+
+ m_image_writeback.aio_compare_and_write(
+ std::move(image_extents), std::move(cmp_bl), std::move(bl), mismatch_offset,
+ fadvise_flags, on_finish);
+}
+
template <typename I>
void PassthroughImageCache<I>::init(Context *on_finish) {
CephContext *cct = m_image_ctx.cct;
void aio_writesame(uint64_t offset, uint64_t length,
ceph::bufferlist&& bl,
int fadvise_flags, Context *on_finish) override;
+ void aio_compare_and_write(Extents&& image_extents,
+ ceph::bufferlist&& cmp_bl, ceph::bufferlist&& bl,
+ uint64_t *mismatch_offset,int fadvise_flags,
+ Context *on_finish) override;
/// internal state methods
void init(Context *on_finish) override;
req.send();
}
+template <typename I>
+void ImageRequest<I>::aio_compare_and_write(I *ictx, AioCompletion *c,
+ Extents &&image_extents,
+ bufferlist &&cmp_bl,
+ bufferlist &&bl,
+ uint64_t *mismatch_offset,
+ int op_flags,
+ const ZTracer::Trace &parent_trace) {
+ ImageCompareAndWriteRequest<I> req(*ictx, c, std::move(image_extents),
+ std::move(cmp_bl), std::move(bl),
+ mismatch_offset, op_flags, parent_trace);
+ req.send();
+}
+
+
template <typename I>
void ImageRequest<I>::send() {
I &image_ctx = this->m_image_ctx;
CephContext *cct = image_ctx.cct;
AioCompletion *aio_comp = this->m_aio_comp;
ldout(cct, 20) << get_request_type() << ": ictx=" << &image_ctx << ", "
- << "completion=" << aio_comp << dendl;
+ << "completion=" << aio_comp << dendl;
aio_comp->get();
int r = clip_request();
image_ctx.journal->is_journal_appending());
}
- prune_object_extents(object_extents);
+ int ret = prune_object_extents(object_extents);
+ if (ret < 0) {
+ aio_comp->fail(ret);
+ return;
+ }
if (!object_extents.empty()) {
uint64_t journal_tid = 0;
}
template <typename I>
-void ImageDiscardRequest<I>::prune_object_extents(ObjectExtents &object_extents) {
+int ImageDiscardRequest<I>::prune_object_extents(ObjectExtents &object_extents) {
I &image_ctx = this->m_image_ctx;
CephContext *cct = image_ctx.cct;
if (!this->m_skip_partial_discard) {
- return;
+ return 0;
}
for (auto p = object_extents.begin(); p != object_extents.end(); ) {
++p;
}
}
+
+ return 0;
}
template <typename I>
image_ctx.perfcounter->inc(l_librbd_ws_bytes, length);
}
+template <typename I>
+uint64_t ImageCompareAndWriteRequest<I>::append_journal_event(
+ const ObjectRequests &requests, bool synchronous) {
+
+ I &image_ctx = this->m_image_ctx;
+
+ uint64_t tid = 0;
+ assert(this->m_image_extents.size() == 1);
+ auto &extent = this->m_image_extents.front();
+ journal::EventEntry event_entry(journal::AioCompareAndWriteEvent(extent.first,
+ extent.second,
+ m_cmp_bl, m_bl));
+ tid = image_ctx.journal->append_io_event(std::move(event_entry),
+ requests, extent.first,
+ extent.second, synchronous);
+
+ AioCompletion *aio_comp = this->m_aio_comp;
+ aio_comp->associate_journal_event(tid);
+
+ return tid;
+}
+
+template <typename I>
+void ImageCompareAndWriteRequest<I>::send_object_cache_requests(
+ const ObjectExtents &object_extents, uint64_t journal_tid) {
+ I &image_ctx = this->m_image_ctx;
+
+ if (image_ctx.object_cacher != NULL) {
+ Mutex::Locker cache_locker(image_ctx.cache_lock);
+ image_ctx.object_cacher->discard_set(image_ctx.object_set,
+ object_extents);
+ }
+}
+
+template <typename I>
+void ImageCompareAndWriteRequest<I>::assemble_extent(
+ const ObjectExtent &object_extent, bufferlist *bl) {
+ for (auto q = object_extent.buffer_extents.begin();
+ q != object_extent.buffer_extents.end(); ++q) {
+ bufferlist sub_bl;
+ sub_bl.substr_of(m_bl, q->first, q->second);
+ bl->claim_append(sub_bl);
+ }
+}
+
+template <typename I>
+void ImageCompareAndWriteRequest<I>::send_image_cache_request() {
+ I &image_ctx = this->m_image_ctx;
+ assert(image_ctx.image_cache != nullptr);
+
+ AioCompletion *aio_comp = this->m_aio_comp;
+ aio_comp->set_request_count(1);
+ C_AioRequest *req_comp = new C_AioRequest(aio_comp);
+ image_ctx.image_cache->aio_compare_and_write(
+ std::move(this->m_image_extents), std::move(m_cmp_bl), std::move(m_bl),
+ m_mismatch_offset, m_op_flags, req_comp);
+}
+
+template <typename I>
+ObjectRequestHandle *ImageCompareAndWriteRequest<I>::create_object_request(
+ const ObjectExtent &object_extent,
+ const ::SnapContext &snapc,
+ Context *on_finish) {
+ I &image_ctx = this->m_image_ctx;
+
+ bufferlist bl;
+ assemble_extent(object_extent, &bl);
+ ObjectRequest<I> *req = ObjectRequest<I>::create_compare_and_write(
+ &image_ctx, object_extent.oid.name,
+ object_extent.objectno, object_extent.offset,
+ m_cmp_bl, bl, snapc, m_mismatch_offset,
+ m_op_flags, this->m_trace, on_finish);
+ return req;
+}
+
+template <typename I>
+void ImageCompareAndWriteRequest<I>::update_stats(size_t length) {
+ I &image_ctx = this->m_image_ctx;
+ image_ctx.perfcounter->inc(l_librbd_cmp);
+ image_ctx.perfcounter->inc(l_librbd_cmp_bytes, length);
+}
+
+template <typename I>
+int ImageCompareAndWriteRequest<I>::prune_object_extents(ObjectExtents &object_extents) {
+ if (object_extents.size() > 1)
+ return -EINVAL;
+
+ I &image_ctx = this->m_image_ctx;
+ uint64_t sector_size = 512ULL;
+ uint64_t su = image_ctx.layout.stripe_unit;
+ ObjectExtent object_extent = object_extents.front();
+ if (object_extent.offset % sector_size + object_extent.length > sector_size ||
+ (su != 0 && (object_extent.offset % su + object_extent.length > su)))
+ return -EINVAL;
+
+ return 0;
+}
+
} // namespace io
} // namespace librbd
template class librbd::io::ImageDiscardRequest<librbd::ImageCtx>;
template class librbd::io::ImageFlushRequest<librbd::ImageCtx>;
template class librbd::io::ImageWriteSameRequest<librbd::ImageCtx>;
+template class librbd::io::ImageCompareAndWriteRequest<librbd::ImageCtx>;
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 send_request() override;
- virtual void prune_object_extents(ObjectExtents &object_extents) {
+ virtual int prune_object_extents(ObjectExtents &object_extents) {
+ return 0;
}
virtual uint32_t get_object_cache_request_count(bool journaling) const {
return 0;
return "aio_discard";
}
- void prune_object_extents(ObjectExtents &object_extents) override;
+ int prune_object_extents(ObjectExtents &object_extents) override;
void send_image_cache_request() override;
int m_op_flags;
};
+template <typename ImageCtxT = ImageCtx>
+class ImageCompareAndWriteRequest : public AbstractImageWriteRequest<ImageCtxT> {
+public:
+ using typename ImageRequest<ImageCtxT>::ObjectRequests;
+ using typename AbstractImageWriteRequest<ImageCtxT>::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<ImageCtxT>(
+ 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::ImageDiscardRequest<librbd::ImageCtx>;
extern template class librbd::io::ImageFlushRequest<librbd::ImageCtx>;
extern template class librbd::io::ImageWriteSameRequest<librbd::ImageCtx>;
+extern template class librbd::io::ImageCompareAndWriteRequest<librbd::ImageCtx>;
#endif // CEPH_LIBRBD_IO_IMAGE_REQUEST_H