*id = payload.async_request_id;
}
return true;
+ case NOTIFY_OP_UPDATE_FEATURES:
+ {
+ UpdateFeaturesPayload payload;
+ payload.decode(7, iter);
+ *id = payload.async_request_id;
+ }
+ return true;
default:
break;
}
}
};
+struct UpdateFeaturesTask {
+ librbd::ImageCtx *ictx;
+ int result;
+
+ UpdateFeaturesTask(librbd::ImageCtx *ictx)
+ : ictx(ictx), result(0) {}
+
+ void operator()() {
+ std::shared_lock l{ictx->owner_lock};
+ C_SaferCond ctx;
+ uint64_t features = 24;
+ bool enabled = 0;
+ ictx->image_watcher->notify_update_features(0, features, enabled, &ctx);
+ result = ctx.wait();
+ }
+};
+
TEST_F(TestImageWatcher, NotifyHeaderUpdate) {
REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
ASSERT_EQ(0, rebuild_task.result);
}
+TEST_F(TestImageWatcher, NotifyUpdateFeatures) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ ASSERT_EQ(0, register_image_watch(*ictx));
+ ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE,
+ "auto " + stringify(m_watch_ctx->get_handle())));
+
+ m_notify_acks = {{NOTIFY_OP_UPDATE_FEATURES, create_response_message(0)}};
+
+ UpdateFeaturesTask update_features_task(ictx);
+ boost::thread thread(boost::ref(update_features_task));
+
+ ASSERT_TRUE(wait_for_notifies(*ictx));
+
+ NotifyOps expected_notify_ops;
+ expected_notify_ops += NOTIFY_OP_UPDATE_FEATURES;
+ ASSERT_EQ(expected_notify_ops, m_notifies);
+
+ AsyncRequestId async_request_id;
+ ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_UPDATE_FEATURES,
+ &async_request_id));
+
+ ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0));
+ ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
+ ASSERT_EQ(0, update_features_task.result);
+}
+
TEST_F(TestImageWatcher, NotifySnapCreate) {
REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
ASSERT_TRUE(lock_owner);
}
+TEST_F(TestLibRBD, UpdateFeaturesViaLockOwner) {
+
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
+
+ std::string name = get_temp_image_name();
+ uint64_t size = 2 << 20;
+ librbd::RBD rbd;
+ int order = 0;
+ //creates full with rbd default features
+ ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
+
+ bool lock_owner;
+ librbd::Image image1;
+ ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
+ bufferlist bl;
+ ASSERT_EQ(0, image1.write(0, 0, bl));
+ ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
+ ASSERT_TRUE(lock_owner);
+
+ librbd::Image image2;
+ ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
+ ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
+ ASSERT_FALSE(lock_owner);
+
+ ASSERT_EQ(0, image2.update_features(RBD_FEATURE_OBJECT_MAP, false));
+ ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
+ ASSERT_FALSE(lock_owner);
+
+ ASSERT_EQ(0, image2.update_features(RBD_FEATURE_OBJECT_MAP, true));
+ ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
+ ASSERT_FALSE(lock_owner);
+
+}
+
TEST_F(TestLibRBD, EnableJournalingViaLockOwner)
{
REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);