diff options
author | Josh Durgin <josh.durgin@inktank.com> | 2013-05-16 15:28:40 -0700 |
---|---|---|
committer | Josh Durgin <josh.durgin@inktank.com> | 2013-05-16 15:28:40 -0700 |
commit | aacc9adc4e9ca90bbe73ac153cc754a3a5b2c0a1 (patch) | |
tree | 390fb7355a95728e1083b3243351ba6543333409 | |
parent | 53ee6f965e8f06c7256848210ad3c4f89d0cb5a0 (diff) | |
download | ceph-aacc9adc4e9ca90bbe73ac153cc754a3a5b2c0a1.tar.gz |
librbd: make image creation defaults configurable
Programs using older versions of the image creation functions can't
set newer parameters like image format and fancier striping.
Setting these options lets them use all the new functionality without
being patched and recompiled to use e.g. rbd_create3().
This is particularly useful for things like qemu-img, which does not
know how to create format 2 images yet.
Refs: #5067
backport: cuttlefish, bobtail
Signed-off-by: Josh Durgin <josh.durgin@inktank.com>
-rw-r--r-- | src/common/config_opts.h | 23 | ||||
-rw-r--r-- | src/librbd/internal.cc | 25 | ||||
-rw-r--r-- | src/librbd/internal.h | 2 | ||||
-rw-r--r-- | src/librbd/librbd.cc | 10 | ||||
-rw-r--r-- | src/test/pybind/test_rbd.py | 90 |
5 files changed, 142 insertions, 8 deletions
diff --git a/src/common/config_opts.h b/src/common/config_opts.h index aa54a213fbf..06c980087da 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -535,6 +535,7 @@ OPTION(journal_align_min_size, OPT_INT, 64 << 10) // align data payloads >= thi OPTION(journal_replay_from, OPT_INT, 0) OPTION(journal_zero_on_create, OPT_BOOL, false) OPTION(journal_ignore_corruption, OPT_BOOL, false) // assume journal is not corrupt + OPTION(rbd_cache, OPT_BOOL, false) // whether to enable caching (writeback unless rbd_cache_max_dirty is 0) OPTION(rbd_cache_writethrough_until_flush, OPT_BOOL, false) // whether to make writeback caching writethrough until flush is called, to be sure the user of librbd will send flushs so that writeback is safe OPTION(rbd_cache_size, OPT_LONGLONG, 32<<20) // cache size in bytes @@ -546,6 +547,28 @@ OPTION(rbd_concurrent_management_ops, OPT_INT, 10) // how many operations can be OPTION(rbd_balance_snap_reads, OPT_BOOL, false) OPTION(rbd_localize_snap_reads, OPT_BOOL, false) +/* + * The following options change the behavior for librbd's image creation methods that + * don't require all of the parameters. These are provided so that older programs + * can take advantage of newer features without being rewritten to use new versions + * of the image creation functions. + * + * rbd_create()/RBD::create() are affected by all of these options. + * + * rbd_create2()/RBD::create2() and rbd_clone()/RBD::clone() are affected by: + * - rbd_default_order + * - rbd_default_stripe_count + * - rbd_default_stripe_size + * + * rbd_create3()/RBD::create3() and rbd_clone2/RBD::clone2() are only + * affected by rbd_default_order. + */ +OPTION(rbd_default_format, OPT_INT, 1) +OPTION(rbd_default_order, OPT_INT, 22) +OPTION(rbd_default_stripe_count, OPT_U64, 1) // changing requires stripingv2 feature +OPTION(rbd_default_stripe_unit, OPT_U64, 4194304) // changing to non-object size requires stripingv2 feature +OPTION(rbd_default_features, OPT_INT, 3) // 1 for layering, 3 for layering+stripingv2. only applies to format 2 images + OPTION(nss_db_path, OPT_STR, "") // path to nss db OPTION(rgw_data, OPT_STR, "/var/lib/ceph/radosgw/$cluster-$id") diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index d845886b25f..627b9a78cc1 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -820,6 +820,15 @@ reprotect_and_return_err: return r; } + int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size, + int *order) + { + CephContext *cct = (CephContext *)io_ctx.cct(); + bool old_format = cct->_conf->rbd_default_format == 1; + uint64_t features = old_format ? 0 : cct->_conf->rbd_default_features; + return create(io_ctx, imgname, size, old_format, features, order, 0, 0); + } + int create(IoCtx& io_ctx, const char *imgname, uint64_t size, bool old_format, uint64_t features, int *order, uint64_t stripe_unit, uint64_t stripe_count) @@ -852,6 +861,11 @@ reprotect_and_return_err: if (!order) return -EINVAL; + if (!*order) + *order = cct->_conf->rbd_default_order; + if (!*order) + *order = RBD_DEFAULT_OBJ_ORDER; + if (*order && (*order > 64 || *order < 12)) { lderr(cct) << "order must be in the range [12, 64]" << dendl; return -EDOM; @@ -859,8 +873,12 @@ reprotect_and_return_err: uint64_t bid = rbd_assign_bid(io_ctx); - if (!*order) - *order = RBD_DEFAULT_OBJ_ORDER; + // if striping is enabled, use possibly custom defaults + if (!old_format && (features & RBD_FEATURE_STRIPINGV2) && + !stripe_unit && !stripe_count) { + stripe_unit = cct->_conf->rbd_default_stripe_unit; + stripe_count = cct->_conf->rbd_default_stripe_count; + } // normalize for default striping if (stripe_unit == (1ull << *order) && stripe_count == 1) { @@ -972,7 +990,8 @@ reprotect_and_return_err: if (!order) order = p_imctx->order; - r = create(c_ioctx, c_name, size, false, features, &order, stripe_unit, stripe_count); + r = create(c_ioctx, c_name, size, false, features, &order, + stripe_unit, stripe_count); if (r < 0) { lderr(cct) << "error creating child: " << cpp_strerror(r) << dendl; goto err_close_parent; diff --git a/src/librbd/internal.h b/src/librbd/internal.h index a7d39b3c964..048e4387c41 100644 --- a/src/librbd/internal.h +++ b/src/librbd/internal.h @@ -81,6 +81,8 @@ namespace librbd { int list_children(ImageCtx *ictx, std::set<pair<std::string, std::string> > & names); int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size, + int *order); + int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size, bool old_format, uint64_t features, int *order, uint64_t stripe_unit, uint64_t stripe_count); int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name, diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 89bbe595752..af413dda04f 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -115,7 +115,7 @@ namespace librbd { int RBD::create(IoCtx& io_ctx, const char *name, uint64_t size, int *order) { - return librbd::create(io_ctx, name, size, true, 0, order, 0, 0); + return librbd::create(io_ctx, name, size, order); } int RBD::create2(IoCtx& io_ctx, const char *name, uint64_t size, @@ -128,7 +128,8 @@ namespace librbd { uint64_t features, int *order, uint64_t stripe_unit, uint64_t stripe_count) { - return librbd::create(io_ctx, name, size, false, features, order, stripe_unit, stripe_count); + return librbd::create(io_ctx, name, size, false, features, order, + stripe_unit, stripe_count); } int RBD::clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name, @@ -559,7 +560,7 @@ extern "C" int rbd_create(rados_ioctx_t p, const char *name, uint64_t size, int { librados::IoCtx io_ctx; librados::IoCtx::from_rados_ioctx_t(p, io_ctx); - return librbd::create(io_ctx, name, size, true, 0, order, 0, 0); + return librbd::create(io_ctx, name, size, order); } extern "C" int rbd_create2(rados_ioctx_t p, const char *name, @@ -578,7 +579,8 @@ extern "C" int rbd_create3(rados_ioctx_t p, const char *name, { librados::IoCtx io_ctx; librados::IoCtx::from_rados_ioctx_t(p, io_ctx); - return librbd::create(io_ctx, name, size, false, features, order, stripe_unit, stripe_count); + return librbd::create(io_ctx, name, size, false, features, order, + stripe_unit, stripe_count); } extern "C" int rbd_clone(rados_ioctx_t p_ioctx, const char *p_name, diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index ea3e5fc5e04..5f14e62bbde 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -8,7 +8,8 @@ from nose.tools import eq_ as eq, assert_raises from rados import Rados from rbd import (RBD, Image, ImageNotFound, InvalidArgument, ImageExists, ImageBusy, ImageHasSnapshots, ReadOnlyImage, - FunctionNotSupported, RBD_FEATURE_LAYERING) + FunctionNotSupported, ArgumentOutOfRange, + RBD_FEATURE_LAYERING, RBD_FEATURE_STRIPINGV2) rados = None @@ -66,6 +67,93 @@ def test_create(): create_image() remove_image() +def check_default_params(format, order=None, features=None, stripe_count=None, + stripe_unit=None, exception=None): + global rados + global ioctx + orig_vals = {} + for k in ['rbd_default_format', 'rbd_default_order', 'rbd_default_features', + 'rbd_default_stripe_count', 'rbd_default_stripe_unit']: + orig_vals[k] = rados.conf_get(k) + try: + rados.conf_set('rbd_default_format', str(format)) + if order is not None: + rados.conf_set('rbd_default_order', str(order or 0)) + if features is not None: + rados.conf_set('rbd_default_features', str(features or 0)) + if stripe_count is not None: + rados.conf_set('rbd_default_stripe_count', str(stripe_count or 0)) + if stripe_unit is not None: + rados.conf_set('rbd_default_stripe_unit', str(stripe_unit or 0)) + if exception is None: + RBD().create(ioctx, IMG_NAME, IMG_SIZE) + try: + with Image(ioctx, IMG_NAME) as image: + eq(format == 1, image.old_format()) + + expected_order = order + if not order: + expected_order = 22 + actual_order = image.stat()['order'] + eq(expected_order, actual_order) + + expected_features = features + if expected_features is None or format == 1: + expected_features = 0 if format == 1 else 3 + eq(expected_features, image.features()) + + expected_stripe_count = stripe_count + if not expected_stripe_count or format == 1 or \ + features & RBD_FEATURE_STRIPINGV2 == 0: + expected_stripe_count = 1 + eq(expected_stripe_count, image.stripe_count()) + + expected_stripe_unit = stripe_unit + if not expected_stripe_unit or format == 1 or \ + features & RBD_FEATURE_STRIPINGV2 == 0: + expected_stripe_unit = 1 << actual_order + eq(expected_stripe_unit, image.stripe_unit()) + finally: + RBD().remove(ioctx, IMG_NAME) + else: + assert_raises(exception, RBD().create, ioctx, IMG_NAME, IMG_SIZE) + finally: + for k, v in orig_vals.iteritems(): + rados.conf_set(k, v) + +def test_create_defaults(): + # basic format 1 and 2 + check_default_params(1) + check_default_params(2) + # default order still works + check_default_params(1, 0) + check_default_params(2, 0) + # invalid order + check_default_params(1, 11, exception=ArgumentOutOfRange) + check_default_params(2, 11, exception=ArgumentOutOfRange) + check_default_params(1, 65, exception=ArgumentOutOfRange) + check_default_params(2, 65, exception=ArgumentOutOfRange) + # striping and features are ignored for format 1 + check_default_params(1, 20, 0, 1, 1) + check_default_params(1, 20, 3, 1, 1) + check_default_params(1, 20, 0, 0, 0) + # striping is ignored if stripingv2 is not set + check_default_params(2, 20, 0, 1, 1 << 20) + check_default_params(2, 20, RBD_FEATURE_LAYERING, 1, 1 << 20) + check_default_params(2, 20, 0, 0, 0) + # striping with stripingv2 is fine + check_default_params(2, 20, RBD_FEATURE_STRIPINGV2, 1, 1 << 16) + check_default_params(2, 20, RBD_FEATURE_STRIPINGV2, 10, 1 << 20) + check_default_params(2, 20, RBD_FEATURE_STRIPINGV2, 10, 1 << 16) + # make sure invalid combinations of stripe unit and order are still invalid + check_default_params(2, 20, RBD_FEATURE_STRIPINGV2, exception=InvalidArgument) + check_default_params(2, 22, RBD_FEATURE_STRIPINGV2, 10, 1 << 50, exception=InvalidArgument) + check_default_params(2, 22, RBD_FEATURE_STRIPINGV2, 10, 100, exception=InvalidArgument) + check_default_params(2, 22, RBD_FEATURE_STRIPINGV2, 0, 1, exception=InvalidArgument) + check_default_params(2, 22, RBD_FEATURE_STRIPINGV2, 1, 0, exception=InvalidArgument) + # 0 stripe unit and count are still ignored + check_default_params(2, 22, RBD_FEATURE_STRIPINGV2, 0, 0) + def test_context_manager(): with Rados(conffile='') as cluster: with cluster.open_ioctx('rbd') as ioctx: |