]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd/action/Create.cc
update sources to ceph Nautilus 14.2.1
[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"
7#include "common/errno.h"
8#include <iostream>
9#include <boost/program_options.hpp>
11fdf7f2
TL
10#include "common/Cond.h"
11#include "common/Mutex.h"
7c673cae
FG
12
13namespace rbd {
14namespace action {
15namespace create {
16
17namespace at = argument_types;
18namespace po = boost::program_options;
19
20static int do_create(librbd::RBD &rbd, librados::IoCtx& io_ctx,
21 const char *imgname, uint64_t size,
22 librbd::ImageOptions& opts) {
23 return rbd.create4(io_ctx, imgname, size, opts);
24}
25
26void get_arguments(po::options_description *positional,
27 po::options_description *options) {
28 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
29 at::add_create_image_options(options, true);
11fdf7f2
TL
30 options->add_options()
31 (at::IMAGE_THICK_PROVISION.c_str(), po::bool_switch(), "fully allocate storage and zero image");
7c673cae 32 at::add_size_option(options);
11fdf7f2 33 at::add_no_progress_option(options);
7c673cae
FG
34}
35
11fdf7f2
TL
36void thick_provision_writer_completion(rbd_completion_t, void *);
37
38struct thick_provision_writer {
39 librbd::Image *image;
40 Mutex lock;
41 Cond cond;
42 bufferlist bl;
43 uint64_t chunk_size;
44 const int block_size;
45 uint64_t concurr;
46 struct {
47 uint64_t in_flight;
48 int io_error;
49 } io_status;
50
51 // Constructor
52 explicit thick_provision_writer(librbd::Image *i, librbd::ImageOptions &o)
53 : image(i),
54 lock("thick_provision_writer::lock"),
55 block_size(512) // 512 Bytes
56 {
57 // If error cases occur, the code is aborted, because
58 // constructor cannot return error value.
59 ceph_assert(g_ceph_context != nullptr);
60 bl.append_zero(block_size);
61
62 librbd::image_info_t info;
63 int r = image->stat(info, sizeof(info));
64 ceph_assert(r >= 0);
65 uint64_t order;
66 if (info.order == 0) {
67 order = g_conf().get_val<uint64_t>("rbd_default_order");
68 } else {
69 order = info.order;
70 }
71 chunk_size = (1ull << order);
72 if (image->get_stripe_unit() < chunk_size) {
73 chunk_size = image->get_stripe_unit();
74 }
75
76 concurr = g_conf().get_val<uint64_t>("rbd_concurrent_management_ops");
77 io_status.in_flight = 0;
78 io_status.io_error = 0;
79 }
80
81 int start_io(uint64_t write_offset)
82 {
83 {
84 Mutex::Locker l(lock);
85 io_status.in_flight++;
86 if (io_status.in_flight > concurr) {
87 io_status.in_flight--;
88 return -EINVAL;
89 }
90 }
91
92 librbd::RBD::AioCompletion *c;
93 c = new librbd::RBD::AioCompletion(this, thick_provision_writer_completion);
94 int r;
95 r = image->aio_writesame(write_offset, chunk_size, bl, c, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
96 if (r < 0) {
97 Mutex::Locker l(lock);
98 io_status.io_error = r;
99 }
100 return r;
101 }
102
103 int wait_for(uint64_t max) {
104 Mutex::Locker l(lock);
105 int r = io_status.io_error;
106
107 while (io_status.in_flight > max) {
108 utime_t dur;
109 dur.set_from_double(.2);
110 cond.WaitInterval(lock, dur);
111 }
112 return r;
113 }
114};
115
116void thick_provision_writer_completion(rbd_completion_t rc, void *pc) {
117 librbd::RBD::AioCompletion *ac = (librbd::RBD::AioCompletion *)rc;
118 thick_provision_writer *tc = static_cast<thick_provision_writer *>(pc);
119
120 int r = ac->get_return_value();
121 tc->lock.Lock();
122 if (r < 0 && tc->io_status.io_error >= 0) {
123 tc->io_status.io_error = r;
124 }
125 tc->io_status.in_flight--;
126 tc->cond.Signal();
127 tc->lock.Unlock();
128 ac->release();
129}
130
131int write_data(librbd::Image &image, librbd::ImageOptions &opts,
132 bool no_progress) {
133 uint64_t image_size;
134 int r = 0;
135 utils::ProgressContext pc("Thick provisioning", no_progress);
136
137 if (image.size(&image_size) != 0) {
138 return -EINVAL;
139 }
140
141 thick_provision_writer tpw(&image, opts);
142 uint64_t off;
143 uint64_t i;
144 for (off = 0; off < image_size;) {
145 i = 0;
146 while (i < tpw.concurr && off < image_size) {
147 tpw.wait_for(tpw.concurr - 1);
148 r = tpw.start_io(off);
149 if (r != 0) {
150 goto err_writesame;
151 }
152 ++i;
153 off += tpw.chunk_size;
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