1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/int_types.h"
16 #include <boost/regex.hpp>
18 #include "common/Preforker.h"
19 #include "common/ceph_argparse.h"
20 #include "common/config.h"
21 #include "common/debug.h"
22 #include "common/errno.h"
23 #include "global/global_init.h"
24 #include "global/signal_handler.h"
26 #include "include/rados/librados.hpp"
27 #include "include/rbd/librbd.hpp"
33 #define dout_context g_ceph_context
34 #define dout_subsys ceph_subsys_rbd
36 #define dout_prefix *_dout << "rbd-ggate: " << __func__ << ": "
39 std::cout
<< "Usage: rbd-ggate [options] map <image-or-snap-spec> Map an image to ggate device\n"
40 << " unmap <device path> Unmap ggate device\n"
41 << " list List mapped ggate devices\n"
43 << " --device <device path> Specify ggate device path\n"
44 << " --read-only Map readonly\n"
45 << " --exclusive Forbid writes by other clients\n"
47 generic_server_usage();
50 static std::string devpath
, poolname("rbd"), imgname
, snapname
;
51 static bool readonly
= false;
52 static bool exclusive
= false;
54 static std::unique_ptr
<rbd::ggate::Driver
> drv
;
56 static void handle_signal(int signum
)
58 derr
<< "*** Got signal " << sig_str(signum
) << " ***" << dendl
;
60 assert(signum
== SIGINT
|| signum
== SIGTERM
);
66 static int do_map(int argc
, const char *argv
[])
70 librados::Rados rados
;
72 librados::IoCtx io_ctx
;
75 librbd::image_info_t info
;
80 vector
<const char*> args
;
81 argv_to_vec(argc
, argv
, args
);
84 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
85 CODE_ENVIRONMENT_DAEMON
,
86 CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS
);
87 g_ceph_context
->_conf
->set_val_or_die("pid_file", "");
89 if (global_init_prefork(g_ceph_context
) >= 0) {
91 r
= forker
.prefork(err
);
93 cerr
<< err
<< std::endl
;
97 if (forker
.is_parent()) {
98 global_init_postfork_start(g_ceph_context
);
99 if (forker
.parent_wait(err
) != 0) {
106 common_init_finish(g_ceph_context
);
107 global_init_chdir(g_ceph_context
);
109 std::string devname
= (devpath
.compare(0, 5, "/dev/") == 0) ?
110 devpath
.substr(5) : devpath
;
111 std::unique_ptr
<rbd::ggate::Watcher
> watcher
;
114 r
= rados
.init_with_context(g_ceph_context
);
124 r
= rados
.ioctx_create(poolname
.c_str(), io_ctx
);
129 r
= rbd
.open(io_ctx
, image
, imgname
.c_str());
135 r
= image
.lock_acquire(RBD_LOCK_MODE_EXCLUSIVE
);
137 cerr
<< "rbd-ggate: failed to acquire exclusive lock: " << cpp_strerror(r
)
143 desc
= "RBD " + poolname
+ "/" + imgname
;
145 if (!snapname
.empty()) {
146 r
= image
.snap_set(snapname
.c_str());
151 desc
+= "@" + snapname
;
154 r
= image
.stat(info
, sizeof(info
));
159 rbd::ggate::Driver::load();
160 drv
.reset(new rbd::ggate::Driver(devname
, 512, info
.size
, readonly
, desc
));
167 watcher
.reset(new rbd::ggate::Watcher(drv
.get(), io_ctx
, image
, info
.size
));
168 r
= image
.update_watch(watcher
.get(), &handle
);
174 std::cout
<< "/dev/" << drv
->get_devname() << std::endl
;
176 if (g_conf
->daemonize
) {
178 global_init_postfork_start(g_ceph_context
);
179 global_init_postfork_finish(g_ceph_context
);
182 init_async_signal_handler();
183 register_async_signal_handler(SIGHUP
, sighup_handler
);
184 register_async_signal_handler_oneshot(SIGINT
, handle_signal
);
185 register_async_signal_handler_oneshot(SIGTERM
, handle_signal
);
187 rbd::ggate::Server(drv
.get(), image
).run();
189 unregister_async_signal_handler(SIGHUP
, sighup_handler
);
190 unregister_async_signal_handler(SIGINT
, handle_signal
);
191 unregister_async_signal_handler(SIGTERM
, handle_signal
);
192 shutdown_async_signal_handler();
194 r
= image
.update_unwatch(handle
);
202 forker
.exit(r
< 0 ? EXIT_FAILURE
: 0);
207 static int do_unmap()
209 std::string devname
= (devpath
.compare(0, 5, "/dev/") == 0) ?
210 devpath
.substr(5) : devpath
;
212 int r
= rbd::ggate::Driver::kill(devname
);
214 cerr
<< "rbd-ggate: failed to destroy " << devname
<< ": "
215 << cpp_strerror(r
) << std::endl
;
222 static int parse_imgpath(const std::string
&imgpath
)
224 boost::regex
pattern("^(?:([^/@]+)/)?([^/@]+)(?:@([^/@]+))?$");
226 if (!boost::regex_match(imgpath
, match
, pattern
)) {
227 std::cerr
<< "rbd-ggate: invalid spec '" << imgpath
<< "'" << std::endl
;
231 if (match
[1].matched
) {
237 if (match
[3].matched
) {
246 rbd::ggate::Driver::load();
248 std::list
<std::string
> devs
;
249 int r
= rbd::ggate::Driver::list(devs
);
254 for (auto &devname
: devs
) {
255 cout
<< "/dev/" << devname
<< std::endl
;
260 int main(int argc
, const char *argv
[]) {
269 vector
<const char*> args
;
271 argv_to_vec(argc
, argv
, args
);
272 md_config_t().parse_argv(args
);
274 std::vector
<const char*>::iterator i
;
276 for (i
= args
.begin(); i
!= args
.end(); ) {
277 if (ceph_argparse_flag(args
, i
, "-h", "--help", (char*)NULL
)) {
280 } else if (ceph_argparse_witharg(args
, i
, &devpath
, "--device",
282 } else if (ceph_argparse_flag(args
, i
, "--read-only", (char *)NULL
)) {
284 } else if (ceph_argparse_flag(args
, i
, "--exclusive", (char *)NULL
)) {
291 if (args
.begin() != args
.end()) {
292 if (strcmp(*args
.begin(), "map") == 0) {
294 } else if (strcmp(*args
.begin(), "unmap") == 0) {
296 } else if (strcmp(*args
.begin(), "list") == 0) {
299 cerr
<< "rbd-ggate: unknown command: " << *args
.begin() << std::endl
;
302 args
.erase(args
.begin());
306 cerr
<< "rbd-ggate: must specify command" << std::endl
;
312 if (args
.begin() == args
.end()) {
313 cerr
<< "rbd-ggate: must specify image-or-snap-spec" << std::endl
;
316 if (parse_imgpath(string(*args
.begin())) < 0)
318 args
.erase(args
.begin());
321 if (args
.begin() == args
.end()) {
322 cerr
<< "rbd-ggate: must specify ggate device path" << std::endl
;
325 devpath
= *args
.begin();
326 args
.erase(args
.begin());
332 if (args
.begin() != args
.end()) {
333 cerr
<< "rbd-ggate: unknown args: " << *args
.begin() << std::endl
;
339 if (imgname
.empty()) {
340 cerr
<< "rbd-ggate: image name was not specified" << std::endl
;
344 r
= do_map(argc
, argv
);