#include "librbd/ImageCtx.h"
#include "librbd/ImageWatcher.h"
#include "librbd/internal.h"
+#include "include/rados/librados.hpp"
+#include "osdc/Striper.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
namespace librbd {
-void AioImageRequest::read(
+void AioImageRequest::aio_read(
ImageCtx *ictx, AioCompletion *c,
const std::vector<std::pair<uint64_t,uint64_t> > &extents,
char *buf, bufferlist *pbl, int op_flags) {
req.send();
}
-void AioImageRequest::read(ImageCtx *ictx, AioCompletion *c, uint64_t off,
- size_t len, char *buf, bufferlist *pbl,
- int op_flags) {
+void AioImageRequest::aio_read(ImageCtx *ictx, AioCompletion *c, uint64_t off,
+ size_t len, char *buf, bufferlist *pbl,
+ int op_flags) {
AioImageRead req(*ictx, c, off, len, buf, pbl, op_flags);
req.send();
}
-void AioImageRequest::write(ImageCtx *ictx, AioCompletion *c, uint64_t off,
- size_t len, const char *buf, int op_flags) {
+void AioImageRequest::aio_write(ImageCtx *ictx, AioCompletion *c, uint64_t off,
+ size_t len, const char *buf, int op_flags) {
AioImageWrite req(*ictx, c, off, len, buf, op_flags);
req.send();
}
-void AioImageRequest::discard(ImageCtx *ictx, AioCompletion *c, uint64_t off,
- uint64_t len) {
+void AioImageRequest::aio_discard(ImageCtx *ictx, AioCompletion *c,
+ uint64_t off, uint64_t len) {
AioImageDiscard req(*ictx, c, off, len);
req.send();
}
-void AioImageRequest::flush(ImageCtx *ictx, AioCompletion *c) {
+void AioImageRequest::aio_flush(ImageCtx *ictx, AioCompletion *c) {
AioImageFlush req(*ictx, c);
req.send();
}
return;
}
- execute_request();
+ send_request();
}
-
-void AioImageRead::execute_request() {
+void AioImageRead::send_request() {
CephContext *cct = m_image_ctx.cct;
if (m_image_ctx.object_cacher && m_image_ctx.readahead_max_bytes > 0 &&
m_image_ctx.perfcounter->inc(l_librbd_rd_bytes, buffer_ofs);
}
-void AioImageWrite::execute_request() {
+void AbstractAioImageWrite::send_request() {
CephContext *cct = m_image_ctx.cct;
RWLock::RLocker md_locker(m_image_ctx.md_lock);
}
snapc = m_image_ctx.snapc;
- m_aio_comp->start_op(&m_image_ctx, AIO_TYPE_WRITE);
+ m_aio_comp->start_op(&m_image_ctx, AIO_TYPE_WRITE); // TODO use correct enum
}
assert(!m_image_ctx.image_watcher->is_lock_supported() ||
m_image_ctx.image_watcher->is_lock_owner());
- // map
- vector<ObjectExtent> extents;
- if (m_len > 0) {
+ // map to object extents
+ ObjectExtents extents;
+ if (clip_len > 0) {
Striper::file_to_extents(cct, m_image_ctx.format_string,
&m_image_ctx.layout, m_off, clip_len, 0, extents);
}
- for (vector<ObjectExtent>::iterator p = extents.begin();
- p != extents.end(); ++p) {
- ldout(cct, 20) << " oid " << p->oid << " " << p->offset << "~" << p->length
- << " from " << p->buffer_extents << dendl;
- // assemble extent
- bufferlist bl;
- for (vector<pair<uint64_t,uint64_t> >::iterator q =
- p->buffer_extents.begin();
- q != p->buffer_extents.end(); ++q) {
- bl.append(m_buf + q->first, q->second);
- }
-
- C_AioRequest *req_comp = new C_AioRequest(cct, m_aio_comp);
- if (m_image_ctx.object_cacher) {
- m_image_ctx.write_to_cache(p->oid, bl, p->length, p->offset, req_comp,
- m_op_flags);
- } else {
- AioObjectWrite *req = new AioObjectWrite(&m_image_ctx, p->oid.name,
- p->objectno, p->offset, bl,
- snapc, req_comp);
-
- req->set_op_flags(m_op_flags);
- req->send();
- }
- }
+ send_object_requests(extents, snapc);
+ update_stats(clip_len);
m_aio_comp->finish_adding_requests(cct);
m_aio_comp->put();
-
- m_image_ctx.perfcounter->inc(l_librbd_wr);
- m_image_ctx.perfcounter->inc(l_librbd_wr_bytes, clip_len);
}
-void AioImageDiscard::execute_request() {
+void AbstractAioImageWrite::send_object_requests(
+ const ObjectExtents &object_extents, const ::SnapContext &snapc) {
CephContext *cct = m_image_ctx.cct;
+ for (ObjectExtents::const_iterator p = object_extents.begin();
+ p != object_extents.end(); ++p) {
+ ldout(cct, 20) << " oid " << p->oid << " " << p->offset << "~" << p->length
+ << " from " << p->buffer_extents << dendl;
+ send_object_request(*p, snapc);
+ }
+}
- RWLock::RLocker md_locker(m_image_ctx.md_lock);
+void AioImageWrite::send_object_request(const ObjectExtent &object_extent,
+ const ::SnapContext &snapc) {
+ CephContext *cct = m_image_ctx.cct;
- uint64_t clip_len = m_len;
- ::SnapContext snapc;
- {
- // prevent image size from changing between computing clip and recording
- // pending async operation
- RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
- if (m_image_ctx.snap_id != CEPH_NOSNAP || m_image_ctx.read_only) {
- m_aio_comp->fail(cct, -EROFS);
- return;
- }
+ // assemble extent
+ bufferlist bl;
+ for (Extents::const_iterator q = object_extent.buffer_extents.begin();
+ q != object_extent.buffer_extents.end(); ++q) {
+ bl.append(m_buf + q->first, q->second);
+ }
- int r = clip_io(&m_image_ctx, m_off, &clip_len);
- if (r < 0) {
- m_aio_comp->fail(cct, r);
- return;
- }
+ C_AioRequest *req_comp = new C_AioRequest(cct, m_aio_comp);
+ if (m_image_ctx.object_cacher) {
+ m_image_ctx.write_to_cache(object_extent.oid, bl, object_extent.length,
+ object_extent.offset, req_comp, m_op_flags);
+ } else {
+ AioObjectWrite *req = new AioObjectWrite(&m_image_ctx,
+ object_extent.oid.name,
+ object_extent.objectno,
+ object_extent.offset, bl,
+ snapc, req_comp);
- snapc = m_image_ctx.snapc;
- m_aio_comp->start_op(&m_image_ctx, AIO_TYPE_DISCARD);
+ req->set_op_flags(m_op_flags);
+ req->send();
}
+}
- assert(!m_image_ctx.image_watcher->is_lock_supported() ||
- m_image_ctx.image_watcher->is_lock_owner());
- // map
- vector<ObjectExtent> extents;
- if (m_len > 0) {
- Striper::file_to_extents(cct, m_image_ctx.format_string,
- &m_image_ctx.layout, m_off, clip_len, 0, extents);
- }
+void AioImageWrite::update_stats(size_t length) {
+ m_image_ctx.perfcounter->inc(l_librbd_wr);
+ m_image_ctx.perfcounter->inc(l_librbd_wr_bytes, length);
+}
- for (vector<ObjectExtent>::iterator p = extents.begin();
- p != extents.end(); ++p) {
- ldout(cct, 20) << " oid " << p->oid << " " << p->offset << "~" << p->length
- << " from " << p->buffer_extents << dendl;
- C_AioRequest *req_comp = new C_AioRequest(cct, m_aio_comp);
- AioObjectRequest *req;
-
- if (p->length == m_image_ctx.layout.fl_object_size) {
- req = new AioObjectRemove(&m_image_ctx, p->oid.name, p->objectno, snapc,
- req_comp);
- } else if (p->offset + p->length == m_image_ctx.layout.fl_object_size) {
- req = new AioObjectTruncate(&m_image_ctx, p->oid.name, p->objectno,
- p->offset, snapc, req_comp);
- } else {
- if(cct->_conf->rbd_skip_partial_discard) {
- delete req_comp;
- continue;
- }
- req = new AioObjectZero(&m_image_ctx, p->oid.name, p->objectno, p->offset,
- p->length, snapc, req_comp);
- }
- req->send();
+void AioImageDiscard::send_object_requests(const ObjectExtents &object_extents,
+ const ::SnapContext &snapc) {
+ // discard from the cache first to ensure writeback won't recreate
+ if (m_image_ctx.object_cacher != NULL) {
+ Mutex::Locker cache_locker(m_image_ctx.cache_lock);
+ m_image_ctx.object_cacher->discard_set(m_image_ctx.object_set,
+ object_extents);
}
- if (m_image_ctx.object_cacher) {
- Mutex::Locker l(m_image_ctx.cache_lock);
- m_image_ctx.object_cacher->discard_set(m_image_ctx.object_set, extents);
- }
+ AbstractAioImageWrite::send_object_requests(object_extents, snapc);
+}
- m_aio_comp->finish_adding_requests(cct);
- m_aio_comp->put();
+void AioImageDiscard::send_object_request(const ObjectExtent &object_extent,
+ const ::SnapContext &snapc) {
+ CephContext *cct = m_image_ctx.cct;
+
+ C_AioRequest *req_comp = new C_AioRequest(cct, m_aio_comp);
+
+ AioObjectRequest *req;
+ if (object_extent.length == m_image_ctx.layout.fl_object_size) {
+ req = new AioObjectRemove(&m_image_ctx, object_extent.oid.name,
+ object_extent.objectno, snapc, req_comp);
+ } else if (object_extent.offset + object_extent.length ==
+ m_image_ctx.layout.fl_object_size) {
+ req = new AioObjectTruncate(&m_image_ctx, object_extent.oid.name,
+ object_extent.objectno, object_extent.offset,
+ snapc, req_comp);
+ } else {
+ if(cct->_conf->rbd_skip_partial_discard) {
+ delete req_comp;
+ return;
+ }
+ req = new AioObjectZero(&m_image_ctx, object_extent.oid.name,
+ object_extent.objectno, object_extent.offset,
+ object_extent.length, snapc, req_comp);
+ }
+ req->send();
+}
+void AioImageDiscard::update_stats(size_t length) {
m_image_ctx.perfcounter->inc(l_librbd_discard);
- m_image_ctx.perfcounter->inc(l_librbd_discard_bytes, clip_len);
+ m_image_ctx.perfcounter->inc(l_librbd_discard_bytes, length);
}
-void AioImageFlush::execute_request() {
+void AioImageFlush::send_request() {
CephContext *cct = m_image_ctx.cct;
// TODO race condition between registering op and submitting to cache
#include "include/int_types.h"
#include "include/buffer.h"
+#include "common/snap_types.h"
+#include "osd/osd_types.h"
#include <utility>
#include <vector>
class AioImageRequest {
public:
- AioImageRequest(ImageCtx &image_ctx, AioCompletion *aio_comp)
- : m_image_ctx(image_ctx), m_aio_comp(aio_comp) {}
+ typedef std::vector<std::pair<uint64_t,uint64_t> > Extents;
+
virtual ~AioImageRequest() {}
- static void read(ImageCtx *ictx, AioCompletion *c,
- const std::vector<std::pair<uint64_t,uint64_t> > &extents,
- char *buf, bufferlist *pbl, int op_flags);
- static void read(ImageCtx *ictx, AioCompletion *c, uint64_t off, size_t len,
- char *buf, bufferlist *pbl, int op_flags);
- static void write(ImageCtx *ictx, AioCompletion *c, uint64_t off, size_t len,
- const char *buf, int op_flags);
- static void discard(ImageCtx *ictx, AioCompletion *c, uint64_t off,
- uint64_t len);
- static void flush(ImageCtx *ictx, AioCompletion *c);
+ static void aio_read(ImageCtx *ictx, AioCompletion *c,
+ const std::vector<std::pair<uint64_t,uint64_t> > &extents,
+ char *buf, bufferlist *pbl, int op_flags);
+ static void aio_read(ImageCtx *ictx, AioCompletion *c, uint64_t off,
+ size_t len, char *buf, bufferlist *pbl, int op_flags);
+ static void aio_write(ImageCtx *ictx, AioCompletion *c, uint64_t off,
+ size_t len, const char *buf, int op_flags);
+ static void aio_discard(ImageCtx *ictx, AioCompletion *c, uint64_t off,
+ uint64_t len);
+ static void aio_flush(ImageCtx *ictx, AioCompletion *c);
- virtual bool is_write_op() const = 0;
+ virtual bool is_write_op() const {
+ return false;
+ }
void send();
+
protected:
ImageCtx &m_image_ctx;
AioCompletion *m_aio_comp;
- virtual void execute_request() = 0;
+ AioImageRequest(ImageCtx &image_ctx, AioCompletion *aio_comp)
+ : m_image_ctx(image_ctx), m_aio_comp(aio_comp) {}
+
+ virtual void send_request() = 0;
virtual const char *get_request_type() const = 0;
};
m_op_flags(op_flags) {
m_image_extents.push_back(std::make_pair(off, len));
}
+
AioImageRead(ImageCtx &image_ctx, AioCompletion *aio_comp,
- const std::vector<std::pair<uint64_t,uint64_t> > &image_extents,
- char *buf, bufferlist *pbl, int op_flags)
+ const Extents &image_extents, char *buf, bufferlist *pbl,
+ int op_flags)
: AioImageRequest(image_ctx, aio_comp), m_image_extents(image_extents),
m_buf(buf), m_pbl(pbl), m_op_flags(op_flags) {
}
- virtual bool is_write_op() const {
- return false;
- }
protected:
- virtual void execute_request();
+ virtual void send_request();
virtual const char *get_request_type() const {
return "aio_read";
}
private:
- std::vector<std::pair<uint64_t,uint64_t> > m_image_extents;
+ Extents m_image_extents;
char *m_buf;
bufferlist *m_pbl;
int m_op_flags;
};
-class AioImageWrite : public AioImageRequest {
+class AbstractAioImageWrite : public AioImageRequest {
+public:
+ virtual bool is_write_op() const {
+ return true;
+ }
+
+protected:
+ typedef std::vector<ObjectExtent> ObjectExtents;
+
+ AbstractAioImageWrite(ImageCtx &image_ctx, AioCompletion *aio_comp,
+ uint64_t off, size_t len)
+ : AioImageRequest(image_ctx, aio_comp), m_off(off), m_len(len) {
+ }
+
+ virtual void send_request();
+
+ virtual void send_object_requests(const ObjectExtents &object_extents,
+ const ::SnapContext &snapc);
+ virtual void send_object_request(const ObjectExtent &object_extent,
+ const ::SnapContext &snapc) = 0;
+ virtual void update_stats(size_t length) = 0;
+
+private:
+ uint64_t m_off;
+ size_t m_len;
+};
+
+class AioImageWrite : public AbstractAioImageWrite {
public:
AioImageWrite(ImageCtx &image_ctx, AioCompletion *aio_comp, uint64_t off,
size_t len, const char *buf, int op_flags)
- : AioImageRequest(image_ctx, aio_comp), m_off(off), m_len(len), m_buf(buf),
+ : AbstractAioImageWrite(image_ctx, aio_comp, off, len), m_buf(buf),
m_op_flags(op_flags) {
}
- virtual bool is_write_op() const {
- return true;
- }
protected:
- virtual void execute_request();
virtual const char *get_request_type() const {
return "aio_write";
}
+
+ virtual void send_object_request(const ObjectExtent &object_extent,
+ const ::SnapContext &snapc);
+ virtual void update_stats(size_t length);
private:
- uint64_t m_off;
- uint64_t m_len;
const char *m_buf;
int m_op_flags;
};
-class AioImageDiscard : public AioImageRequest {
+class AioImageDiscard : public AbstractAioImageWrite {
public:
AioImageDiscard(ImageCtx &image_ctx, AioCompletion *aio_comp, uint64_t off,
uint64_t len)
- : AioImageRequest(image_ctx, aio_comp), m_off(off), m_len(len) {
+ : AbstractAioImageWrite(image_ctx, aio_comp, off, len) {
}
- virtual bool is_write_op() const {
- return true;
- }
protected:
- virtual void execute_request();
virtual const char *get_request_type() const {
return "aio_discard";
}
-private:
- uint64_t m_off;
- uint64_t m_len;
+
+ virtual void send_object_requests(const ObjectExtents &object_extents,
+ const ::SnapContext &snapc);
+ virtual void send_object_request(const ObjectExtent &object_extent,
+ const ::SnapContext &snapc);
+ virtual void update_stats(size_t length);
};
class AioImageFlush : public AioImageRequest {
: AioImageRequest(image_ctx, aio_comp) {
}
- virtual bool is_write_op() const {
- return false;
- }
protected:
- virtual void execute_request();
+ virtual void send_request();
virtual const char *get_request_type() const {
return "aio_flush";
}