unlock();
}
+void ImageWatcher::finalize_header_update() {
+ librbd::notify_change(m_image_ctx.md_ctx, m_image_ctx.header_oid,
+ &m_image_ctx);
+}
+
int ImageWatcher::notify_async_progress(const RemoteAsyncRequest &request,
uint64_t offset, uint64_t total) {
ldout(m_image_ctx.cct, 20) << "remote async request progress: "
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());
+ int r = librbd::snap_create(&m_image_ctx, snap_name.c_str(), false);
ENCODE_START(NOTIFY_VERSION, NOTIFY_VERSION, *out);
::encode(r, *out);
ENCODE_FINISH(*out);
+
+ if (r == 0) {
+ // cannot notify within a notificiation
+ FunctionContext *ctx = new FunctionContext(
+ boost::bind(&ImageWatcher::finalize_header_update, this));
+ m_finisher->queue(ctx);
+ }
}
}
void release_lock();
bool try_request_lock();
void finalize_request_lock();
+ void finalize_header_update();
void schedule_retry_aio_requests();
void cancel_retry_aio_requests();
return r;
}
- int snap_create(ImageCtx *ictx, const char *snap_name)
+ int snap_create(ImageCtx *ictx, const char *snap_name, bool notify)
{
assert(ictx->owner_lock.is_locked());
ldout(ictx->cct, 20) << "snap_create " << ictx << " " << snap_name << dendl;
}
if (ictx->image_watcher->is_lock_supported() &&
!ictx->image_watcher->is_lock_owner()) {
- // TODO: temporary until request proxied to lock owner
- return -EROFS;
+ return ictx->image_watcher->notify_snap_create(snap_name);
}
RWLock::RLocker l2(ictx->md_lock);
if (r < 0)
return r;
- notify_change(ictx->md_ctx, ictx->header_oid, ictx);
+ if (notify) {
+ notify_change(ictx->md_ctx, ictx->header_oid, ictx);
+ }
ictx->perfcounter->inc(l_librbd_snap_create);
return 0;
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);
+ }
+ }
+
Mutex my_lock("librbd::resize::my_lock");
Cond cond;
bool done;
int ret;
-
Context *ctx = new C_SafeCond(&my_lock, &cond, &done, &ret);
+
ret = async_resize(ictx, ctx, size, prog_ctx);
if (ret < 0) {
delete ctx;
CephContext *cct = ictx->cct;
ldout(cct, 20) << "flatten" << dendl;
+ if (ictx->read_only || ictx->snap_id != CEPH_NOSNAP) {
+ 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);
+ }
+ }
+
Mutex my_lock("librbd::flatten:my_lock");
Cond cond;
bool done;
int ret;
-
Context *ctx = new C_SafeCond(&my_lock, &cond, &done, &ret);
+
ret = async_flatten(ictx, ctx, prog_ctx);
if (ret < 0) {
delete ctx;
int remove(librados::IoCtx& io_ctx, const char *imgname,
ProgressContext& prog_ctx);
int resize(ImageCtx *ictx, uint64_t size, ProgressContext& prog_ctx);
- int snap_create(ImageCtx *ictx, const char *snap_name);
+ int snap_create(ImageCtx *ictx, const char *snap_name, bool notify);
int snap_list(ImageCtx *ictx, std::vector<snap_info_t>& snaps);
bool snap_exists(ImageCtx *ictx, const char *snap_name);
int snap_rollback(ImageCtx *ictx, const char *snap_name,
ImageCtx *ictx = (ImageCtx *)ctx;
tracepoint(librbd, snap_create_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
RWLock::RLocker owner_locker(ictx->owner_lock);
- int r = librbd::snap_create(ictx, snap_name);
+ int r = librbd::snap_create(ictx, snap_name, true);
tracepoint(librbd, snap_create_exit, r);
return r;
}
librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
tracepoint(librbd, snap_create_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
RWLock::RLocker owner_locker(ictx->owner_lock);
- int r = librbd::snap_create(ictx, snap_name);
+ int r = librbd::snap_create(ictx, snap_name, true);
tracepoint(librbd, snap_create_exit, r);
return r;
}
{
RWLock::RLocker l(ictx->owner_lock);
- r = librbd::snap_create(ictx, snap_name);
+ r = librbd::snap_create(ictx, snap_name, true);
}
if (r < 0) {
return r;
{
RWLock::RLocker l(ictx->owner_lock);
- ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
+ ASSERT_EQ(0, librbd::snap_create(ictx, "snap1", true));
}
BOOST_SCOPE_EXIT( (ictx) ) {
ASSERT_EQ(0, librbd::snap_remove(ictx, "snap1"));
ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE, "manually locked"));
RWLock::RLocker l(ictx->owner_lock);
- ASSERT_EQ(-EROFS, librbd::snap_create(ictx, "snap1"));
+ ASSERT_EQ(-EROFS, librbd::snap_create(ictx, "snap1", true));
}
TEST_F(TestInternal, SnapRollbackLocksImage) {
RBD().clone(ioctx, image_name, 'snap', ioctx, 'clone', features)
with nested(Image(ioctx, 'clone'), Image(ioctx2, 'clone')) as (
image1, image2):
- image1.write('0'*256, 0)
- assert_raises(ReadOnlyImage, image2.flatten)
- image1.flatten()
+ data = rand_data(256)
+ image1.write(data, 0)
+ image2.flatten()
+ assert_raises(ImageNotFound, image1.parent_info)
+ parent = True
+ for x in xrange(30):
+ try:
+ image2.parent_info()
+ except ImageNotFound:
+ parent = False
+ break
+ eq(False, parent)
finally:
RBD().remove(ioctx, 'clone')
with Image(ioctx, image_name) as image:
image1, image2):
image1.write('0'*256, 0)
for new_size in [IMG_SIZE * 2, IMG_SIZE / 2]:
- assert_raises(ReadOnlyImage, image2.resize, new_size)
- image1.resize(new_size);
+ image2.resize(new_size);
+ eq(new_size, image1.size())
+ for x in xrange(30):
+ if new_size == image2.size():
+ break
+ time.sleep(1)
+ eq(new_size, image2.size())
+
+ def test_follower_snap_create(self):
+ with nested(Image(ioctx, image_name), Image(ioctx2, image_name)) as (
+ image1, image2):
+ image2.create_snap('snap1')
+ image1.remove_snap('snap1')
def test_follower_snap_rollback(self):
with nested(Image(ioctx, image_name), Image(ioctx2, image_name)) as (