req.send();
}
-
template <typename I>
void ImageRequest<I>::send() {
I &image_ctx = this->m_image_ctx;
return;
}
+ if (finish_request_early()) {
+ return;
+ }
+
if (m_bypass_image_cache || m_image_ctx.image_cache == nullptr) {
update_timestamp();
send_request();
req_comp);
}
+template <typename I>
+bool AbstractImageWriteRequest<I>::finish_request_early() {
+ AioCompletion *aio_comp = this->m_aio_comp;
+ {
+ std::shared_lock image_locker{this->m_image_ctx.image_lock};
+ if (this->m_image_ctx.snap_id != CEPH_NOSNAP || this->m_image_ctx.read_only) {
+ aio_comp->fail(-EROFS);
+ return true;
+ }
+ }
+ uint64_t total_bytes = 0;
+ for (auto& image_extent : this->m_image_extents) {
+ total_bytes += image_extent.second;
+ }
+ if (total_bytes == 0) {
+ aio_comp->set_request_count(0);
+ return true;
+ }
+ return false;
+}
+
template <typename I>
void AbstractImageWriteRequest<I>::send_request() {
I &image_ctx = this->m_image_ctx;
// prevent image size from changing between computing clip and recording
// pending async operation
std::shared_lock image_locker{image_ctx.image_lock};
- if (image_ctx.snap_id != CEPH_NOSNAP || image_ctx.read_only) {
- aio_comp->fail(-EROFS);
- return;
- }
snapc = image_ctx.snapc;
journaling = (image_ctx.journal != nullptr &&
m_trace.event("start");
}
-
+ virtual bool finish_request_early() {
+ return false;
+ }
virtual int clip_request();
virtual void update_timestamp();
virtual void send_request() = 0;
}
void send_request() override;
+ bool finish_request_early() override;
virtual int prune_object_extents(
LightweightObjectExtents* object_extents) const {
ASSERT_EQ(0, aio_comp_ctx_2.wait());
}
+TEST_F(TestMockIoImageRequest, AioWriteEarlyFinish) {
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+
+ C_SaferCond aio_comp_ctx_1, aio_comp_ctx_2;
+ AioCompletion *aio_comp_1 = AioCompletion::create_and_start(
+ &aio_comp_ctx_1, ictx, AIO_TYPE_WRITE);
+ AioCompletion *aio_comp_2 = AioCompletion::create_and_start(
+ &aio_comp_ctx_2, ictx, AIO_TYPE_WRITE);
+
+ bufferlist bl;
+ MockImageWriteRequest mock_aio_image_write_1(mock_image_ctx, aio_comp_1,
+ {{0, 0}}, std::move(bl), 0, {});
+ {
+ std::shared_lock owner_locker{mock_image_ctx.owner_lock};
+ mock_aio_image_write_1.send();
+ }
+ ASSERT_EQ(0, aio_comp_ctx_1.wait());
+
+ mock_image_ctx.snap_id = 123;
+ bl.append("1");
+ MockImageWriteRequest mock_aio_image_write_2(mock_image_ctx, aio_comp_2,
+ {{0, 1}}, std::move(bl), 0, {});
+ {
+ std::shared_lock owner_locker{mock_image_ctx.owner_lock};
+ mock_aio_image_write_2.send();
+ }
+ ASSERT_EQ(-EROFS, aio_comp_ctx_2.wait());
+}
+
TEST_F(TestMockIoImageRequest, AioReadAccessTimestamp) {
REQUIRE_FORMAT_V2();