@@ -13625,6 +13625,171 @@ TEST_F(TestLibRBD, ConcurrentOperations)
1362513625 ioctx.close();
1362613626}
1362713627
13628+ TEST_F (TestLibRBD, FormatAndCloneFormatOptions)
13629+ {
13630+ REQUIRE_FEATURE (RBD_FEATURE_LAYERING);
13631+
13632+ librados::IoCtx ioctx;
13633+ ASSERT_EQ (0 , _rados.ioctx_create (m_pool_name.c_str (), ioctx));
13634+
13635+ librbd::ImageOptions opts_with_0;
13636+ ASSERT_EQ (0 , opts_with_0.set (RBD_IMAGE_OPTION_FORMAT, 0 ));
13637+ librbd::ImageOptions opts_with_1;
13638+ ASSERT_EQ (0 , opts_with_1.set (RBD_IMAGE_OPTION_FORMAT, 1 ));
13639+ librbd::ImageOptions opts_with_2;
13640+ ASSERT_EQ (0 , opts_with_2.set (RBD_IMAGE_OPTION_FORMAT, 2 ));
13641+ librbd::ImageOptions opts_with_3;
13642+ ASSERT_EQ (0 , opts_with_3.set (RBD_IMAGE_OPTION_FORMAT, 3 ));
13643+
13644+ uint64_t features;
13645+ ASSERT_TRUE (get_features (&features));
13646+ ASSERT_EQ (0 , opts_with_2.set (RBD_IMAGE_OPTION_FEATURES, features));
13647+
13648+ // create
13649+ librbd::RBD rbd;
13650+ std::string name1 = get_temp_image_name ();
13651+ std::string name2 = get_temp_image_name ();
13652+ auto do_create = [&rbd, &ioctx](const auto & name, const auto & opts) {
13653+ auto mod_opts = opts;
13654+ return rbd.create4 (ioctx, name.c_str (), 2 << 20 , mod_opts);
13655+ };
13656+ ASSERT_EQ (-EINVAL, do_create (name1, opts_with_0));
13657+ ASSERT_EQ (-EINVAL, do_create (name1, opts_with_3));
13658+ ASSERT_EQ (0 , do_create (name1, opts_with_1));
13659+ auto verify_format_1 = [&rbd, &ioctx](const auto & name) {
13660+ librbd::Image image;
13661+ ASSERT_EQ (0 , rbd.open (ioctx, image, name.c_str (), NULL ));
13662+ uint8_t old_format;
13663+ ASSERT_EQ (0 , image.old_format (&old_format));
13664+ ASSERT_TRUE (old_format);
13665+ };
13666+ ASSERT_NO_FATAL_FAILURE (verify_format_1 (name1));
13667+ ASSERT_EQ (0 , do_create (name2, opts_with_2));
13668+ auto verify_format_2 = [&rbd, &ioctx](const auto & name) {
13669+ librbd::Image image;
13670+ ASSERT_EQ (0 , rbd.open (ioctx, image, name.c_str (), NULL ));
13671+ uint8_t old_format;
13672+ ASSERT_EQ (0 , image.old_format (&old_format));
13673+ ASSERT_FALSE (old_format);
13674+ };
13675+ ASSERT_NO_FATAL_FAILURE (verify_format_2 (name2));
13676+
13677+ {
13678+ librbd::Image image;
13679+ ASSERT_EQ (0 , rbd.open (ioctx, image, name2.c_str (), NULL ));
13680+ ASSERT_EQ (0 , image.snap_create (" parent_snap" ));
13681+ ASSERT_EQ (0 , image.snap_protect (" parent_snap" ));
13682+ }
13683+
13684+ // clone
13685+ std::string clone_name1 = get_temp_image_name ();
13686+ std::string clone_name2 = get_temp_image_name ();
13687+ auto do_clone = [&rbd, &ioctx, &name2](const auto & clone_name,
13688+ const auto & opts) {
13689+ auto mod_opts = opts;
13690+ return rbd.clone3 (ioctx, name2.c_str (), " parent_snap" , ioctx,
13691+ clone_name.c_str (), mod_opts);
13692+ };
13693+ ASSERT_EQ (-EINVAL, do_clone (clone_name1, opts_with_0));
13694+ ASSERT_EQ (-EINVAL, do_clone (clone_name1, opts_with_1));
13695+ ASSERT_EQ (-EINVAL, do_clone (clone_name1, opts_with_3));
13696+ // if RBD_IMAGE_OPTION_CLONE_FORMAT isn't set, rbd_default_clone_format
13697+ // config option kicks in -- we aren't interested in its behavior here
13698+ ASSERT_EQ (0 , do_clone (clone_name1, opts_with_2));
13699+ ASSERT_EQ (0 , rbd.remove (ioctx, clone_name1.c_str ()));
13700+
13701+ auto clone_opts_with_0 = opts_with_2;
13702+ ASSERT_EQ (0 , clone_opts_with_0.set (RBD_IMAGE_OPTION_CLONE_FORMAT, 0 ));
13703+ auto clone_opts_with_1 = opts_with_2;
13704+ ASSERT_EQ (0 , clone_opts_with_1.set (RBD_IMAGE_OPTION_CLONE_FORMAT, 1 ));
13705+ auto clone_opts_with_2 = opts_with_2;
13706+ ASSERT_EQ (0 , clone_opts_with_2.set (RBD_IMAGE_OPTION_CLONE_FORMAT, 2 ));
13707+ auto clone_opts_with_3 = opts_with_2;
13708+ ASSERT_EQ (0 , clone_opts_with_3.set (RBD_IMAGE_OPTION_CLONE_FORMAT, 3 ));
13709+
13710+ ASSERT_EQ (-EINVAL, do_clone (clone_name1, clone_opts_with_0));
13711+ ASSERT_EQ (-EINVAL, do_clone (clone_name1, clone_opts_with_3));
13712+ ASSERT_EQ (0 , do_clone (clone_name1, clone_opts_with_1));
13713+ {
13714+ librbd::Image image;
13715+ ASSERT_EQ (0 , rbd.open (ioctx, image, clone_name1.c_str (), NULL ));
13716+ uint64_t op_features;
13717+ ASSERT_EQ (0 , image.get_op_features (&op_features));
13718+ ASSERT_EQ (op_features, 0 );
13719+ }
13720+ ASSERT_EQ (0 , do_clone (clone_name2, clone_opts_with_2));
13721+ {
13722+ librbd::Image image;
13723+ ASSERT_EQ (0 , rbd.open (ioctx, image, clone_name2.c_str (), NULL ));
13724+ uint64_t op_features;
13725+ ASSERT_EQ (0 , image.get_op_features (&op_features));
13726+ ASSERT_EQ (op_features, RBD_OPERATION_FEATURE_CLONE_CHILD);
13727+ }
13728+
13729+ librbd::Image image;
13730+ ASSERT_EQ (0 , rbd.open (ioctx, image, name1.c_str (), NULL ));
13731+
13732+ // copy
13733+ std::string copy_name1 = get_temp_image_name ();
13734+ std::string copy_name2 = get_temp_image_name ();
13735+ auto do_copy = [&image, &ioctx](const auto & copy_name, const auto & opts) {
13736+ auto mod_opts = opts;
13737+ return image.copy3 (ioctx, copy_name.c_str (), mod_opts);
13738+ };
13739+ ASSERT_EQ (-EINVAL, do_copy (copy_name1, opts_with_0));
13740+ ASSERT_EQ (-EINVAL, do_copy (copy_name1, opts_with_3));
13741+ ASSERT_EQ (0 , do_copy (copy_name1, opts_with_1));
13742+ ASSERT_NO_FATAL_FAILURE (verify_format_1 (copy_name1));
13743+ ASSERT_EQ (0 , do_copy (copy_name2, opts_with_2));
13744+ ASSERT_NO_FATAL_FAILURE (verify_format_2 (copy_name2));
13745+
13746+ // deep copy
13747+ std::string deep_copy_name = get_temp_image_name ();
13748+ auto do_deep_copy = [&image, &ioctx, &deep_copy_name](const auto & opts) {
13749+ auto mod_opts = opts;
13750+ return image.deep_copy (ioctx, deep_copy_name.c_str (), mod_opts);
13751+ };
13752+ ASSERT_EQ (-EINVAL, do_deep_copy (opts_with_0));
13753+ ASSERT_EQ (-EINVAL, do_deep_copy (opts_with_1));
13754+ ASSERT_EQ (-EINVAL, do_deep_copy (opts_with_3));
13755+ ASSERT_EQ (0 , do_deep_copy (opts_with_2));
13756+ ASSERT_NO_FATAL_FAILURE (verify_format_2 (deep_copy_name));
13757+
13758+ ASSERT_EQ (0 , image.close ());
13759+
13760+ // migration
13761+ std::string migrate_name = get_temp_image_name ();
13762+ auto do_migrate = [&rbd, &ioctx, &name1, &migrate_name](const auto & opts) {
13763+ auto mod_opts = opts;
13764+ return rbd.migration_prepare (ioctx, name1.c_str (), ioctx,
13765+ migrate_name.c_str (), mod_opts);
13766+ };
13767+ ASSERT_EQ (-EINVAL, do_migrate (opts_with_0));
13768+ ASSERT_EQ (-EINVAL, do_migrate (opts_with_1));
13769+ ASSERT_EQ (-EINVAL, do_migrate (opts_with_3));
13770+ ASSERT_EQ (0 , do_migrate (opts_with_2));
13771+ ASSERT_NO_FATAL_FAILURE (verify_format_2 (migrate_name));
13772+
13773+ // import-only migration
13774+ std::string source_spec = R"( {
13775+ "type": "native",
13776+ "pool_name": ")" + m_pool_name + R"( ",
13777+ "image_name": ")" + name2 + R"( ",
13778+ "snap_name": "parent_snap"
13779+ })" ;
13780+ std::string import_name = get_temp_image_name ();
13781+ auto do_migrate_import = [&rbd, &ioctx, &source_spec, &import_name](
13782+ const auto & opts) {
13783+ auto mod_opts = opts;
13784+ return rbd.migration_prepare_import (source_spec.c_str (), ioctx,
13785+ import_name.c_str (), mod_opts);
13786+ };
13787+ ASSERT_EQ (-EINVAL, do_migrate_import (opts_with_0));
13788+ ASSERT_EQ (-EINVAL, do_migrate_import (opts_with_1));
13789+ ASSERT_EQ (-EINVAL, do_migrate_import (opts_with_3));
13790+ ASSERT_EQ (0 , do_migrate_import (opts_with_2));
13791+ ASSERT_NO_FATAL_FAILURE (verify_format_2 (import_name));
13792+ }
1362813793
1362913794// poorman's ceph_assert()
1363013795namespace ceph {
0 commit comments