]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd/action/Create.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / tools / rbd / action / Create.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "tools/rbd/ArgumentTypes.h"
5#include "tools/rbd/Shell.h"
6#include "tools/rbd/Utils.h"
9f95a23c
TL
7#include "common/ceph_mutex.h"
8#include "common/config_proxy.h"
7c673cae 9#include "common/errno.h"
9f95a23c 10#include "global/global_context.h"
7c673cae
FG
11#include <iostream>
12#include <boost/program_options.hpp>
13
14namespace rbd {
15namespace action {
16namespace create {
17
18namespace at = argument_types;
19namespace po = boost::program_options;
20
21static int do_create(librbd::RBD &rbd, librados::IoCtx& io_ctx,
22 const char *imgname, uint64_t size,
23 librbd::ImageOptions& opts) {
24 return rbd.create4(io_ctx, imgname, size, opts);
25}
26
27void get_arguments(po::options_description *positional,
28 po::options_description *options) {
29 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
30 at::add_create_image_options(options, true);
11fdf7f2
TL
31 options->add_options()
32 (at::IMAGE_THICK_PROVISION.c_str(), po::bool_switch(), "fully allocate storage and zero image");
7c673cae 33 at::add_size_option(options);
11fdf7f2 34 at::add_no_progress_option(options);
7c673cae
FG
35}
36
11fdf7f2
TL
37void thick_provision_writer_completion(rbd_completion_t, void *);
38
39struct thick_provision_writer {
40 librbd::Image *image;
9f95a23c
TL
41 ceph::mutex lock = ceph::make_mutex("thick_provision_writer::lock");
42 ceph::condition_variable cond;
11fdf7f2 43 uint64_t chunk_size;
11fdf7f2
TL
44 uint64_t concurr;
45 struct {
46 uint64_t in_flight;
47 int io_error;
48 } io_status;
49
50 // Constructor
51 explicit thick_provision_writer(librbd::Image *i, librbd::ImageOptions &o)
f67539c2 52 : image(i)
11fdf7f2
TL
53 {
54 // If error cases occur, the code is aborted, because
55 // constructor cannot return error value.
56 ceph_assert(g_ceph_context != nullptr);
11fdf7f2
TL
57
58 librbd::image_info_t info;
59 int r = image->stat(info, sizeof(info));
60 ceph_assert(r >= 0);
f67539c2
TL
61
62 uint64_t order = info.order;
63 if (order == 0) {
11fdf7f2 64 order = g_conf().get_val<uint64_t>("rbd_default_order");
11fdf7f2
TL
65 }
66
f67539c2
TL
67 auto stripe_count = std::max<uint64_t>(1U, image->get_stripe_count());
68 chunk_size = (1ull << order) * stripe_count;
69
70 concurr = std::max<uint64_t>(
71 1U, g_conf().get_val<uint64_t>("rbd_concurrent_management_ops") /
72 stripe_count);
73
11fdf7f2
TL
74 io_status.in_flight = 0;
75 io_status.io_error = 0;
76 }
77
78 int start_io(uint64_t write_offset)
79 {
80 {
9f95a23c 81 std::lock_guard l{lock};
11fdf7f2
TL
82 io_status.in_flight++;
83 if (io_status.in_flight > concurr) {
84 io_status.in_flight--;
85 return -EINVAL;
86 }
87 }
88
89 librbd::RBD::AioCompletion *c;
90 c = new librbd::RBD::AioCompletion(this, thick_provision_writer_completion);
91 int r;
f67539c2
TL
92 r = image->aio_write_zeroes(write_offset, chunk_size, c,
93 RBD_WRITE_ZEROES_FLAG_THICK_PROVISION,
94 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
11fdf7f2 95 if (r < 0) {
9f95a23c 96 std::lock_guard l{lock};
11fdf7f2
TL
97 io_status.io_error = r;
98 }
99 return r;
100 }
101
102 int wait_for(uint64_t max) {
9f95a23c 103 std::unique_lock l{lock};
11fdf7f2
TL
104 int r = io_status.io_error;
105
106 while (io_status.in_flight > max) {
9f95a23c 107 cond.wait_for(l, 200ms);
11fdf7f2
TL
108 }
109 return r;
110 }
111};
112
113void thick_provision_writer_completion(rbd_completion_t rc, void *pc) {
114 librbd::RBD::AioCompletion *ac = (librbd::RBD::AioCompletion *)rc;
115 thick_provision_writer *tc = static_cast<thick_provision_writer *>(pc);
116
117 int r = ac->get_return_value();
9f95a23c 118 tc->lock.lock();
11fdf7f2
TL
119 if (r < 0 && tc->io_status.io_error >= 0) {
120 tc->io_status.io_error = r;
121 }
122 tc->io_status.in_flight--;
9f95a23c
TL
123 tc->cond.notify_all();
124 tc->lock.unlock();
11fdf7f2
TL
125 ac->release();
126}
127
128int write_data(librbd::Image &image, librbd::ImageOptions &opts,
129 bool no_progress) {
130 uint64_t image_size;
131 int r = 0;
132 utils::ProgressContext pc("Thick provisioning", no_progress);
133
134 if (image.size(&image_size) != 0) {
135 return -EINVAL;
136 }
137
138 thick_provision_writer tpw(&image, opts);
139 uint64_t off;
140 uint64_t i;
141 for (off = 0; off < image_size;) {
142 i = 0;
143 while (i < tpw.concurr && off < image_size) {
144 tpw.wait_for(tpw.concurr - 1);
145 r = tpw.start_io(off);
146 if (r != 0) {
147 goto err_writesame;
148 }
149 ++i;
150 off += tpw.chunk_size;
92f5a8d4
TL
151 if(off > image_size) {
152 off = image_size;
153 }
11fdf7f2
TL
154 pc.update_progress(off, image_size);
155 }
156 }
157
158 tpw.wait_for(0);
159 r = image.flush();
160 if (r < 0) {
161 std::cerr << "rbd: failed to flush at the end: " << cpp_strerror(r)
162 << std::endl;
163 goto err_writesame;
164 }
165 pc.finish();
166
167 return r;
168
169err_writesame:
170 tpw.wait_for(0);
171 pc.fail();
172
173 return r;
174}
175
176int thick_write(const std::string &image_name,librados::IoCtx &io_ctx,
177 librbd::ImageOptions &opts, bool no_progress) {
178 int r = 0;
179 librbd::Image image;
180
181 // To prevent writesame from discarding data, thick_write sets
182 // the rbd_discard_on_zeroed_write_same option to false.
183 ceph_assert(g_ceph_context != nullptr);
184 r = g_conf().set_val("rbd_discard_on_zeroed_write_same", "false");
185 ceph_assert(r == 0);
186 r = utils::open_image(io_ctx, image_name, false, &image);
187 if (r < 0) {
188 return r;
189 }
190
191 r = write_data(image, opts, no_progress);
192
193 image.close();
194
195 return r;
196}
197
198int execute(const po::variables_map &vm,
199 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
200 size_t arg_index = 0;
201 std::string pool_name;
11fdf7f2 202 std::string namespace_name;
7c673cae
FG
203 std::string image_name;
204 std::string snap_name;
205 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
206 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
207 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
208 utils::SPEC_VALIDATION_FULL);
7c673cae
FG
209 if (r < 0) {
210 return r;
211 }
212
213 librbd::ImageOptions opts;
214 r = utils::get_image_options(vm, true, &opts);
215 if (r < 0) {
216 return r;
217 }
218
219 uint64_t size;
220 r = utils::get_image_size(vm, &size);
221 if (r < 0) {
222 return r;
223 }
224
225 librados::Rados rados;
226 librados::IoCtx io_ctx;
11fdf7f2 227 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
7c673cae
FG
228 if (r < 0) {
229 return r;
230 }
231
232 librbd::RBD rbd;
233 r = do_create(rbd, io_ctx, image_name.c_str(), size, opts);
11fdf7f2
TL
234 if (!namespace_name.empty() && r == -ENOENT) {
235 std::cerr << "rbd: namespace not found - it must be created with "
236 << "'rbd namespace create' before creating an image."
237 << std::endl;
238 return r;
239 } else if (r < 0) {
7c673cae
FG
240 std::cerr << "rbd: create error: " << cpp_strerror(r) << std::endl;
241 return r;
242 }
11fdf7f2
TL
243
244 if (vm.count(at::IMAGE_THICK_PROVISION) && vm[at::IMAGE_THICK_PROVISION].as<bool>()) {
245 r = thick_write(image_name, io_ctx, opts, vm[at::NO_PROGRESS].as<bool>());
246 if (r < 0) {
247 std::cerr << "rbd: image created but error encountered during thick provisioning: "
248 << cpp_strerror(r) << std::endl;
249 return r;
250 }
251 }
7c673cae
FG
252 return 0;
253}
254
255Shell::Action action(
256 {"create"}, {}, "Create an empty image.", at::get_long_features_help(),
257 &get_arguments, &execute);
258
259} // namespace create
260} // namespace action
261} // namespace rbd