}
bool ImageWatcher::try_request_lock() {
- RWLock::WLocker l(m_image_ctx.owner_lock);
+ assert(m_image_ctx.owner_lock.is_locked());
if (is_lock_owner()) {
return true;
}
- int r = try_lock();
+ int r = 0;
+ m_image_ctx.owner_lock.put_read();
+ {
+ RWLock::WLocker l(m_image_ctx.owner_lock);
+ if (!is_lock_owner()) {
+ r = try_lock();
+ }
+ }
+ m_image_ctx.owner_lock.get_read();
+
if (r < 0) {
ldout(m_image_ctx.cct, 5) << "failed to acquire exclusive lock:"
<< cpp_strerror(r) << dendl;
void ImageWatcher::finalize_request_lock() {
cancel_retry_aio_requests();
- if (try_request_lock()) {
+ bool owned_lock;
+ {
+ RWLock::RLocker l(m_image_ctx.owner_lock);
+ owned_lock = try_request_lock();
+ }
+ if (owned_lock) {
retry_aio_requests();
+
} else {
schedule_retry_aio_requests();
}
}
int ImageWatcher::notify_flatten(ProgressContext &prog_ctx) {
+ assert(m_image_ctx.owner_lock.is_locked());
+ assert(!is_lock_owner());
+
bufferlist bl;
uint64_t async_request_id;
ENCODE_START(NOTIFY_VERSION, NOTIFY_VERSION, bl);
}
int ImageWatcher::notify_resize(uint64_t size, ProgressContext &prog_ctx) {
+ assert(m_image_ctx.owner_lock.is_locked());
+ assert(!is_lock_owner());
+
bufferlist bl;
uint64_t async_request_id;
ENCODE_START(NOTIFY_VERSION, NOTIFY_VERSION, bl);
}
int ImageWatcher::notify_snap_create(const std::string &snap_name) {
+ assert(m_image_ctx.owner_lock.is_locked());
+ assert(!is_lock_owner());
+
bufferlist bl;
ENCODE_START(NOTIFY_VERSION, NOTIFY_VERSION, bl);
::encode(NOTIFY_OP_SNAP_CREATE, bl);
int ImageWatcher::decode_response_code(bufferlist &bl) {
int r;
- bufferlist::iterator iter = bl.begin();
- DECODE_START(NOTIFY_VERSION, iter);
- ::decode(r, iter);
- DECODE_FINISH(iter);
+ try {
+ bufferlist::iterator iter = bl.begin();
+ DECODE_START(NOTIFY_VERSION, iter);
+ ::decode(r, iter);
+ DECODE_FINISH(iter);
+ } catch (const buffer::error &err) {
+ r = -EINVAL;
+ }
return r;
}
void ImageWatcher::notify_request_lock() {
cancel_retry_aio_requests();
+ m_image_ctx.owner_lock.get_read();
if (try_request_lock()) {
+ m_image_ctx.owner_lock.put_read();
retry_aio_requests();
return;
}
bufferlist response;
int r = notify_lock_owner(bl, response);
+ m_image_ctx.owner_lock.put_read();
+
if (r == -ETIMEDOUT) {
ldout(m_image_ctx.cct, 5) << "timed out requesting lock: retrying" << dendl;
retry_aio_requests();
}
int ImageWatcher::notify_lock_owner(bufferlist &bl, bufferlist& response) {
+ assert(m_image_ctx.owner_lock.is_locked());
+
+ // since we need to ack our own notifications, release the owner lock just in
+ // case another notification occurs before this one and it requires the lock
bufferlist response_bl;
+ m_image_ctx.owner_lock.put_read();
int r = m_image_ctx.md_ctx.notify2(m_image_ctx.header_oid, bl, NOTIFY_TIMEOUT,
&response_bl);
+ m_image_ctx.owner_lock.get_read();
if (r < 0 && r != -ETIMEDOUT) {
lderr(m_image_ctx.cct) << "lock owner notification failed: "
<< cpp_strerror(r) << dendl;
int ImageWatcher::notify_async_request(uint64_t async_request_id,
bufferlist &in,
ProgressContext& prog_ctx) {
+ assert(m_image_ctx.owner_lock.is_locked());
+
Mutex my_lock("librbd::ImageWatcher::notify_async_request::my_lock");
Cond cond;
bool done = false;
void ImageWatcher::handle_released_lock() {
ldout(m_image_ctx.cct, 20) << "exclusive lock released" << dendl;
+ FunctionContext *ctx = new FunctionContext(
+ boost::bind(&ImageWatcher::cancel_async_requests, this, -ERESTART));
+ m_finisher->queue(ctx);
Mutex::Locker l(m_aio_request_lock);
if (!m_aio_requests.empty()) {
ldout(m_image_ctx.cct, 20) << "queuing lock request" << dendl;
- FunctionContext *ctx = new FunctionContext(
+ FunctionContext *req_ctx = new FunctionContext(
boost::bind(&ImageWatcher::finalize_request_lock, this));
- m_finisher->queue(ctx);
+ m_finisher->queue(req_ctx);
}
}
::decode(snap_name, iter);
ldout(m_image_ctx.cct, 20) << "remote snap_create request: " << snap_name << dendl;
-
int r = librbd::snap_create(&m_image_ctx, snap_name.c_str(), false);
ENCODE_START(NOTIFY_VERSION, NOTIFY_VERSION, *out);
::encode(r, *out);
void trim_image(ImageCtx *ictx, uint64_t newsize, ProgressContext& prog_ctx)
{
+ assert(ictx->owner_lock.is_locked());
+ assert(!ictx->image_watcher->is_lock_supported() ||
+ ictx->image_watcher->is_lock_owner());
+
Mutex my_lock("librbd::trim_image::my_lock");
Cond cond;
bool done;
{
assert(ictx->owner_lock.is_locked() && !ictx->owner_lock.is_wlocked());
if (ictx->image_watcher == NULL) {
- return -EROFS;;
+ return -EROFS;
} else if (!ictx->image_watcher->is_lock_supported() ||
ictx->image_watcher->is_lock_owner()) {
return 0;
if (r < 0)
return r;
- r = prepare_image_update(ictx);
- if (r < 0) {
- return -EROFS;
- }
- if (ictx->image_watcher->is_lock_supported() &&
- !ictx->image_watcher->is_lock_owner()) {
- return ictx->image_watcher->notify_snap_create(snap_name);
+ while (ictx->image_watcher->is_lock_supported()) {
+ r = prepare_image_update(ictx);
+ if (r < 0) {
+ return -EROFS;
+ } else if (ictx->image_watcher->is_lock_owner()) {
+ break;
+ }
+
+ r = ictx->image_watcher->notify_snap_create(snap_name);
+ if (r != -ETIMEDOUT) {
+ return r;
+ }
+ ldout(ictx->cct, 5) << "snap_create timed out notifying lock owner" << dendl;
}
RWLock::RLocker l2(ictx->md_lock);
unknown_format = false;
id = ictx->id;
+ ictx->owner_lock.get_read();
+ if (ictx->image_watcher->is_lock_supported()) {
+ r = prepare_image_update(ictx);
+ if (r < 0 || !ictx->image_watcher->is_lock_owner()) {
+ lderr(cct) << "cannot obtain exclusive lock - not removing" << dendl;
+ ictx->owner_lock.put_read();
+ close_image(ictx);
+ return -EBUSY;
+ }
+ }
+
if (ictx->snaps.size()) {
lderr(cct) << "image has snapshots - not removing" << dendl;
+ ictx->owner_lock.put_read();
close_image(ictx);
return -ENOTEMPTY;
}
r = io_ctx.list_watchers(header_oid, &watchers);
if (r < 0) {
lderr(cct) << "error listing watchers" << dendl;
+ ictx->owner_lock.put_read();
close_image(ictx);
return r;
}
if (watchers.size() > 1) {
lderr(cct) << "image has watchers - not removing" << dendl;
+ ictx->owner_lock.put_read();
close_image(ictx);
return -EBUSY;
}
parent_info.spec, id);
if (r < 0 && r != -ENOENT) {
lderr(cct) << "error removing child from children list" << dendl;
+ ictx->owner_lock.put_read();
close_image(ictx);
return r;
}
+
+ ictx->owner_lock.put_read();
close_image(ictx);
ldout(cct, 2) << "removing header..." << dendl;
ldout(cct, 20) << "resize " << ictx << " " << ictx->size << " -> "
<< size << dendl;
- {
- RWLock::RLocker l(ictx->owner_lock);
- int r = prepare_image_update(ictx);
- if (r < 0) {
- return -EROFS;
- }
- if (ictx->image_watcher->is_lock_supported() &&
- !ictx->image_watcher->is_lock_owner()) {
- return ictx->image_watcher->notify_resize(size, prog_ctx);
- }
- }
+ int r;
+ do {
+ Mutex my_lock("librbd::resize::my_lock");
+ Cond cond;
+ bool done;
+ {
+ RWLock::RLocker l(ictx->owner_lock);
+ while (ictx->image_watcher->is_lock_supported()) {
+ r = prepare_image_update(ictx);
+ if (r < 0) {
+ return -EROFS;
+ } else if (ictx->image_watcher->is_lock_owner()) {
+ break;
+ }
- Mutex my_lock("librbd::resize::my_lock");
- Cond cond;
- bool done;
- int ret;
- Context *ctx = new C_SafeCond(&my_lock, &cond, &done, &ret);
+ r = ictx->image_watcher->notify_resize(size, prog_ctx);
+ if (r != -ETIMEDOUT && r != -ERESTART) {
+ return r;
+ }
+ ldout(ictx->cct, 5) << "resize timed out notifying lock owner" << dendl;
+ }
- ret = async_resize(ictx, ctx, size, prog_ctx);
- if (ret < 0) {
- delete ctx;
- return ret;
- }
+ Context *ctx = new C_SafeCond(&my_lock, &cond, &done, &r);
+ r = async_resize(ictx, ctx, size, prog_ctx);
+ if (r < 0) {
+ delete ctx;
+ return r;
+ }
+ }
- my_lock.Lock();
- while (!done) {
- cond.Wait(my_lock);
- }
- my_lock.Unlock();
+ my_lock.Lock();
+ while (!done) {
+ cond.Wait(my_lock);
+ }
+ my_lock.Unlock();
+
+ if (r == -ERESTART) {
+ ldout(ictx->cct, 5) << "resize interrupted: restarting" << dendl;
+ }
+ } while (r == -ERESTART);
notify_change(ictx->md_ctx, ictx->header_oid, ictx);
ldout(cct, 2) << "resize finished" << dendl;
- return ret;
+ return r;
}
class AsyncResizeFinishContext : public Context {
int async_resize(ImageCtx *ictx, Context *ctx, uint64_t size,
ProgressContext &prog_ctx)
{
+ assert(ictx->owner_lock.is_locked());
+ assert(!ictx->image_watcher->is_lock_supported() ||
+ ictx->image_watcher->is_lock_owner());
+
CephContext *cct = ictx->cct;
ldout(cct, 20) << "async_resize " << ictx << " " << ictx->size << " -> "
<< size << dendl;
uint64_t original_size;
{
- RWLock::RLocker l(ictx->owner_lock);
- r = prepare_image_update(ictx);
- if (r < 0) {
- return -EROFS;
- }
- if (ictx->image_watcher->is_lock_supported() &&
- !ictx->image_watcher->is_lock_owner()) {
- return -EROFS;
- }
-
- RWLock::RLocker l2(ictx->md_lock);
+ RWLock::RLocker l(ictx->md_lock);
original_size = ictx->size;
if (size < ictx->size) {
ictx->wait_for_pending_copyup();
RWLock::RLocker l(m_ictx->owner_lock);
if (m_ictx->image_watcher->is_lock_supported() &&
!m_ictx->image_watcher->is_lock_owner()) {
- r = -EROFS;
+ r = -ERESTART;
return;
}
RWLock::RLocker l(m_ictx->owner_lock);
if (m_ictx->image_watcher->is_lock_supported() &&
!m_ictx->image_watcher->is_lock_owner()) {
- return -EROFS;
+ return -ERESTART;
}
string oid = m_ictx->get_object_name(m_object_no);
RWLock::RLocker l(m_ictx->owner_lock);
if (m_ictx->image_watcher->is_lock_supported() &&
!m_ictx->image_watcher->is_lock_owner()) {
- r = -EROFS;
+ r = -ERESTART;
return;
}
RWLock::RLocker l(m_ictx->owner_lock);
if (m_ictx->image_watcher->is_lock_supported() &&
!m_ictx->image_watcher->is_lock_owner()) {
- return -EROFS;
+ return -ERESTART;
}
RWLock::RLocker l2(m_ictx->md_lock);
RWLock::RLocker l(m_ictx->owner_lock);
if (m_ictx->image_watcher->is_lock_supported() &&
!m_ictx->image_watcher->is_lock_owner()) {
- r = -EROFS;
+ r = -ERESTART;
return;
}
return -EROFS;
}
- {
- RWLock::RLocker l(ictx->owner_lock);
- int r = prepare_image_update(ictx);
- if (r < 0) {
- return -EROFS;
- }
- if (ictx->image_watcher->is_lock_supported() &&
- !ictx->image_watcher->is_lock_owner()) {
- return ictx->image_watcher->notify_flatten(prog_ctx);
- }
- }
+ int r;
+ do {
+ Mutex my_lock("librbd::flatten:my_lock");
+ Cond cond;
+ bool done;
+ {
+ RWLock::RLocker l(ictx->owner_lock);
+ while (ictx->image_watcher->is_lock_supported()) {
+ r = prepare_image_update(ictx);
+ if (r < 0) {
+ return -EROFS;
+ } else if (ictx->image_watcher->is_lock_owner()) {
+ break;
+ }
- Mutex my_lock("librbd::flatten:my_lock");
- Cond cond;
- bool done;
- int ret;
- Context *ctx = new C_SafeCond(&my_lock, &cond, &done, &ret);
+ r = ictx->image_watcher->notify_flatten(prog_ctx);
+ if (r != -ETIMEDOUT && r != -ERESTART) {
+ return r;
+ }
+ ldout(ictx->cct, 5) << "flatten timed out notifying lock owner" << dendl;
+ }
- ret = async_flatten(ictx, ctx, prog_ctx);
- if (ret < 0) {
- delete ctx;
- return ret;
- }
+ Context *ctx = new C_SafeCond(&my_lock, &cond, &done, &r);
+ r = async_flatten(ictx, ctx, prog_ctx);
+ if (r < 0) {
+ delete ctx;
+ return r;
+ }
+ }
- my_lock.Lock();
- while (!done) {
- cond.Wait(my_lock);
- }
- my_lock.Unlock();
+ my_lock.Lock();
+ while (!done) {
+ cond.Wait(my_lock);
+ }
+ my_lock.Unlock();
+
+ if (r == -ERESTART) {
+ ldout(ictx->cct, 5) << "flatten interrupted: restarting" << dendl;
+ }
+ } while (r == -ERESTART);
notify_change(ictx->md_ctx, ictx->header_oid, ictx);
ldout(cct, 20) << "flatten finished" << dendl;
- return ret;
+ return r;
}
int async_flatten(ImageCtx *ictx, Context *ctx, ProgressContext &prog_ctx)
{
+ assert(ictx->owner_lock.is_locked());
+ assert(!ictx->image_watcher->is_lock_supported() ||
+ ictx->image_watcher->is_lock_owner());
+
CephContext *cct = ictx->cct;
ldout(cct, 20) << "flatten" << dendl;
overlap_objects = Striper::get_num_objects(ictx->layout, overlap);
}
- {
- RWLock::RLocker l(ictx->owner_lock);
- r = prepare_image_update(ictx);
- if (r < 0) {
- return -EROFS;
- }
- if (ictx->image_watcher->is_lock_supported() &&
- !ictx->image_watcher->is_lock_owner()) {
- // TODO: temporary until request proxied to lock owner
- return -EROFS;
- }
- }
-
AsyncObjectThrottle::ContextFactory context_factory(
boost::lambda::bind(boost::lambda::new_ptr<AsyncFlattenObjectContext>(),
boost::lambda::_1, ictx, object_size, snapc,