]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: make image creation defaults configurable 303/head
authorJosh Durgin <josh.durgin@inktank.com>
Thu, 16 May 2013 22:28:40 +0000 (15:28 -0700)
committerJosh Durgin <josh.durgin@inktank.com>
Thu, 16 May 2013 22:28:40 +0000 (15:28 -0700)
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>
src/common/config_opts.h
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/librbd.cc
src/test/pybind/test_rbd.py

index aa54a213fbf688a4fbd1aec58dc4a42514a1f745..06c980087dab01286aa2760088e6cde932bcf2e5 100644 (file)
@@ -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")
index d845886b25f92be483c8c9774b531057fe2bcb3a..627b9a78cc1d8ab5d2146d3e3455ab858b687851 100644 (file)
@@ -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;
index a7d39b3c964b67e43dd556276bca741d6865fe97..048e4387c4121ee076a9ee01b6b0cd45a8ad31bd 100644 (file)
@@ -80,6 +80,8 @@ namespace librbd {
   int list(librados::IoCtx& io_ctx, std::vector<std::string>& names);
   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);
index 89bbe595752a900f3ea22ff080342ae2d2a9690f..af413dda04f469332456de500acd9c157dc19356 100644 (file)
@@ -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,
index ea3e5fc5e040edc64507dddb4fd9de49a8760c2f..5f14e62bbded50f308d550baadb6d1c5694e257d 100644 (file)
@@ -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: