diff --git a/qa/workunits/cephtool/test.sh b/qa/workunits/cephtool/test.sh index 51e7ab4dbbe..4b24e69c874 100755 --- a/qa/workunits/cephtool/test.sh +++ b/qa/workunits/cephtool/test.sh @@ -439,6 +439,8 @@ ceph osd pool get rbd crush_ruleset | grep 'crush_ruleset: 0' ceph osd thrash 10 + + set +e # expect error about missing 'pool' argument @@ -460,4 +462,43 @@ ceph heap dump ceph heap stop_profiler ceph heap release + +# test osd bench limits +# As we should not rely on defaults (as they may change over time), +# lets inject some values and perform some simple tests +# max iops: 10 # 100 IOPS +# max throughput: 10485760 # 10MB/s +# max block size: 2097152 # 2MB +# duration: 10 # 10 seconds + +ceph tell osd.0 injectargs "\ + --osd-bench-duration 10 \ + --osd-bench-max-block-size 2097152 \ + --osd-bench-large-size-max-throughput 10485760 \ + --osd-bench-small-size-max-iops 10" + +# anything with a bs larger than 2097152 must fail +expect_false ceph tell osd.0 bench 1 2097153 +# but using 'osd_bench_max_bs' must succeed +ceph tell osd.0 bench 1 2097152 + +# we assume 1MB as a large bs; anything lower is a small bs +# for a 4096 bytes bs, for 10 seconds, we are limited by IOPS +# max count: 409600 + +# more than max count must not be allowed +expect_false ceph tell osd.0 bench 409601 4096 +# but 409600 must be succeed +ceph tell osd.0 bench 409600 4096 + +# for a large bs, we are limited by throughput. +# for a 2MB block size for 10 seconds, out max count is 50 +# max count: 50 + +# more than max count must not be allowed +expect_false ceph tell osd.0 bench 51 2097152 +# but 50 must succeed +ceph tell osd.0 bench 50 2097152 + + echo OK diff --git a/src/common/config_opts.h b/src/common/config_opts.h index 8bbd58671e0..560a975b35d 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -580,6 +580,11 @@ OPTION(osd_objectstore, OPT_STR, "filestore") // ObjectStore backend type // Set to true for testing. Users should NOT set this. OPTION(osd_debug_override_acting_compat, OPT_BOOL, false) +OPTION(osd_bench_small_size_max_iops, OPT_U32, 100) // 100 IOPS +OPTION(osd_bench_large_size_max_throughput, OPT_U64, 100 << 20) // 100 MB/s +OPTION(osd_bench_max_block_size, OPT_U64, 64 << 20) // cap the block size at 64MB +OPTION(osd_bench_duration, OPT_U32, 30) // duration of 'osd bench', capped at 30s to avoid triggering timeouts + OPTION(filestore_debug_disable_sharded_check, OPT_BOOL, false) /// filestore wb throttle limits diff --git a/src/osd/OSD.cc b/src/osd/OSD.cc index 7bf1f5bcbdb..f229bc08503 100644 --- a/src/osd/OSD.cc +++ b/src/osd/OSD.cc @@ -4283,6 +4283,59 @@ void OSD::do_command(Connection *con, tid_t tid, vector& cmd, bufferlist cmd_getval(cct, cmdmap, "count", count, (int64_t)1 << 30); cmd_getval(cct, cmdmap, "size", bsize, (int64_t)4 << 20); + uint32_t duration = g_conf->osd_bench_duration; + + if (bsize > (int64_t) g_conf->osd_bench_max_block_size) { + // let us limit the block size because the next checks rely on it + // having a sane value. If we allow any block size to be set things + // can still go sideways. + ss << "block 'size' values are capped at " + << prettybyte_t(g_conf->osd_bench_max_block_size) << ". If you wish to use" + << " a higher value, please adjust 'osd_bench_max_block_size'"; + r = -EINVAL; + goto out; + } else if (bsize < (int64_t) (1 << 20)) { + // entering the realm of small block sizes. + // limit the count to a sane value, assuming a configurable amount of + // IOPS and duration, so that the OSD doesn't get hung up on this, + // preventing timeouts from going off + int64_t max_count = + bsize * duration * g_conf->osd_bench_small_size_max_iops; + if (count > max_count) { + ss << "'count' values greater than " << max_count + << " for a block size of " << prettybyte_t(bsize) << ", assuming " + << g_conf->osd_bench_small_size_max_iops << " IOPS," + << " for " << duration << " seconds," + << " can cause ill effects on osd. " + << " Please adjust 'osd_bench_small_size_max_iops' with a higher" + << " value if you wish to use a higher 'count'."; + r = -EINVAL; + goto out; + } + } else { + // 1MB block sizes are big enough so that we get more stuff done. + // However, to avoid the osd from getting hung on this and having + // timers being triggered, we are going to limit the count assuming + // a configurable throughput and duration. + int64_t total_throughput = + g_conf->osd_bench_large_size_max_throughput * duration; + int64_t max_count = (int64_t) (total_throughput / bsize); + if (count > max_count) { + ss << "'count' values greater than " << max_count + << " for a block size of " << prettybyte_t(bsize) << ", assuming " + << prettybyte_t(g_conf->osd_bench_large_size_max_throughput) << "/s," + << " for " << duration << " seconds," + << " can cause ill effects on osd. " + << " Please adjust 'osd_bench_large_size_max_throughput'" + << " with a higher value if you wish to use a higher 'count'."; + r = -EINVAL; + goto out; + } + } + + dout(1) << " bench count " << count + << " bsize " << prettybyte_t(bsize) << dendl; + bufferlist bl; bufferptr bp(bsize); bp.zero();