m_ictx(NULL), m_ioctx(NULL),
m_object_no(0), m_object_off(0), m_object_len(0),
m_snap_id(CEPH_NOSNAP), m_completion(NULL), m_parent_completion(NULL),
- m_hide_enoent(false), m_entire_object(NULL) {}
+ m_hide_enoent(false) {}
AioRequest::AioRequest(ImageCtx *ictx, const std::string &oid,
uint64_t objectno, uint64_t off, uint64_t len,
const ::SnapContext &snapc, librados::snap_t snap_id,
m_ictx(ictx), m_ioctx(&ictx->data_ctx), m_oid(oid), m_object_no(objectno),
m_object_off(off), m_object_len(len), m_snap_id(snap_id),
m_completion(completion), m_parent_completion(NULL),
- m_hide_enoent(hide_enoent), m_entire_object(NULL) {
+ m_hide_enoent(hide_enoent) {
for (std::vector<snapid_t>::const_iterator it = snapc.snaps.begin();
it != snapc.snaps.end(); ++it)
m_snaps.push_back(it->val);
m_parent_completion, 0);
}
- static inline bool is_cor(ImageCtx *ictx, librados::snap_t snap_id) {
- return (ictx->cct->_conf->rbd_clone_copy_on_read) &&
- (!ictx->read_only) && (snap_id == CEPH_NOSNAP);
+ static inline bool is_copy_on_read(ImageCtx *ictx, librados::snap_t snap_id) {
+ assert(ictx->snap_lock.is_locked());
+ return (ictx->cct->_conf->rbd_clone_copy_on_read) &&
+ (!ictx->read_only) && (snap_id == CEPH_NOSNAP);
}
/** read **/
- void AioRead::guard_read()
- {
+ AioRead::AioRead(ImageCtx *ictx, const std::string &oid,
+ uint64_t objectno, uint64_t offset, uint64_t len,
+ vector<pair<uint64_t,uint64_t> >& be,
+ const ::SnapContext &snapc,
+ librados::snap_t snap_id, bool sparse,
+ Context *completion, int op_flags)
+ : AioRequest(ictx, oid, objectno, offset, len, snapc, snap_id, completion,
+ false),
+ m_buffer_extents(be), m_tried_parent(false),
+ m_sparse(sparse), m_op_flags(op_flags), m_state(LIBRBD_AIO_READ_FLAT) {
RWLock::RLocker l(m_ictx->snap_lock);
RWLock::RLocker l2(m_ictx->parent_lock);
- vector<pair<uint64_t,uint64_t> > image_extents;
Striper::extent_to_file(m_ictx->cct, &m_ictx->layout,
m_object_no, 0, m_ictx->layout.fl_object_size,
- image_extents);
+ m_image_extents);
+
+ guard_read();
+ }
+
+ void AioRead::guard_read()
+ {
+ assert(m_ictx->snap_lock.is_locked());
uint64_t image_overlap = 0;
m_ictx->get_parent_overlap(m_snap_id, &image_overlap);
uint64_t object_overlap =
- m_ictx->prune_parent_extents(image_extents, image_overlap);
+ m_ictx->prune_parent_extents(m_image_extents, image_overlap);
if (object_overlap) {
ldout(m_ictx->cct, 20) << __func__ << " guarding read" << dendl;
m_state = LIBRBD_AIO_READ_GUARD;
bool AioRead::should_complete(int r)
{
- ldout(m_ictx->cct, 20) << "AioRead::should_complete " << this
- << " " << m_oid << " " << m_object_off
- << "~" << m_object_len << " r = " << r
- << " cor = " << is_cor(m_ictx, m_snap_id)
- << " readonly = " << m_ictx->read_only
- << dendl;
+ ldout(m_ictx->cct, 20) << "should_complete " << this << " " << m_oid << " " << m_object_off << "~" << m_object_len
+ << " r = " << r << dendl;
bool finished = true;
RWLock::RLocker l(m_ictx->snap_lock);
RWLock::RLocker l2(m_ictx->parent_lock);
+ if (m_ictx->parent == NULL) {
+ ldout(m_ictx->cct, 20) << "parent is gone; do nothing" << dendl;
+ m_state = LIBRBD_AIO_READ_FLAT;
+ finished = false;
+ break;
+ }
+
// calculate reverse mapping onto the image
vector<pair<uint64_t,uint64_t> > image_extents;
Striper::extent_to_file(m_ictx->cct, &m_ictx->layout,
if (object_overlap) {
m_tried_parent = true;
- if (is_cor(m_ictx, m_snap_id)) {
+ if (is_copy_on_read(m_ictx, m_snap_id)) {
// If there is a valid object being coyping up, directly extract
// content and finish up.
Mutex::Locker l3(m_ictx->copyup_list_lock);
read_from_parent(image_extents);
- if (is_cor(m_ictx, m_snap_id))
+ if (is_copy_on_read(m_ictx, m_snap_id))
m_state = LIBRBD_AIO_READ_COPYUP;
else
m_state = LIBRBD_AIO_READ_GUARD;
// It is different from copy-on-write as asynchronous copyup will finish
// by itself so state won't go back to LIBRBD_AIO_READ_GUARD.
- if (m_tried_parent && r > 0) {
+ assert(m_tried_parent);
+ if (r > 0) {
// If read entire object from parent success and CoR is possible, kick
// off a asynchronous copyup. This approach minimizes the latency
// impact.
map<uint64_t, CopyupRequest*>::iterator it =
m_ictx->copyup_list.find(m_object_no);
if (it == m_ictx->copyup_list.end()) {
- // create and kick off a CopyupRequest
- CopyupRequest *new_req = new CopyupRequest(m_ictx, m_oid,
- m_object_no, true);
- pair<uint64_t, CopyupRequest*> new_slot =
- pair<uint64_t, CopyupRequest*>(m_object_no, new_req);
- m_ictx->copyup_list.insert(new_slot);
- m_ictx->copyup_list_lock.Unlock();
-
RWLock::RLocker l(m_ictx->snap_lock);
RWLock::RLocker l2(m_ictx->parent_lock);
- vector<pair<uint64_t,uint64_t> > extend_image_extents;
- //extend range to entire object
- Striper::extent_to_file(m_ictx->cct, &m_ictx->layout, m_object_no,
- 0, m_ictx->layout.fl_object_size,
- extend_image_extents);
- uint64_t image_overlap = 0;
- r = m_ictx->get_parent_overlap(m_snap_id, &image_overlap);
- if (r < 0) {
- assert(0 == "FIXME");
+ if (m_ictx->parent == NULL) {
+ ldout(m_ictx->cct, 20) << "parent is gone; do nothing" << dendl;
+ m_state = LIBRBD_AIO_READ_FLAT;
+ finished = true;
+ break;
}
- m_ictx->prune_parent_extents(extend_image_extents, image_overlap);
- m_ictx->copyup_list[m_object_no]->read_from_parent(extend_image_extents);
+ // If parent still exists, overlap might also have changed.
+ uint64_t newlen = m_ictx->prune_parent_extents(
+ m_image_extents, m_ictx->parent_md.overlap);
+ if (newlen != 0) {
+ // create and kick off a CopyupRequest
+ CopyupRequest *new_req = new CopyupRequest(m_ictx, m_oid,
+ m_object_no, true);
+ m_ictx->copyup_list[m_object_no] = new_req;
+ m_ictx->copyup_list_lock.Unlock();
+
+ new_req->read_from_parent(m_image_extents);
+ }
} else {
m_ictx->copyup_list_lock.Unlock();
}
break;
case LIBRBD_AIO_READ_FLAT:
ldout(m_ictx->cct, 20) << "should_complete " << this << " READ_FLAT" << dendl;
- // The read contect should be deposit in m_read_data
+ // The read content should be deposit in m_read_data
break;
default:
lderr(m_ictx->cct) << "invalid request state: " << m_state << dendl;
bool hide_enoent)
: AioRequest(ictx, oid, object_no, object_off, len, snapc, snap_id,
completion, hide_enoent),
- m_state(LIBRBD_AIO_WRITE_FLAT), m_snap_seq(snapc.seq.val)
+ m_state(LIBRBD_AIO_WRITE_FLAT), m_snap_seq(snapc.seq.val), m_entire_object(NULL)
{
m_object_image_extents = objectx;
m_parent_overlap = object_overlap;
m_state = LIBRBD_AIO_WRITE_COPYUP;
- if (is_cor(m_ictx, m_snap_id)) {
+ if (is_copy_on_read(m_ictx, m_snap_id)) {
m_ictx->copyup_list_lock.Lock();
it = m_ictx->copyup_list.find(m_object_no);
if (it == m_ictx->copyup_list.end()) {
m_object_no, false);
// make sure to wait on this CopyupRequest
new_req->append_request(this);
- pair<uint64_t, CopyupRequest*> new_slot =
- pair<uint64_t, CopyupRequest*>(m_object_no, new_req);
- m_ictx->copyup_list.insert(new_slot);
+ m_ictx->copyup_list[m_object_no] = new_req;
m_ictx->copyup_list_lock.Unlock();
- m_entire_object = &(m_ictx->copyup_list[m_object_no]->get_copyup_data());
+ m_entire_object = &(new_req->get_copyup_data());
ldout(m_ictx->cct, 20) << __func__ << " creating new Copyup for AioWrite, obj-"
<< m_object_no << dendl;
- m_ictx->copyup_list[m_object_no]->read_from_parent(m_object_image_extents);
+ new_req->read_from_parent(m_object_image_extents);
ldout(m_ictx->cct, 20) << __func__ << " issuing read_from_parent" << dendl;
} else {
Mutex::Locker l3(it->second->get_lock());
} else {
ldout(m_ictx->cct, 20) << __func__ << " someone is reading back from parent" << dendl;
it->second->append_request(this);
- m_ictx->copyup_list_lock.Unlock();
-
m_entire_object = &(m_ictx->copyup_list[m_object_no]->get_copyup_data());
+ m_ictx->copyup_list_lock.Unlock();
}
}
- } else
+ } else {
read_from_parent(m_object_image_extents);
+ }
} else {
ldout(m_ictx->cct, 20) << "should_complete(" << this
<< "): parent overlap now 0" << dendl;
// Read data from waiting list safely. If this AioWrite created a
// CopyupRequest, m_read_data should be empty.
- if (m_read_data.is_zero()) {
- Mutex::Locker l(m_ictx->copyup_list_lock);
- ldout(m_ictx->cct, 20) << __func__ << " releasing self pending, obj-"
- << m_object_no << dendl;
- it = m_ictx->copyup_list.find(m_object_no);
- assert(it != m_ictx->copyup_list.end());
- assert(it->second->is_ready());
- assert(m_entire_object);
- m_read_data.append(*m_entire_object);
+ {
+ RWLock::RLocker l3(m_ictx->snap_lock);
+ if (is_copy_on_read(m_ictx, m_snap_id) &&
+ m_read_data.is_zero()) {
+ Mutex::Locker l(m_ictx->copyup_list_lock);
+ ldout(m_ictx->cct, 20) << __func__ << " releasing self pending, obj-"
+ << m_object_no << dendl;
+ it = m_ictx->copyup_list.find(m_object_no);
+ assert(it != m_ictx->copyup_list.end());
+ assert(it->second->is_ready());
+ assert(m_entire_object);
+ m_read_data.append(*m_entire_object);
+ }
}
send_copyup();
#define dout_prefix *_dout << "librbd::CopyupRequest: "
namespace librbd {
- CopyupRequest::CopyupRequest()
- : m_ictx(NULL), m_object_no(0), m_lock("librbd::CopyupRequest::m_lock"),
- m_ready(false), m_need_copyup(false), m_parent_completion(NULL),
- m_copyup_completion(NULL) {}
CopyupRequest::CopyupRequest(ImageCtx *ictx, const std::string &oid,
- uint64_t objectno, bool need_copyup)
+ uint64_t objectno, bool send_copyup)
: m_ictx(ictx), m_oid(oid), m_object_no(objectno),
m_lock("librbd::CopyupRequest::m_lock"), m_ready(false),
- m_need_copyup(need_copyup), m_parent_completion(NULL),
+ m_send_copyup(send_copyup), m_parent_completion(NULL),
m_copyup_completion(NULL) {}
CopyupRequest::~CopyupRequest() {
return m_ready;
}
- bool CopyupRequest::is_need_send_copyup() {
- return m_need_copyup;
+ bool CopyupRequest::should_send_copyup() {
+ return m_send_copyup;
}
ceph::bufferlist& CopyupRequest::get_copyup_data() {
aio_read(m_ictx->parent, image_extents, NULL, &m_copyup_data, m_parent_completion, 0);
}
- void rbd_read_from_parent_cb(completion_t cb, void *arg)
+ void CopyupRequest::rbd_read_from_parent_cb(completion_t cb, void *arg)
{
CopyupRequest *req = reinterpret_cast<CopyupRequest *>(arg);
AioCompletion *comp = reinterpret_cast<AioCompletion *>(cb);
ldout(req->m_ictx->cct, 20) << __func__ << dendl;
- req->get_lock().Lock();
+ req->m_lock.Lock();
req->set_ready();
req->complete_all(comp->get_return_value());
- req->get_lock().Unlock();
+ req->m_lock.Unlock();
// If this entry is created by a read request, then copyup operation will
// be performed asynchronously. Perform cleaning up from copyup callback.
// If this entry is created by a write request, then copyup operation will
// be performed synchronously by AioWrite. After extracting data, perform
// cleaning up here
- if (req->is_need_send_copyup())
+ if (req->should_send_copyup())
req->send_copyup(comp->get_return_value());
else
delete req;
}
- void rbd_copyup_cb(rados_completion_t c, void *arg)
+ void CopyupRequest::rbd_copyup_cb(rados_completion_t c, void *arg)
{
CopyupRequest *req = reinterpret_cast<CopyupRequest *>(arg);