2 * Ceph - scalable distributed file system
4 * Copyright (C) 2014 Inktank Storage, Inc.
6 * This is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License version 2.1, as published by the Free Software
9 * Foundation. See file COPYING.
26 #include <sys/sysmacros.h>
27 #include <sys/types.h>
32 #include "auth/KeyRing.h"
33 #include "common/errno.h"
34 #include "common/Formatter.h"
35 #include "common/module.h"
36 #include "common/run_cmd.h"
37 #include "common/safe_io.h"
38 #include "common/secret.h"
39 #include "common/TextTable.h"
40 #include "common/Thread.h"
41 #include "include/ceph_assert.h"
42 #include "include/stringify.h"
43 #include "include/krbd.h"
44 #include "mon/MonMap.h"
46 #include <blkid/blkid.h>
47 #include <boost/algorithm/string/predicate.hpp>
48 #include <boost/tokenizer.hpp>
51 static const int UDEV_BUF_SIZE
= 1 << 20; /* doubled to 2M (SO_RCVBUFFORCE) */
52 static const char DEVNODE_PREFIX
[] = "/dev/rbd";
53 static const char SNAP_HEAD_NAME
[] = "-";
55 #define DEFINE_UDEV_UPTR(what) \
56 struct udev_##what##_deleter { \
57 void operator()(udev_##what *p) { \
58 udev_##what##_unref(p); \
61 using udev_##what##_uptr = \
62 std::unique_ptr<udev_##what, udev_##what##_deleter>;
64 DEFINE_UDEV_UPTR(monitor
) /* udev_monitor_uptr */
65 DEFINE_UDEV_UPTR(enumerate
) /* udev_enumerate_uptr */
66 DEFINE_UDEV_UPTR(device
) /* udev_device_uptr */
73 uint32_t flags
; /* KRBD_CTX_F_* */
77 std::string pool_name
;
78 std::string nspace_name
;
79 std::string image_name
;
80 std::string snap_name
;
82 krbd_spec(const char *pool_name
, const char *nspace_name
,
83 const char *image_name
, const char *snap_name
)
84 : pool_name(pool_name
),
85 nspace_name(nspace_name
),
86 image_name(image_name
),
87 snap_name(*snap_name
? snap_name
: SNAP_HEAD_NAME
) { }
89 bool operator==(const krbd_spec
& rhs
) const {
90 return pool_name
== rhs
.pool_name
&&
91 nspace_name
== rhs
.nspace_name
&&
92 image_name
== rhs
.image_name
&&
93 snap_name
== rhs
.snap_name
;
97 static std::ostream
& operator<<(std::ostream
& os
, const krbd_spec
& spec
)
99 os
<< spec
.pool_name
<< "/";
100 if (!spec
.nspace_name
.empty())
101 os
<< spec
.nspace_name
<< "/";
102 os
<< spec
.image_name
;
103 if (spec
.snap_name
!= SNAP_HEAD_NAME
)
104 os
<< "@" << spec
.snap_name
;
108 static std::optional
<krbd_spec
> spec_from_dev(udev_device
*dev
)
110 const char *pool_name
= udev_device_get_sysattr_value(dev
, "pool");
111 const char *nspace_name
= udev_device_get_sysattr_value(dev
, "pool_ns");
112 const char *image_name
= udev_device_get_sysattr_value(dev
, "name");
113 const char *snap_name
= udev_device_get_sysattr_value(dev
, "current_snap");
115 if (!pool_name
|| !image_name
|| !snap_name
)
118 return std::make_optional
<krbd_spec
>(
119 pool_name
, nspace_name
?: "", image_name
, snap_name
);
122 static udev_device_uptr
dev_from_list_entry(udev
*udev
, udev_list_entry
*l
)
124 return udev_device_uptr(
125 udev_device_new_from_syspath(udev
, udev_list_entry_get_name(l
)));
128 static std::string
get_devnode(udev_device
*dev
)
130 std::string devnode
= DEVNODE_PREFIX
;
131 devnode
+= udev_device_get_sysname(dev
);
135 static int sysfs_write_rbd(const char *which
, const string
& buf
)
137 const string s
= string("/sys/bus/rbd/") + which
;
138 const string t
= s
+ "_single_major";
143 * 'add' and 'add_single_major' interfaces are identical, but if rbd
144 * kernel module is new enough and is configured to use single-major
145 * scheme, 'add' is disabled in order to prevent old userspace from
146 * doing weird things at unmap time.
148 * Same goes for 'remove' vs 'remove_single_major'.
150 fd
= open(t
.c_str(), O_WRONLY
);
152 if (errno
== ENOENT
) {
153 fd
= open(s
.c_str(), O_WRONLY
);
161 r
= safe_write(fd
, buf
.c_str(), buf
.size());
167 static int sysfs_write_rbd_add(const string
& buf
)
169 return sysfs_write_rbd("add", buf
);
172 static int sysfs_write_rbd_remove(const string
& buf
)
174 return sysfs_write_rbd("remove", buf
);
177 static int have_minor_attr(void)
180 * 'minor' attribute was added as part of single_major merge, which
181 * exposed the 'single_major' parameter. 'minor' is always present,
182 * regardless of whether single-major scheme is turned on or not.
184 * (Something like ver >= KERNEL_VERSION(3, 14, 0) is a no-go because
185 * this has to work with rbd.ko backported to various kernels.)
187 return access("/sys/module/rbd/parameters/single_major", F_OK
) == 0;
190 static int build_map_buf(CephContext
*cct
, const krbd_spec
& spec
,
191 const string
& options
, string
*pbuf
)
194 std::ostringstream oss
;
197 boost::char_separator
<char> sep(",");
198 boost::tokenizer
<boost::char_separator
<char>> tok(options
, sep
);
199 for (const auto& t
: tok
) {
200 if (boost::starts_with(t
, "ms_mode=")) {
201 /* msgr2 unless ms_mode=legacy */
202 msgr2
= t
.compare(8, t
.npos
, "legacy");
207 r
= monmap
.build_initial(cct
, false, std::cerr
);
212 * If msgr2, filter TYPE_MSGR2 addresses. Otherwise, filter
213 * TYPE_LEGACY addresses.
215 for (const auto& p
: monmap
.mon_info
) {
216 for (const auto& a
: p
.second
.public_addrs
.v
) {
217 if ((msgr2
&& a
.is_msgr2()) || (!msgr2
&& a
.is_legacy())) {
218 if (oss
.tellp() > 0) {
221 oss
<< a
.get_sockaddr();
226 if (oss
.tellp() == 0) {
227 std::cerr
<< "rbd: failed to get mon address (possible ms_mode mismatch)" << std::endl
;
231 oss
<< " name=" << cct
->_conf
->name
.get_id();
234 auto auth_client_required
=
235 cct
->_conf
.get_val
<std::string
>("auth_client_required");
236 if (auth_client_required
!= "none") {
237 r
= keyring
.from_ceph_context(cct
);
238 auto keyfile
= cct
->_conf
.get_val
<std::string
>("keyfile");
239 auto key
= cct
->_conf
.get_val
<std::string
>("key");
240 if (r
== -ENOENT
&& keyfile
.empty() && key
.empty())
243 std::cerr
<< "rbd: failed to get secret" << std::endl
;
249 string key_name
= string("client.") + cct
->_conf
->name
.get_id();
250 if (keyring
.get_secret(cct
->_conf
->name
, secret
)) {
252 secret
.encode_base64(secret_str
);
254 r
= set_kernel_secret(secret_str
.c_str(), key_name
.c_str());
257 std::cerr
<< "rbd: warning: secret has length 0" << std::endl
;
258 oss
<< ",key=" << key_name
;
259 } else if (r
== -ENODEV
|| r
== -ENOSYS
) {
260 // running against older kernel; fall back to secret= in options
261 oss
<< ",secret=" << secret_str
;
263 std::cerr
<< "rbd: failed to add secret '" << key_name
<< "' to kernel"
267 } else if (is_kernel_secret(key_name
.c_str())) {
268 oss
<< ",key=" << key_name
;
271 if (!options
.empty())
272 oss
<< "," << options
;
273 if (!spec
.nspace_name
.empty())
274 oss
<< ",_pool_ns=" << spec
.nspace_name
;
276 oss
<< " " << spec
.pool_name
<< " " << spec
.image_name
<< " "
285 * <kernel error, false> - didn't map
286 * <0 or udev error, true> - mapped
288 template <typename F
>
289 static std::pair
<int, bool> wait_for_mapping(int sysfs_r_fd
, udev_monitor
*mon
,
290 F udev_device_handler
)
292 struct pollfd fds
[2];
293 int sysfs_r
= INT_MAX
, udev_r
= INT_MAX
;
296 fds
[0].fd
= sysfs_r_fd
;
297 fds
[0].events
= POLLIN
;
298 fds
[1].fd
= udev_monitor_get_fd(mon
);
299 fds
[1].events
= POLLIN
;
302 if (poll(fds
, 2, -1) < 0) {
303 ceph_abort_msgf("poll failed: %d", -errno
);
306 if (fds
[0].revents
) {
307 r
= safe_read_exact(sysfs_r_fd
, &sysfs_r
, sizeof(sysfs_r
));
309 ceph_abort_msgf("safe_read_exact failed: %d", r
);
312 return std::make_pair(sysfs_r
, false);
314 if (udev_r
!= INT_MAX
) {
315 ceph_assert(!sysfs_r
);
316 return std::make_pair(udev_r
, true);
321 if (fds
[1].revents
) {
323 udev_device_uptr
dev(udev_monitor_receive_device(mon
));
325 if (errno
!= EINTR
&& errno
!= EAGAIN
) {
327 if (sysfs_r
!= INT_MAX
) {
328 ceph_assert(!sysfs_r
);
329 return std::make_pair(udev_r
, true);
335 if (udev_device_handler(std::move(dev
))) {
337 if (sysfs_r
!= INT_MAX
) {
338 ceph_assert(!sysfs_r
);
339 return std::make_pair(udev_r
, true);
349 class UdevMapHandler
{
351 UdevMapHandler(const krbd_spec
*spec
, std::string
*pdevnode
,
352 std::string
*majnum
, std::string
*minnum
) :
353 m_spec(spec
), m_pdevnode(pdevnode
), m_majnum(majnum
), m_minnum(minnum
) {}
356 * Catch /sys/devices/rbd/<id>/ and wait for the corresponding
357 * block device to show up. This is necessary because rbd devices
358 * and block devices aren't linked together in our sysfs layout.
360 * Note that our "block" event can come before the "rbd" event, so
361 * all potential "block" events are gathered in m_block_devs before
362 * m_bus_dev is caught.
364 bool operator()(udev_device_uptr dev
) {
365 if (strcmp(udev_device_get_action(dev
.get()), "add")) {
368 if (!strcmp(udev_device_get_subsystem(dev
.get()), "rbd")) {
370 auto spec
= spec_from_dev(dev
.get());
371 if (spec
&& *spec
== *m_spec
) {
372 m_bus_dev
= std::move(dev
);
373 m_devnode
= get_devnode(m_bus_dev
.get());
376 } else if (!strcmp(udev_device_get_subsystem(dev
.get()), "block")) {
377 if (boost::starts_with(udev_device_get_devnode(dev
.get()),
379 m_block_devs
.push_back(std::move(dev
));
383 if (m_bus_dev
&& !m_block_devs
.empty()) {
384 for (const auto& p
: m_block_devs
) {
385 if (udev_device_get_devnode(p
.get()) == m_devnode
) {
386 *m_pdevnode
= std::move(m_devnode
);
387 *m_majnum
= udev_device_get_property_value(p
.get(), "MAJOR");
388 *m_minnum
= udev_device_get_property_value(p
.get(), "MINOR");
389 ceph_assert(*m_majnum
== udev_device_get_sysattr_value(
390 m_bus_dev
.get(), "major"));
391 ceph_assert(!have_minor_attr() ||
392 *m_minnum
== udev_device_get_sysattr_value(
393 m_bus_dev
.get(), "minor"));
397 m_block_devs
.clear();
403 udev_device_uptr m_bus_dev
;
404 std::vector
<udev_device_uptr
> m_block_devs
;
405 std::string m_devnode
;
406 const krbd_spec
*m_spec
;
407 std::string
*m_pdevnode
;
408 std::string
*m_majnum
;
409 std::string
*m_minnum
;
412 static const char *get_event_source(const krbd_ctx
*ctx
)
414 if (ctx
->flags
& KRBD_CTX_F_NOUDEV
) {
416 * For block devices (unlike network interfaces, they don't
417 * carry any namespace tags), the kernel broadcasts uevents
418 * into all network namespaces that are owned by the initial
419 * user namespace. This restriction is new in 4.18: starting
420 * with 2.6.35 and through 4.17 the kernel broadcast uevents
421 * into all network namespaces, period.
423 * However, when invoked from a non-initial user namespace,
424 * udev_monitor_receive_device() has always ignored both kernel
425 * and udev uevents by virtue of requiring SCM_CREDENTIALS and
426 * checking that ucred->uid == 0. When UIDs and GIDs are sent to
427 * a process in a user namespace, they are translated according
428 * to that process's UID and GID mappings and, unless root in the
429 * user namespace is mapped to the global root, that check fails.
430 * Normally they show up as 65534(nobody) because the global root
437 * Like most netlink messages, udev uevents don't cross network
438 * namespace boundaries and are therefore confined to the initial
444 static int do_map(krbd_ctx
*ctx
, const krbd_spec
& spec
, const string
& buf
,
447 std::string majnum
, minnum
;
453 udev_monitor_uptr
mon(udev_monitor_new_from_netlink(ctx
->udev
,
454 get_event_source(ctx
)));
458 r
= udev_monitor_filter_add_match_subsystem_devtype(mon
.get(), "rbd",
463 r
= udev_monitor_filter_add_match_subsystem_devtype(mon
.get(), "block",
468 r
= udev_monitor_set_receive_buffer_size(mon
.get(), UDEV_BUF_SIZE
);
470 std::cerr
<< "rbd: failed to set udev buffer size: " << cpp_strerror(r
)
475 r
= udev_monitor_enable_receiving(mon
.get());
479 if (pipe2(fds
, O_NONBLOCK
) < 0)
482 auto mapper
= make_named_thread("mapper", [&buf
, sysfs_r_fd
= fds
[1]]() {
483 int sysfs_r
= sysfs_write_rbd_add(buf
);
484 int r
= safe_write(sysfs_r_fd
, &sysfs_r
, sizeof(sysfs_r
));
486 ceph_abort_msgf("safe_write failed: %d", r
);
490 std::tie(r
, mapped
) = wait_for_mapping(fds
[0], mon
.get(),
491 UdevMapHandler(&spec
, pname
, &majnum
,
495 std::cerr
<< "rbd: sysfs write failed" << std::endl
;
497 std::cerr
<< "rbd: udev wait failed" << std::endl
;
498 /* TODO: fall back to enumeration */
510 * Make sure our device node is there. This is intended to help
511 * diagnose environments where "rbd map" is run from a container with
512 * a private /dev and some external mechanism (e.g. udev) is used to
513 * add the device to the container asynchronously, possibly seconds
514 * after "rbd map" successfully exits. These setups are very fragile
515 * and in some cases can even lead to data loss, depending on higher
516 * level logic and orchestration layers involved.
519 if (stat(pname
->c_str(), &sb
) < 0 || !S_ISBLK(sb
.st_mode
)) {
520 std::cerr
<< "rbd: mapping succeeded but " << *pname
521 << " is not accessible, is host /dev mounted?" << std::endl
;
524 if (stringify(major(sb
.st_rdev
)) != majnum
||
525 stringify(minor(sb
.st_rdev
)) != minnum
) {
526 std::cerr
<< "rbd: mapping succeeded but " << *pname
527 << " (" << major(sb
.st_rdev
) << ":" << minor(sb
.st_rdev
)
528 << ") does not match expected " << majnum
<< ":" << minnum
536 static int map_image(struct krbd_ctx
*ctx
, const krbd_spec
& spec
,
537 const char *options
, string
*pname
)
543 * Modprobe rbd kernel module. If it supports single-major device
544 * number allocation scheme, make sure it's turned on.
546 * Do this before calling build_map_buf() - it wants "ceph" key type
549 if (access("/sys/bus/rbd", F_OK
) != 0) {
550 const char *module_options
= NULL
;
551 if (module_has_param("rbd", "single_major"))
552 module_options
= "single_major=Y";
554 r
= module_load("rbd", module_options
);
556 std::cerr
<< "rbd: failed to load rbd kernel module (" << r
<< ")"
559 * Ignore the error: modprobe failing doesn't necessarily prevent
565 r
= build_map_buf(ctx
->cct
, spec
, options
, &buf
);
569 return do_map(ctx
, spec
, buf
, pname
);
572 static int devno_to_krbd_id(struct udev
*udev
, dev_t devno
, string
*pid
)
574 udev_enumerate_uptr enm
;
575 struct udev_list_entry
*l
;
579 enm
.reset(udev_enumerate_new(udev
));
583 r
= udev_enumerate_add_match_subsystem(enm
.get(), "rbd");
587 r
= udev_enumerate_add_match_sysattr(enm
.get(), "major",
588 stringify(major(devno
)).c_str());
592 if (have_minor_attr()) {
593 r
= udev_enumerate_add_match_sysattr(enm
.get(), "minor",
594 stringify(minor(devno
)).c_str());
599 r
= udev_enumerate_scan_devices(enm
.get());
601 if (r
== -ENOENT
|| r
== -ENODEV
) {
602 std::cerr
<< "rbd: udev enumerate failed, retrying" << std::endl
;
608 l
= udev_enumerate_get_list_entry(enm
.get());
612 /* make sure there is only one match */
613 ceph_assert(!udev_list_entry_get_next(l
));
615 auto dev
= dev_from_list_entry(udev
, l
);
619 *pid
= udev_device_get_sysname(dev
.get());
623 // wrap any of * ? [ between square brackets
624 static std::string
escape_glob(const std::string
& s
)
626 std::regex
glob_meta("([*?[])");
627 return std::regex_replace(s
, glob_meta
, "[$1]");
630 static int __enumerate_devices(struct udev
*udev
, const krbd_spec
& spec
,
631 bool match_nspace
, udev_enumerate_uptr
*penm
)
633 udev_enumerate_uptr enm
;
637 enm
.reset(udev_enumerate_new(udev
));
641 r
= udev_enumerate_add_match_subsystem(enm
.get(), "rbd");
645 r
= udev_enumerate_add_match_sysattr(enm
.get(), "pool",
646 escape_glob(spec
.pool_name
).c_str());
651 r
= udev_enumerate_add_match_sysattr(enm
.get(), "pool_ns",
652 escape_glob(spec
.nspace_name
).c_str());
655 * Match _only_ devices that don't have pool_ns attribute.
656 * If the kernel supports namespaces, the result will be empty.
658 r
= udev_enumerate_add_nomatch_sysattr(enm
.get(), "pool_ns", nullptr);
663 r
= udev_enumerate_add_match_sysattr(enm
.get(), "name",
664 escape_glob(spec
.image_name
).c_str());
668 r
= udev_enumerate_add_match_sysattr(enm
.get(), "current_snap",
669 escape_glob(spec
.snap_name
).c_str());
673 r
= udev_enumerate_scan_devices(enm
.get());
675 if (r
== -ENOENT
|| r
== -ENODEV
) {
676 std::cerr
<< "rbd: udev enumerate failed, retrying" << std::endl
;
682 *penm
= std::move(enm
);
686 static int enumerate_devices(struct udev
*udev
, const krbd_spec
& spec
,
687 udev_enumerate_uptr
*penm
)
689 udev_enumerate_uptr enm
;
692 r
= __enumerate_devices(udev
, spec
, true, &enm
);
697 * If no namespace is set, try again with match_nspace=false to
698 * handle older kernels. On a newer kernel the result will remain
699 * the same (i.e. empty).
701 if (!udev_enumerate_get_list_entry(enm
.get()) && spec
.nspace_name
.empty()) {
702 r
= __enumerate_devices(udev
, spec
, false, &enm
);
707 *penm
= std::move(enm
);
711 static int spec_to_devno_and_krbd_id(struct udev
*udev
, const krbd_spec
& spec
,
712 dev_t
*pdevno
, string
*pid
)
714 udev_enumerate_uptr enm
;
715 struct udev_list_entry
*l
;
716 unsigned int maj
, min
= 0;
720 r
= enumerate_devices(udev
, spec
, &enm
);
724 l
= udev_enumerate_get_list_entry(enm
.get());
728 auto dev
= dev_from_list_entry(udev
, l
);
732 maj
= strict_strtoll(udev_device_get_sysattr_value(dev
.get(), "major"), 10,
735 std::cerr
<< "rbd: couldn't parse major: " << err
<< std::endl
;
738 if (have_minor_attr()) {
739 min
= strict_strtoll(udev_device_get_sysattr_value(dev
.get(), "minor"), 10,
742 std::cerr
<< "rbd: couldn't parse minor: " << err
<< std::endl
;
748 * If an image is mapped more than once don't bother trying to unmap
749 * all devices - let users run unmap the same number of times they
752 if (udev_list_entry_get_next(l
))
753 std::cerr
<< "rbd: " << spec
<< ": mapped more than once, unmapping "
754 << get_devnode(dev
.get()) << " only" << std::endl
;
756 *pdevno
= makedev(maj
, min
);
757 *pid
= udev_device_get_sysname(dev
.get());
761 static void append_unmap_options(std::string
*buf
, const char *options
)
763 if (strcmp(options
, "") != 0) {
769 class UdevUnmapHandler
{
771 UdevUnmapHandler(dev_t devno
) : m_devno(devno
) {}
773 bool operator()(udev_device_uptr dev
) {
774 if (strcmp(udev_device_get_action(dev
.get()), "remove")) {
777 return udev_device_get_devnum(dev
.get()) == m_devno
;
784 static int do_unmap(krbd_ctx
*ctx
, dev_t devno
, const string
& buf
)
790 udev_monitor_uptr
mon(udev_monitor_new_from_netlink(ctx
->udev
,
791 get_event_source(ctx
)));
795 r
= udev_monitor_filter_add_match_subsystem_devtype(mon
.get(), "block",
800 r
= udev_monitor_set_receive_buffer_size(mon
.get(), UDEV_BUF_SIZE
);
802 std::cerr
<< "rbd: failed to set udev buffer size: " << cpp_strerror(r
)
807 r
= udev_monitor_enable_receiving(mon
.get());
811 if (pipe2(fds
, O_NONBLOCK
) < 0)
814 auto unmapper
= make_named_thread(
815 "unmapper", [&buf
, sysfs_r_fd
= fds
[1], flags
= ctx
->flags
]() {
817 * On final device close(), kernel sends a block change event, in
818 * response to which udev apparently runs blkid on the device. This
819 * makes unmap fail with EBUSY, if issued right after final close().
820 * Try to circumvent this with a retry before turning to udev.
822 for (int tries
= 0; ; tries
++) {
823 int sysfs_r
= sysfs_write_rbd_remove(buf
);
824 if (sysfs_r
== -EBUSY
&& tries
< 2) {
827 } else if (!(flags
& KRBD_CTX_F_NOUDEV
)) {
829 * libudev does not provide the "wait until the queue is empty"
830 * API or the sufficient amount of primitives to build it from.
832 std::string err
= run_cmd("udevadm", "settle", "--timeout", "10",
835 std::cerr
<< "rbd: " << err
<< std::endl
;
838 int r
= safe_write(sysfs_r_fd
, &sysfs_r
, sizeof(sysfs_r
));
840 ceph_abort_msgf("safe_write failed: %d", r
);
847 std::tie(r
, unmapped
) = wait_for_mapping(fds
[0], mon
.get(),
848 UdevUnmapHandler(devno
));
851 std::cerr
<< "rbd: sysfs write failed" << std::endl
;
853 std::cerr
<< "rbd: udev wait failed: " << cpp_strerror(r
) << std::endl
;
864 static int unmap_image(struct krbd_ctx
*ctx
, const char *devnode
,
868 dev_t wholedevno
= 0;
872 if (stat(devnode
, &sb
) < 0 || !S_ISBLK(sb
.st_mode
)) {
873 std::cerr
<< "rbd: '" << devnode
<< "' is not a block device" << std::endl
;
877 r
= blkid_devno_to_wholedisk(sb
.st_rdev
, NULL
, 0, &wholedevno
);
879 std::cerr
<< "rbd: couldn't compute wholedevno: " << cpp_strerror(r
)
882 * Ignore the error: we are given whole disks most of the time, and
883 * if it turns out this is a partition we will fail later anyway.
885 wholedevno
= sb
.st_rdev
;
888 for (int tries
= 0; ; tries
++) {
889 r
= devno_to_krbd_id(ctx
->udev
, wholedevno
, &buf
);
890 if (r
== -ENOENT
&& tries
< 2) {
895 std::cerr
<< "rbd: '" << devnode
<< "' is not an rbd device"
902 std::cerr
<< "rbd: udev enumerate missed a device, tries = " << tries
909 append_unmap_options(&buf
, options
);
910 return do_unmap(ctx
, wholedevno
, buf
);
913 static int unmap_image(struct krbd_ctx
*ctx
, const krbd_spec
& spec
,
920 for (int tries
= 0; ; tries
++) {
921 r
= spec_to_devno_and_krbd_id(ctx
->udev
, spec
, &devno
, &buf
);
922 if (r
== -ENOENT
&& tries
< 2) {
927 std::cerr
<< "rbd: " << spec
<< ": not a mapped image or snapshot"
934 std::cerr
<< "rbd: udev enumerate missed a device, tries = " << tries
941 append_unmap_options(&buf
, options
);
942 return do_unmap(ctx
, devno
, buf
);
945 static bool dump_one_image(Formatter
*f
, TextTable
*tbl
,
946 struct udev_device
*dev
)
948 auto spec
= spec_from_dev(dev
);
949 std::string devnode
= get_devnode(dev
);
950 const char *id
= devnode
.c_str() + sizeof(DEVNODE_PREFIX
) - 1;
956 f
->open_object_section("device");
957 f
->dump_string("id", id
);
958 f
->dump_string("pool", spec
->pool_name
);
959 f
->dump_string("namespace", spec
->nspace_name
);
960 f
->dump_string("name", spec
->image_name
);
961 f
->dump_string("snap", spec
->snap_name
);
962 f
->dump_string("device", devnode
);
965 *tbl
<< id
<< spec
->pool_name
<< spec
->nspace_name
<< spec
->image_name
966 << spec
->snap_name
<< devnode
<< TextTable::endrow
;
972 static int do_dump(struct udev
*udev
, Formatter
*f
, TextTable
*tbl
)
974 udev_enumerate_uptr enm
;
975 struct udev_list_entry
*l
= NULL
;
976 bool have_output
= false;
980 enm
.reset(udev_enumerate_new(udev
));
984 r
= udev_enumerate_add_match_subsystem(enm
.get(), "rbd");
988 r
= udev_enumerate_scan_devices(enm
.get());
990 if (r
== -ENOENT
|| r
== -ENODEV
) {
991 std::cerr
<< "rbd: udev enumerate failed, retrying" << std::endl
;
997 udev_list_entry_foreach(l
, udev_enumerate_get_list_entry(enm
.get())) {
998 auto dev
= dev_from_list_entry(udev
, l
);
1000 have_output
|= dump_one_image(f
, tbl
, dev
.get());
1007 static int dump_images(struct krbd_ctx
*ctx
, Formatter
*f
)
1013 f
->open_array_section("devices");
1015 tbl
.define_column("id", TextTable::LEFT
, TextTable::LEFT
);
1016 tbl
.define_column("pool", TextTable::LEFT
, TextTable::LEFT
);
1017 tbl
.define_column("namespace", TextTable::LEFT
, TextTable::LEFT
);
1018 tbl
.define_column("image", TextTable::LEFT
, TextTable::LEFT
);
1019 tbl
.define_column("snap", TextTable::LEFT
, TextTable::LEFT
);
1020 tbl
.define_column("device", TextTable::LEFT
, TextTable::LEFT
);
1023 r
= do_dump(ctx
->udev
, f
, &tbl
);
1027 f
->flush(std::cout
);
1036 static int is_mapped_image(struct udev
*udev
, const krbd_spec
& spec
,
1039 udev_enumerate_uptr enm
;
1040 struct udev_list_entry
*l
;
1043 r
= enumerate_devices(udev
, spec
, &enm
);
1047 l
= udev_enumerate_get_list_entry(enm
.get());
1049 auto dev
= dev_from_list_entry(udev
, l
);
1053 *pname
= get_devnode(dev
.get());
1057 return 0; /* not mapped */
1060 extern "C" int krbd_create_from_context(rados_config_t cct
, uint32_t flags
,
1061 struct krbd_ctx
**pctx
)
1063 struct krbd_ctx
*ctx
= new struct krbd_ctx();
1065 ctx
->cct
= reinterpret_cast<CephContext
*>(cct
);
1066 ctx
->udev
= udev_new();
1077 extern "C" void krbd_destroy(struct krbd_ctx
*ctx
)
1082 udev_unref(ctx
->udev
);
1087 extern "C" int krbd_map(struct krbd_ctx
*ctx
,
1088 const char *pool_name
,
1089 const char *nspace_name
,
1090 const char *image_name
,
1091 const char *snap_name
,
1092 const char *options
,
1095 krbd_spec
spec(pool_name
, nspace_name
, image_name
, snap_name
);
1100 r
= map_image(ctx
, spec
, options
, &name
);
1104 devnode
= strdup(name
.c_str());
1108 *pdevnode
= devnode
;
1112 extern "C" int krbd_unmap(struct krbd_ctx
*ctx
, const char *devnode
,
1113 const char *options
)
1115 return unmap_image(ctx
, devnode
, options
);
1118 extern "C" int krbd_unmap_by_spec(struct krbd_ctx
*ctx
,
1119 const char *pool_name
,
1120 const char *nspace_name
,
1121 const char *image_name
,
1122 const char *snap_name
,
1123 const char *options
)
1125 krbd_spec
spec(pool_name
, nspace_name
, image_name
, snap_name
);
1126 return unmap_image(ctx
, spec
, options
);
1129 int krbd_showmapped(struct krbd_ctx
*ctx
, Formatter
*f
)
1131 return dump_images(ctx
, f
);
1134 extern "C" int krbd_is_mapped(struct krbd_ctx
*ctx
,
1135 const char *pool_name
,
1136 const char *nspace_name
,
1137 const char *image_name
,
1138 const char *snap_name
,
1141 krbd_spec
spec(pool_name
, nspace_name
, image_name
, snap_name
);
1146 r
= is_mapped_image(ctx
->udev
, spec
, &name
);
1147 if (r
<= 0) /* error or not mapped */
1150 devnode
= strdup(name
.c_str());
1154 *pdevnode
= devnode
;