]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd/action/Kernel.cc
import ceph 15.2.14
[ceph.git] / ceph / src / tools / rbd / action / Kernel.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 "acconfig.h"
5#include "tools/rbd/ArgumentTypes.h"
6#include "tools/rbd/Shell.h"
7#include "tools/rbd/Utils.h"
8#include "include/krbd.h"
9#include "include/stringify.h"
10#include "include/uuid.h"
11fdf7f2 11#include "common/config_proxy.h"
7c673cae
FG
12#include "common/errno.h"
13#include "common/safe_io.h"
14#include "common/strtol.h"
15#include "common/Formatter.h"
16#include "msg/msg_types.h"
17#include "global/global_context.h"
18#include <iostream>
19#include <boost/algorithm/string/predicate.hpp>
20#include <boost/scope_exit.hpp>
21#include <boost/program_options.hpp>
22
23namespace rbd {
24namespace action {
25namespace kernel {
26
27namespace at = argument_types;
28namespace po = boost::program_options;
29
ec96510d 30typedef std::map<std::string, std::string> MapOptions;
7c673cae
FG
31
32static std::string map_option_uuid_cb(const char *value_char)
33{
34 uuid_d u;
35 if (!u.parse(value_char))
36 return "";
37
38 return stringify(u);
39}
40
41static std::string map_option_ip_cb(const char *value_char)
42{
43 entity_addr_t a;
44 const char *endptr;
45 if (!a.parse(value_char, &endptr) ||
46 endptr != value_char + strlen(value_char)) {
47 return "";
48 }
49
50 return stringify(a.get_sockaddr());
51}
52
53static std::string map_option_int_cb(const char *value_char)
54{
55 std::string err;
56 int d = strict_strtol(value_char, 10, &err);
57 if (!err.empty() || d < 0)
58 return "";
59
60 return stringify(d);
61}
62
f6b5b4d7
TL
63static std::string map_option_string_cb(const char *value_char)
64{
65 return value_char;
66}
67
68static std::string map_option_read_from_replica_cb(const char *value_char)
69{
70 if (!strcmp(value_char, "no") || !strcmp(value_char, "balance") ||
71 !strcmp(value_char, "localize")) {
72 return value_char;
73 }
74 return "";
75}
76
77static std::string map_option_compression_hint_cb(const char *value_char)
78{
79 if (!strcmp(value_char, "none") || !strcmp(value_char, "compressible") ||
80 !strcmp(value_char, "incompressible")) {
81 return value_char;
82 }
83 return "";
84}
85
adb31ebb
TL
86static std::string map_option_ms_mode_cb(const char *value_char)
87{
88 if (!strcmp(value_char, "legacy") || !strcmp(value_char, "crc") ||
89 !strcmp(value_char, "secure") || !strcmp(value_char, "prefer-crc") ||
90 !strcmp(value_char, "prefer-secure")) {
91 return value_char;
92 }
93 return "";
94}
95
ec96510d
FG
96static void put_map_option(const std::string &key, const std::string &val,
97 MapOptions* map_options)
7c673cae 98{
ec96510d 99 (*map_options)[key] = val;
7c673cae
FG
100}
101
102static int put_map_option_value(const std::string &opt, const char *value_char,
ec96510d
FG
103 std::string (*parse_cb)(const char *),
104 MapOptions* map_options)
7c673cae
FG
105{
106 if (!value_char || *value_char == '\0') {
107 std::cerr << "rbd: " << opt << " option requires a value" << std::endl;
108 return -EINVAL;
109 }
110
111 std::string value = parse_cb(value_char);
112 if (value.empty()) {
113 std::cerr << "rbd: invalid " << opt << " value '" << value_char << "'"
114 << std::endl;
115 return -EINVAL;
116 }
117
ec96510d 118 put_map_option(opt, opt + "=" + value, map_options);
7c673cae
FG
119 return 0;
120}
121
ec96510d
FG
122static int parse_map_options(const std::string &options_string,
123 MapOptions* map_options)
7c673cae 124{
11fdf7f2
TL
125 char *options = strdup(options_string.c_str());
126 BOOST_SCOPE_EXIT(options) {
127 free(options);
128 } BOOST_SCOPE_EXIT_END;
129
7c673cae
FG
130 for (char *this_char = strtok(options, ", ");
131 this_char != NULL;
132 this_char = strtok(NULL, ",")) {
133 char *value_char;
134
135 if ((value_char = strchr(this_char, '=')) != NULL)
136 *value_char++ = '\0';
137
138 if (!strcmp(this_char, "fsid")) {
ec96510d
FG
139 if (put_map_option_value("fsid", value_char, map_option_uuid_cb,
140 map_options))
7c673cae
FG
141 return -EINVAL;
142 } else if (!strcmp(this_char, "ip")) {
ec96510d
FG
143 if (put_map_option_value("ip", value_char, map_option_ip_cb,
144 map_options))
7c673cae
FG
145 return -EINVAL;
146 } else if (!strcmp(this_char, "share") || !strcmp(this_char, "noshare")) {
ec96510d 147 put_map_option("share", this_char, map_options);
7c673cae 148 } else if (!strcmp(this_char, "crc") || !strcmp(this_char, "nocrc")) {
ec96510d 149 put_map_option("crc", this_char, map_options);
7c673cae
FG
150 } else if (!strcmp(this_char, "cephx_require_signatures") ||
151 !strcmp(this_char, "nocephx_require_signatures")) {
ec96510d 152 put_map_option("cephx_require_signatures", this_char, map_options);
7c673cae
FG
153 } else if (!strcmp(this_char, "tcp_nodelay") ||
154 !strcmp(this_char, "notcp_nodelay")) {
ec96510d 155 put_map_option("tcp_nodelay", this_char, map_options);
7c673cae
FG
156 } else if (!strcmp(this_char, "cephx_sign_messages") ||
157 !strcmp(this_char, "nocephx_sign_messages")) {
ec96510d 158 put_map_option("cephx_sign_messages", this_char, map_options);
7c673cae 159 } else if (!strcmp(this_char, "mount_timeout")) {
ec96510d
FG
160 if (put_map_option_value("mount_timeout", value_char, map_option_int_cb,
161 map_options))
7c673cae 162 return -EINVAL;
11fdf7f2 163 } else if (!strcmp(this_char, "osd_request_timeout")) {
ec96510d
FG
164 if (put_map_option_value("osd_request_timeout", value_char,
165 map_option_int_cb, map_options))
11fdf7f2
TL
166 return -EINVAL;
167 } else if (!strcmp(this_char, "lock_timeout")) {
ec96510d
FG
168 if (put_map_option_value("lock_timeout", value_char, map_option_int_cb,
169 map_options))
11fdf7f2 170 return -EINVAL;
7c673cae 171 } else if (!strcmp(this_char, "osdkeepalive")) {
ec96510d
FG
172 if (put_map_option_value("osdkeepalive", value_char, map_option_int_cb,
173 map_options))
7c673cae
FG
174 return -EINVAL;
175 } else if (!strcmp(this_char, "osd_idle_ttl")) {
ec96510d
FG
176 if (put_map_option_value("osd_idle_ttl", value_char, map_option_int_cb,
177 map_options))
7c673cae
FG
178 return -EINVAL;
179 } else if (!strcmp(this_char, "rw") || !strcmp(this_char, "ro")) {
ec96510d 180 put_map_option("rw", this_char, map_options);
7c673cae 181 } else if (!strcmp(this_char, "queue_depth")) {
ec96510d
FG
182 if (put_map_option_value("queue_depth", value_char, map_option_int_cb,
183 map_options))
7c673cae
FG
184 return -EINVAL;
185 } else if (!strcmp(this_char, "lock_on_read")) {
ec96510d 186 put_map_option("lock_on_read", this_char, map_options);
7c673cae 187 } else if (!strcmp(this_char, "exclusive")) {
ec96510d 188 put_map_option("exclusive", this_char, map_options);
11fdf7f2 189 } else if (!strcmp(this_char, "notrim")) {
ec96510d 190 put_map_option("notrim", this_char, map_options);
11fdf7f2 191 } else if (!strcmp(this_char, "abort_on_full")) {
ec96510d 192 put_map_option("abort_on_full", this_char, map_options);
11fdf7f2 193 } else if (!strcmp(this_char, "alloc_size")) {
ec96510d
FG
194 if (put_map_option_value("alloc_size", value_char, map_option_int_cb,
195 map_options))
11fdf7f2 196 return -EINVAL;
f6b5b4d7
TL
197 } else if (!strcmp(this_char, "crush_location")) {
198 if (put_map_option_value("crush_location", value_char,
ec96510d 199 map_option_string_cb, map_options))
f6b5b4d7
TL
200 return -EINVAL;
201 } else if (!strcmp(this_char, "read_from_replica")) {
202 if (put_map_option_value("read_from_replica", value_char,
ec96510d 203 map_option_read_from_replica_cb, map_options))
f6b5b4d7
TL
204 return -EINVAL;
205 } else if (!strcmp(this_char, "compression_hint")) {
206 if (put_map_option_value("compression_hint", value_char,
ec96510d 207 map_option_compression_hint_cb, map_options))
f6b5b4d7 208 return -EINVAL;
adb31ebb 209 } else if (!strcmp(this_char, "ms_mode")) {
ec96510d
FG
210 if (put_map_option_value("ms_mode", value_char, map_option_ms_mode_cb,
211 map_options))
adb31ebb 212 return -EINVAL;
f91f0fd5 213 } else if (!strcmp(this_char, "udev") || !strcmp(this_char, "noudev")) {
ec96510d 214 put_map_option("udev", this_char, map_options);
7c673cae
FG
215 } else {
216 std::cerr << "rbd: unknown map option '" << this_char << "'" << std::endl;
217 return -EINVAL;
218 }
219 }
220
221 return 0;
222}
223
ec96510d
FG
224static int parse_unmap_options(const std::string &options_string,
225 MapOptions* unmap_options)
7c673cae 226{
11fdf7f2
TL
227 char *options = strdup(options_string.c_str());
228 BOOST_SCOPE_EXIT(options) {
229 free(options);
230 } BOOST_SCOPE_EXIT_END;
231
7c673cae
FG
232 for (char *this_char = strtok(options, ", ");
233 this_char != NULL;
234 this_char = strtok(NULL, ",")) {
235 char *value_char;
236
237 if ((value_char = strchr(this_char, '=')) != NULL)
238 *value_char++ = '\0';
239
240 if (!strcmp(this_char, "force")) {
ec96510d 241 put_map_option("force", this_char, unmap_options);
f91f0fd5 242 } else if (!strcmp(this_char, "udev") || !strcmp(this_char, "noudev")) {
ec96510d 243 put_map_option("udev", this_char, unmap_options);
7c673cae 244 } else {
ec96510d
FG
245 std::cerr << "rbd: unknown unmap option '" << this_char << "'"
246 << std::endl;
7c673cae
FG
247 return -EINVAL;
248 }
249 }
250
251 return 0;
252}
253
11fdf7f2 254static int do_kernel_list(Formatter *f) {
7c673cae
FG
255#if defined(WITH_KRBD)
256 struct krbd_ctx *krbd;
257 int r;
258
f91f0fd5 259 r = krbd_create_from_context(g_ceph_context, 0, &krbd);
7c673cae
FG
260 if (r < 0)
261 return r;
262
263 r = krbd_showmapped(krbd, f);
264
265 krbd_destroy(krbd);
266 return r;
267#else
11fdf7f2
TL
268 std::cerr << "rbd: kernel device is not supported" << std::endl;
269 return -EOPNOTSUPP;
7c673cae 270#endif
7c673cae
FG
271}
272
273static int get_unsupported_features(librbd::Image &image,
274 uint64_t *unsupported_features)
275{
276 char buf[20];
277 uint64_t features, supported_features;
278 int r;
279
280 r = safe_read_file("/sys/bus/rbd/", "supported_features", buf,
281 sizeof(buf) - 1);
282 if (r < 0)
283 return r;
284
285 buf[r] = '\0';
286 try {
287 supported_features = std::stoull(buf, nullptr, 16);
288 } catch (...) {
289 return -EINVAL;
290 }
291
292 r = image.features(&features);
293 if (r < 0)
294 return r;
295
296 *unsupported_features = features & ~supported_features;
297 return 0;
298}
299
300/*
301 * hint user to check syslog for krbd related messages and provide suggestions
302 * based on errno return by krbd_map(). also note that even if some librbd calls
303 * fail, we at least dump the "try dmesg..." message to aid debugging.
304 */
11fdf7f2
TL
305static void print_error_description(const char *poolname,
306 const char *nspace_name,
307 const char *imgname,
308 const char *snapname,
309 int maperrno)
7c673cae
FG
310{
311 int r;
312 uint8_t oldformat;
313 librados::Rados rados;
314 librados::IoCtx ioctx;
315 librbd::Image image;
316
317 if (maperrno == -ENOENT)
318 goto done;
319
11fdf7f2 320 r = utils::init_and_open_image(poolname, nspace_name, imgname, "", snapname,
7c673cae
FG
321 true, &rados, &ioctx, &image);
322 if (r < 0)
323 goto done;
324
325 r = image.old_format(&oldformat);
326 if (r < 0)
327 goto done;
328
329 /*
330 * kernel returns -ENXIO when mapping a V2 image due to unsupported feature
331 * set - so, hint about that too...
332 */
333 if (!oldformat && (maperrno == -ENXIO)) {
334 uint64_t unsupported_features;
335 bool need_terminate = true;
336
337 std::cout << "RBD image feature set mismatch. ";
338 r = get_unsupported_features(image, &unsupported_features);
339 if (r == 0 && (unsupported_features & ~RBD_FEATURES_ALL) == 0) {
340 uint64_t immutable = RBD_FEATURES_ALL & ~(RBD_FEATURES_MUTABLE |
341 RBD_FEATURES_DISABLE_ONLY);
342 if (unsupported_features & immutable) {
343 std::cout << "This image cannot be mapped because the following "
344 << "immutable features are unsupported by the kernel:";
345 unsupported_features &= immutable;
346 need_terminate = false;
347 } else {
348 std::cout << "You can disable features unsupported by the kernel "
349 << "with \"rbd feature disable ";
11fdf7f2 350 if (poolname != utils::get_default_pool_name() || *nspace_name) {
7c673cae 351 std::cout << poolname << "/";
31f18b77 352 }
11fdf7f2
TL
353 if (*nspace_name) {
354 std::cout << nspace_name << "/";
355 }
7c673cae
FG
356 std::cout << imgname;
357 }
358 } else {
359 std::cout << "Try disabling features unsupported by the kernel "
360 << "with \"rbd feature disable";
361 unsupported_features = 0;
362 }
363 for (auto it : at::ImageFeatures::FEATURE_MAPPING) {
364 if (it.first & unsupported_features) {
365 std::cout << " " << it.second;
366 }
367 }
368 if (need_terminate)
369 std::cout << "\"";
370 std::cout << "." << std::endl;
371 }
372
373 done:
374 std::cout << "In some cases useful info is found in syslog - try \"dmesg | tail\"." << std::endl;
375}
376
11fdf7f2 377static int do_kernel_map(const char *poolname, const char *nspace_name,
ec96510d
FG
378 const char *imgname, const char *snapname,
379 MapOptions&& map_options)
7c673cae
FG
380{
381#if defined(WITH_KRBD)
382 struct krbd_ctx *krbd;
383 std::ostringstream oss;
f91f0fd5 384 uint32_t flags = 0;
7c673cae
FG
385 char *devnode;
386 int r;
387
f91f0fd5 388 for (auto it = map_options.begin(); it != map_options.end(); ) {
7c673cae
FG
389 // for compatibility with < 3.7 kernels, assume that rw is on by
390 // default and omit it even if it was specified by the user
391 // (see ceph.git commit fb0f1986449b)
392 if (it->first == "rw" && it->second == "rw") {
b32b8144 393 it = map_options.erase(it);
f91f0fd5
TL
394 } else if (it->first == "udev") {
395 if (it->second == "noudev") {
396 flags |= KRBD_CTX_F_NOUDEV;
397 }
398 it = map_options.erase(it);
7c673cae
FG
399 } else {
400 if (it != map_options.begin())
401 oss << ",";
402 oss << it->second;
403 ++it;
404 }
405 }
406
f91f0fd5
TL
407 r = krbd_create_from_context(g_ceph_context, flags, &krbd);
408 if (r < 0)
409 return r;
410
11fdf7f2 411 r = krbd_is_mapped(krbd, poolname, nspace_name, imgname, snapname, &devnode);
7c673cae 412 if (r < 0) {
11fdf7f2
TL
413 std::cerr << "rbd: warning: can't get image map information: "
414 << cpp_strerror(r) << std::endl;
415 } else if (r > 0) {
416 std::cerr << "rbd: warning: image already mapped as " << devnode
417 << std::endl;
418 free(devnode);
419 }
420
421 r = krbd_map(krbd, poolname, nspace_name, imgname, snapname,
422 oss.str().c_str(), &devnode);
423 if (r < 0) {
424 print_error_description(poolname, nspace_name, imgname, snapname, r);
7c673cae
FG
425 goto out;
426 }
427
428 std::cout << devnode << std::endl;
429
430 free(devnode);
431out:
432 krbd_destroy(krbd);
433 return r;
434#else
11fdf7f2
TL
435 std::cerr << "rbd: kernel device is not supported" << std::endl;
436 return -EOPNOTSUPP;
7c673cae
FG
437#endif
438}
439
440static int do_kernel_unmap(const char *dev, const char *poolname,
11fdf7f2 441 const char *nspace_name, const char *imgname,
ec96510d 442 const char *snapname, MapOptions&& unmap_options)
7c673cae
FG
443{
444#if defined(WITH_KRBD)
445 struct krbd_ctx *krbd;
446 std::ostringstream oss;
f91f0fd5 447 uint32_t flags = 0;
7c673cae
FG
448 int r;
449
ec96510d 450 for (auto it = unmap_options.begin(); it != unmap_options.end(); ) {
f91f0fd5
TL
451 if (it->first == "udev") {
452 if (it->second == "noudev") {
453 flags |= KRBD_CTX_F_NOUDEV;
454 }
ec96510d 455 it = unmap_options.erase(it);
f91f0fd5 456 } else {
ec96510d 457 if (it != unmap_options.begin())
f91f0fd5
TL
458 oss << ",";
459 oss << it->second;
460 ++it;
461 }
462 }
463
464 r = krbd_create_from_context(g_ceph_context, flags, &krbd);
7c673cae
FG
465 if (r < 0)
466 return r;
467
7c673cae
FG
468 if (dev)
469 r = krbd_unmap(krbd, dev, oss.str().c_str());
470 else
11fdf7f2 471 r = krbd_unmap_by_spec(krbd, poolname, nspace_name, imgname, snapname,
7c673cae
FG
472 oss.str().c_str());
473
474 krbd_destroy(krbd);
475 return r;
476#else
11fdf7f2
TL
477 std::cerr << "rbd: kernel device is not supported" << std::endl;
478 return -EOPNOTSUPP;
7c673cae 479#endif
7c673cae
FG
480}
481
11fdf7f2
TL
482int execute_list(const po::variables_map &vm,
483 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
484 at::Format::Formatter formatter;
485 int r = utils::get_formatter(vm, &formatter);
486 if (r < 0) {
487 return r;
488 }
489
490 utils::init_context();
491
11fdf7f2 492 r = do_kernel_list(formatter.get());
7c673cae 493 if (r < 0) {
11fdf7f2 494 std::cerr << "rbd: device list failed: " << cpp_strerror(r) << std::endl;
7c673cae
FG
495 return r;
496 }
497 return 0;
498}
499
11fdf7f2
TL
500int execute_map(const po::variables_map &vm,
501 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
502 size_t arg_index = 0;
503 std::string pool_name;
11fdf7f2 504 std::string nspace_name;
7c673cae
FG
505 std::string image_name;
506 std::string snap_name;
507 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
508 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &nspace_name,
509 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_PERMITTED,
7c673cae
FG
510 utils::SPEC_VALIDATION_NONE);
511 if (r < 0) {
512 return r;
513 }
514
ec96510d 515 MapOptions map_options;
7c673cae 516 if (vm.count("options")) {
11fdf7f2 517 for (auto &options : vm["options"].as<std::vector<std::string>>()) {
ec96510d 518 r = parse_map_options(options, &map_options);
11fdf7f2
TL
519 if (r < 0) {
520 std::cerr << "rbd: couldn't parse map options" << std::endl;
521 return r;
522 }
7c673cae
FG
523 }
524 }
525
f91f0fd5
TL
526 // parse options common to all device types after parsing krbd-specific
527 // options so that common options win (in particular "-o rw --read-only"
528 // should result in read-only mapping)
529 if (vm["read-only"].as<bool>()) {
ec96510d 530 put_map_option("rw", "ro", &map_options);
f91f0fd5
TL
531 }
532 if (vm["exclusive"].as<bool>()) {
ec96510d 533 put_map_option("exclusive", "exclusive", &map_options);
f91f0fd5
TL
534 }
535
ec96510d
FG
536 // connect to the cluster to get the default pool and the default map
537 // options
538 librados::Rados rados;
539 r = utils::init_rados(&rados);
540 if (r < 0) {
541 return r;
542 }
543
544 utils::normalize_pool_name(&pool_name);
545
546 MapOptions default_map_options;
547 r = parse_map_options(
548 g_conf().get_val<std::string>("rbd_default_map_options"),
549 &default_map_options);
550 if (r < 0) {
551 std::cerr << "rbd: couldn't parse default map options" << std::endl;
552 return r;
553 }
554 for (auto& [key, value] : default_map_options) {
555 if (map_options.count(key) == 0) {
556 map_options[key] = value;
557 }
558 }
7c673cae 559
11fdf7f2 560 r = do_kernel_map(pool_name.c_str(), nspace_name.c_str(), image_name.c_str(),
ec96510d 561 snap_name.c_str(), std::move(map_options));
7c673cae
FG
562 if (r < 0) {
563 std::cerr << "rbd: map failed: " << cpp_strerror(r) << std::endl;
564 return r;
565 }
566
567 return 0;
568}
569
11fdf7f2
TL
570int execute_unmap(const po::variables_map &vm,
571 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
572 std::string device_name = utils::get_positional_argument(vm, 0);
573 if (!boost::starts_with(device_name, "/dev/")) {
574 device_name.clear();
575 }
576
577 size_t arg_index = 0;
578 std::string pool_name;
11fdf7f2 579 std::string nspace_name;
7c673cae
FG
580 std::string image_name;
581 std::string snap_name;
582 int r;
583 if (device_name.empty()) {
584 r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
585 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &nspace_name,
586 &image_name, &snap_name, false, utils::SNAPSHOT_PRESENCE_PERMITTED,
587 utils::SPEC_VALIDATION_NONE);
7c673cae
FG
588 if (r < 0) {
589 return r;
590 }
591 }
592
593 if (device_name.empty() && image_name.empty()) {
594 std::cerr << "rbd: unmap requires either image name or device path"
595 << std::endl;
596 return -EINVAL;
597 }
598
ec96510d 599 MapOptions unmap_options;
7c673cae 600 if (vm.count("options")) {
11fdf7f2 601 for (auto &options : vm["options"].as<std::vector<std::string>>()) {
ec96510d 602 r = parse_unmap_options(options, &unmap_options);
11fdf7f2
TL
603 if (r < 0) {
604 std::cerr << "rbd: couldn't parse unmap options" << std::endl;
605 return r;
606 }
7c673cae
FG
607 }
608 }
609
ec96510d
FG
610 if (device_name.empty() && pool_name.empty()) {
611 // connect to the cluster to get the default pool
612 librados::Rados rados;
613 r = utils::init_rados(&rados);
614 if (r < 0) {
615 return r;
616 }
617
618 utils::normalize_pool_name(&pool_name);
619 }
7c673cae
FG
620
621 r = do_kernel_unmap(device_name.empty() ? nullptr : device_name.c_str(),
11fdf7f2 622 pool_name.c_str(), nspace_name.c_str(),
ec96510d
FG
623 image_name.c_str(), snap_name.c_str(),
624 std::move(unmap_options));
7c673cae
FG
625 if (r < 0) {
626 std::cerr << "rbd: unmap failed: " << cpp_strerror(r) << std::endl;
627 return r;
628 }
629 return 0;
630}
631
7c673cae
FG
632} // namespace kernel
633} // namespace action
634} // namespace rbd