@@ -13336,6 +13336,171 @@ TEST_F(TestLibRBD, ConcurrentOperations)
1333613336 ioctx.close();
1333713337}
1333813338
13339+ TEST_F (TestLibRBD, FormatAndCloneFormatOptions)
13340+ {
13341+ REQUIRE_FEATURE (RBD_FEATURE_LAYERING);
13342+
13343+ librados::IoCtx ioctx;
13344+ ASSERT_EQ (0 , _rados.ioctx_create (m_pool_name.c_str (), ioctx));
13345+
13346+ librbd::ImageOptions opts_with_0;
13347+ ASSERT_EQ (0 , opts_with_0.set (RBD_IMAGE_OPTION_FORMAT, 0 ));
13348+ librbd::ImageOptions opts_with_1;
13349+ ASSERT_EQ (0 , opts_with_1.set (RBD_IMAGE_OPTION_FORMAT, 1 ));
13350+ librbd::ImageOptions opts_with_2;
13351+ ASSERT_EQ (0 , opts_with_2.set (RBD_IMAGE_OPTION_FORMAT, 2 ));
13352+ librbd::ImageOptions opts_with_3;
13353+ ASSERT_EQ (0 , opts_with_3.set (RBD_IMAGE_OPTION_FORMAT, 3 ));
13354+
13355+ uint64_t features;
13356+ ASSERT_TRUE (get_features (&features));
13357+ ASSERT_EQ (0 , opts_with_2.set (RBD_IMAGE_OPTION_FEATURES, features));
13358+
13359+ // create
13360+ librbd::RBD rbd;
13361+ std::string name1 = get_temp_image_name ();
13362+ std::string name2 = get_temp_image_name ();
13363+ auto do_create = [&rbd, &ioctx](const auto & name, const auto & opts) {
13364+ auto mod_opts = opts;
13365+ return rbd.create4 (ioctx, name.c_str (), 2 << 20 , mod_opts);
13366+ };
13367+ ASSERT_EQ (-EINVAL, do_create (name1, opts_with_0));
13368+ ASSERT_EQ (-EINVAL, do_create (name1, opts_with_3));
13369+ ASSERT_EQ (0 , do_create (name1, opts_with_1));
13370+ auto verify_format_1 = [&rbd, &ioctx](const auto & name) {
13371+ librbd::Image image;
13372+ ASSERT_EQ (0 , rbd.open (ioctx, image, name.c_str (), NULL ));
13373+ uint8_t old_format;
13374+ ASSERT_EQ (0 , image.old_format (&old_format));
13375+ ASSERT_TRUE (old_format);
13376+ };
13377+ ASSERT_NO_FATAL_FAILURE (verify_format_1 (name1));
13378+ ASSERT_EQ (0 , do_create (name2, opts_with_2));
13379+ auto verify_format_2 = [&rbd, &ioctx](const auto & name) {
13380+ librbd::Image image;
13381+ ASSERT_EQ (0 , rbd.open (ioctx, image, name.c_str (), NULL ));
13382+ uint8_t old_format;
13383+ ASSERT_EQ (0 , image.old_format (&old_format));
13384+ ASSERT_FALSE (old_format);
13385+ };
13386+ ASSERT_NO_FATAL_FAILURE (verify_format_2 (name2));
13387+
13388+ {
13389+ librbd::Image image;
13390+ ASSERT_EQ (0 , rbd.open (ioctx, image, name2.c_str (), NULL ));
13391+ ASSERT_EQ (0 , image.snap_create (" parent_snap" ));
13392+ ASSERT_EQ (0 , image.snap_protect (" parent_snap" ));
13393+ }
13394+
13395+ // clone
13396+ std::string clone_name1 = get_temp_image_name ();
13397+ std::string clone_name2 = get_temp_image_name ();
13398+ auto do_clone = [&rbd, &ioctx, &name2](const auto & clone_name,
13399+ const auto & opts) {
13400+ auto mod_opts = opts;
13401+ return rbd.clone3 (ioctx, name2.c_str (), " parent_snap" , ioctx,
13402+ clone_name.c_str (), mod_opts);
13403+ };
13404+ ASSERT_EQ (-EINVAL, do_clone (clone_name1, opts_with_0));
13405+ ASSERT_EQ (-EINVAL, do_clone (clone_name1, opts_with_1));
13406+ ASSERT_EQ (-EINVAL, do_clone (clone_name1, opts_with_3));
13407+ // if RBD_IMAGE_OPTION_CLONE_FORMAT isn't set, rbd_default_clone_format
13408+ // config option kicks in -- we aren't interested in its behavior here
13409+ ASSERT_EQ (0 , do_clone (clone_name1, opts_with_2));
13410+ ASSERT_EQ (0 , rbd.remove (ioctx, clone_name1.c_str ()));
13411+
13412+ auto clone_opts_with_0 = opts_with_2;
13413+ ASSERT_EQ (0 , clone_opts_with_0.set (RBD_IMAGE_OPTION_CLONE_FORMAT, 0 ));
13414+ auto clone_opts_with_1 = opts_with_2;
13415+ ASSERT_EQ (0 , clone_opts_with_1.set (RBD_IMAGE_OPTION_CLONE_FORMAT, 1 ));
13416+ auto clone_opts_with_2 = opts_with_2;
13417+ ASSERT_EQ (0 , clone_opts_with_2.set (RBD_IMAGE_OPTION_CLONE_FORMAT, 2 ));
13418+ auto clone_opts_with_3 = opts_with_2;
13419+ ASSERT_EQ (0 , clone_opts_with_3.set (RBD_IMAGE_OPTION_CLONE_FORMAT, 3 ));
13420+
13421+ ASSERT_EQ (-EINVAL, do_clone (clone_name1, clone_opts_with_0));
13422+ ASSERT_EQ (-EINVAL, do_clone (clone_name1, clone_opts_with_3));
13423+ ASSERT_EQ (0 , do_clone (clone_name1, clone_opts_with_1));
13424+ {
13425+ librbd::Image image;
13426+ ASSERT_EQ (0 , rbd.open (ioctx, image, clone_name1.c_str (), NULL ));
13427+ uint64_t op_features;
13428+ ASSERT_EQ (0 , image.get_op_features (&op_features));
13429+ ASSERT_EQ (op_features, 0 );
13430+ }
13431+ ASSERT_EQ (0 , do_clone (clone_name2, clone_opts_with_2));
13432+ {
13433+ librbd::Image image;
13434+ ASSERT_EQ (0 , rbd.open (ioctx, image, clone_name2.c_str (), NULL ));
13435+ uint64_t op_features;
13436+ ASSERT_EQ (0 , image.get_op_features (&op_features));
13437+ ASSERT_EQ (op_features, RBD_OPERATION_FEATURE_CLONE_CHILD);
13438+ }
13439+
13440+ librbd::Image image;
13441+ ASSERT_EQ (0 , rbd.open (ioctx, image, name1.c_str (), NULL ));
13442+
13443+ // copy
13444+ std::string copy_name1 = get_temp_image_name ();
13445+ std::string copy_name2 = get_temp_image_name ();
13446+ auto do_copy = [&image, &ioctx](const auto & copy_name, const auto & opts) {
13447+ auto mod_opts = opts;
13448+ return image.copy3 (ioctx, copy_name.c_str (), mod_opts);
13449+ };
13450+ ASSERT_EQ (-EINVAL, do_copy (copy_name1, opts_with_0));
13451+ ASSERT_EQ (-EINVAL, do_copy (copy_name1, opts_with_3));
13452+ ASSERT_EQ (0 , do_copy (copy_name1, opts_with_1));
13453+ ASSERT_NO_FATAL_FAILURE (verify_format_1 (copy_name1));
13454+ ASSERT_EQ (0 , do_copy (copy_name2, opts_with_2));
13455+ ASSERT_NO_FATAL_FAILURE (verify_format_2 (copy_name2));
13456+
13457+ // deep copy
13458+ std::string deep_copy_name = get_temp_image_name ();
13459+ auto do_deep_copy = [&image, &ioctx, &deep_copy_name](const auto & opts) {
13460+ auto mod_opts = opts;
13461+ return image.deep_copy (ioctx, deep_copy_name.c_str (), mod_opts);
13462+ };
13463+ ASSERT_EQ (-EINVAL, do_deep_copy (opts_with_0));
13464+ ASSERT_EQ (-EINVAL, do_deep_copy (opts_with_1));
13465+ ASSERT_EQ (-EINVAL, do_deep_copy (opts_with_3));
13466+ ASSERT_EQ (0 , do_deep_copy (opts_with_2));
13467+ ASSERT_NO_FATAL_FAILURE (verify_format_2 (deep_copy_name));
13468+
13469+ ASSERT_EQ (0 , image.close ());
13470+
13471+ // migration
13472+ std::string migrate_name = get_temp_image_name ();
13473+ auto do_migrate = [&rbd, &ioctx, &name1, &migrate_name](const auto & opts) {
13474+ auto mod_opts = opts;
13475+ return rbd.migration_prepare (ioctx, name1.c_str (), ioctx,
13476+ migrate_name.c_str (), mod_opts);
13477+ };
13478+ ASSERT_EQ (-EINVAL, do_migrate (opts_with_0));
13479+ ASSERT_EQ (-EINVAL, do_migrate (opts_with_1));
13480+ ASSERT_EQ (-EINVAL, do_migrate (opts_with_3));
13481+ ASSERT_EQ (0 , do_migrate (opts_with_2));
13482+ ASSERT_NO_FATAL_FAILURE (verify_format_2 (migrate_name));
13483+
13484+ // import-only migration
13485+ std::string source_spec = R"( {
13486+ "type": "native",
13487+ "pool_name": ")" + m_pool_name + R"( ",
13488+ "image_name": ")" + name2 + R"( ",
13489+ "snap_name": "parent_snap"
13490+ })" ;
13491+ std::string import_name = get_temp_image_name ();
13492+ auto do_migrate_import = [&rbd, &ioctx, &source_spec, &import_name](
13493+ const auto & opts) {
13494+ auto mod_opts = opts;
13495+ return rbd.migration_prepare_import (source_spec.c_str (), ioctx,
13496+ import_name.c_str (), mod_opts);
13497+ };
13498+ ASSERT_EQ (-EINVAL, do_migrate_import (opts_with_0));
13499+ ASSERT_EQ (-EINVAL, do_migrate_import (opts_with_1));
13500+ ASSERT_EQ (-EINVAL, do_migrate_import (opts_with_3));
13501+ ASSERT_EQ (0 , do_migrate_import (opts_with_2));
13502+ ASSERT_NO_FATAL_FAILURE (verify_format_2 (import_name));
13503+ }
1333913504
1334013505// poorman's ceph_assert()
1334113506namespace ceph {
0 commit comments