Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / krbd.cc
1 /*
2  * Ceph - scalable distributed file system
3  *
4  * Copyright (C) 2014 Inktank Storage, Inc.
5  *
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.
10  *
11  */
12
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <iostream>
16 #include <map>
17 #include <poll.h>
18 #include <sstream>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <string>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include "auth/KeyRing.h"
28 #include "common/errno.h"
29 #include "common/Formatter.h"
30 #include "common/module.h"
31 #include "common/run_cmd.h"
32 #include "common/safe_io.h"
33 #include "common/secret.h"
34 #include "common/TextTable.h"
35 #include "include/assert.h"
36 #include "include/stringify.h"
37 #include "include/krbd.h"
38 #include "mon/MonMap.h"
39
40 #include <blkid/blkid.h>
41 #include <libudev.h>
42
43 using namespace std;
44
45 const static int POLL_TIMEOUT=120000;
46
47 struct krbd_ctx {
48   CephContext *cct;
49   struct udev *udev;
50 };
51
52 static string get_kernel_rbd_name(const char *id)
53 {
54   return string("/dev/rbd") + id;
55 }
56
57 static int sysfs_write_rbd(const char *which, const string& buf)
58 {
59   const string s = string("/sys/bus/rbd/") + which;
60   const string t = s + "_single_major";
61   int fd;
62   int r;
63
64   /*
65    * 'add' and 'add_single_major' interfaces are identical, but if rbd
66    * kernel module is new enough and is configured to use single-major
67    * scheme, 'add' is disabled in order to prevent old userspace from
68    * doing weird things at unmap time.
69    *
70    * Same goes for 'remove' vs 'remove_single_major'.
71    */
72   fd = open(t.c_str(), O_WRONLY);
73   if (fd < 0) {
74     if (errno == ENOENT) {
75       fd = open(s.c_str(), O_WRONLY);
76       if (fd < 0)
77         return -errno;
78     } else {
79       return -errno;
80     }
81   }
82
83   r = safe_write(fd, buf.c_str(), buf.size());
84
85   close(fd);
86   return r;
87 }
88
89 static int sysfs_write_rbd_add(const string& buf)
90 {
91   return sysfs_write_rbd("add", buf);
92 }
93
94 static int sysfs_write_rbd_remove(const string& buf)
95 {
96   return sysfs_write_rbd("remove", buf);
97 }
98
99 static int have_minor_attr(void)
100 {
101   /*
102    * 'minor' attribute was added as part of single_major merge, which
103    * exposed the 'single_major' parameter.  'minor' is always present,
104    * regardless of whether single-major scheme is turned on or not.
105    *
106    * (Something like ver >= KERNEL_VERSION(3, 14, 0) is a no-go because
107    * this has to work with rbd.ko backported to various kernels.)
108    */
109   return access("/sys/module/rbd/parameters/single_major", F_OK) == 0;
110 }
111
112 static int build_map_buf(CephContext *cct, const char *pool, const char *image,
113                          const char *snap, const char *options, string *pbuf)
114 {
115   ostringstream oss;
116   int r;
117
118   MonMap monmap;
119   r = monmap.build_initial(cct, cerr);
120   if (r < 0)
121     return r;
122
123   list<entity_addr_t> mon_addr;
124   monmap.list_addrs(mon_addr);
125
126   for (const auto &p : mon_addr) {
127     if (oss.tellp() > 0) {
128       oss << ",";
129     }
130     oss << p.get_sockaddr();
131   }
132
133   oss << " name=" << cct->_conf->name.get_id();
134
135   KeyRing keyring;
136   if (cct->_conf->auth_client_required != "none") {
137     r = keyring.from_ceph_context(cct);
138     if (r == -ENOENT && !(cct->_conf->keyfile.length() ||
139                           cct->_conf->key.length()))
140       r = 0;
141     if (r < 0) {
142       cerr << "rbd: failed to get secret" << std::endl;
143       return r;
144     }
145   }
146
147   CryptoKey secret;
148   string key_name = string("client.") + cct->_conf->name.get_id();
149   if (keyring.get_secret(cct->_conf->name, secret)) {
150     string secret_str;
151     secret.encode_base64(secret_str);
152
153     r = set_kernel_secret(secret_str.c_str(), key_name.c_str());
154     if (r >= 0) {
155       if (r == 0)
156         cerr << "rbd: warning: secret has length 0" << std::endl;
157       oss << ",key=" << key_name;
158     } else if (r == -ENODEV || r == -ENOSYS) {
159       // running against older kernel; fall back to secret= in options
160       oss << ",secret=" << secret_str;
161     } else {
162       cerr << "rbd: failed to add secret '" << key_name << "' to kernel"
163            << std::endl;
164       return r;
165     }
166   } else if (is_kernel_secret(key_name.c_str())) {
167     oss << ",key=" << key_name;
168   }
169
170   if (strcmp(options, "") != 0)
171     oss << "," << options;
172
173   oss << " " << pool << " " << image << " " << snap;
174
175   *pbuf = oss.str();
176   return 0;
177 }
178
179 static int wait_for_udev_add(struct udev_monitor *mon, const char *pool,
180                              const char *image, const char *snap,
181                              string *pname)
182 {
183   struct udev_device *bus_dev = NULL;
184
185   /*
186    * Catch /sys/devices/rbd/<id>/ and wait for the corresponding
187    * block device to show up.  This is necessary because rbd devices
188    * and block devices aren't linked together in our sysfs layout.
189    */
190   for (;;) {
191     struct pollfd fds[1];
192     struct udev_device *dev;
193
194     fds[0].fd = udev_monitor_get_fd(mon);
195     fds[0].events = POLLIN;
196     if (poll(fds, 1, POLL_TIMEOUT) < 0)
197       return -errno;
198
199     dev = udev_monitor_receive_device(mon);
200     if (!dev)
201       continue;
202
203     if (strcmp(udev_device_get_action(dev), "add") != 0)
204       goto next;
205
206     if (!bus_dev) {
207       if (strcmp(udev_device_get_subsystem(dev), "rbd") == 0) {
208         const char *this_pool = udev_device_get_sysattr_value(dev, "pool");
209         const char *this_image = udev_device_get_sysattr_value(dev, "name");
210         const char *this_snap = udev_device_get_sysattr_value(dev,
211                                                               "current_snap");
212
213         if (this_pool && strcmp(this_pool, pool) == 0 &&
214             this_image && strcmp(this_image, image) == 0 &&
215             this_snap && strcmp(this_snap, snap) == 0) {
216           bus_dev = dev;
217           continue;
218         }
219       }
220     } else {
221       if (strcmp(udev_device_get_subsystem(dev), "block") == 0) {
222         const char *major = udev_device_get_sysattr_value(bus_dev, "major");
223         const char *minor = udev_device_get_sysattr_value(bus_dev, "minor");
224         const char *this_major = udev_device_get_property_value(dev, "MAJOR");
225         const char *this_minor = udev_device_get_property_value(dev, "MINOR");
226
227         assert(!minor ^ have_minor_attr());
228
229         if (strcmp(this_major, major) == 0 &&
230             (!minor || strcmp(this_minor, minor) == 0)) {
231           string name = get_kernel_rbd_name(udev_device_get_sysname(bus_dev));
232
233           assert(strcmp(udev_device_get_devnode(dev), name.c_str()) == 0);
234           *pname = name;
235
236           udev_device_unref(dev);
237           udev_device_unref(bus_dev);
238           break;
239         }
240       }
241     }
242
243   next:
244     udev_device_unref(dev);
245   }
246
247   return 0;
248 }
249
250 static int do_map(struct udev *udev, const char *pool, const char *image,
251                   const char *snap, const string& buf, string *pname)
252 {
253   struct udev_monitor *mon;
254   int r;
255
256   mon = udev_monitor_new_from_netlink(udev, "udev");
257   if (!mon)
258     return -ENOMEM;
259
260   r = udev_monitor_filter_add_match_subsystem_devtype(mon, "rbd", NULL);
261   if (r < 0)
262     goto out_mon;
263
264   r = udev_monitor_filter_add_match_subsystem_devtype(mon, "block", "disk");
265   if (r < 0)
266     goto out_mon;
267
268   r = udev_monitor_enable_receiving(mon);
269   if (r < 0)
270     goto out_mon;
271
272   r = sysfs_write_rbd_add(buf);
273   if (r < 0) {
274     cerr << "rbd: sysfs write failed" << std::endl;
275     goto out_mon;
276   }
277
278   r = wait_for_udev_add(mon, pool, image, snap, pname);
279   if (r < 0) {
280     cerr << "rbd: wait failed" << std::endl;
281     goto out_mon;
282   }
283
284 out_mon:
285   udev_monitor_unref(mon);
286   return r;
287 }
288
289 static int map_image(struct krbd_ctx *ctx, const char *pool, const char *image,
290                      const char *snap, const char *options, string *pname)
291 {
292   string buf;
293   int r;
294
295   if (strcmp(snap, "") == 0)
296     snap = "-";
297
298   r = build_map_buf(ctx->cct, pool, image, snap, options, &buf);
299   if (r < 0)
300     return r;
301
302   /*
303    * Modprobe rbd kernel module.  If it supports single-major device
304    * number allocation scheme, make sure it's turned on.
305    */
306   if (access("/sys/bus/rbd", F_OK) != 0) {
307     const char *module_options = NULL;
308     if (module_has_param("rbd", "single_major"))
309       module_options = "single_major=Y";
310
311     r = module_load("rbd", module_options);
312     if (r) {
313       cerr << "rbd: failed to load rbd kernel module (" << r << ")"
314            << std::endl;
315       /*
316        * Ignore the error: modprobe failing doesn't necessarily prevent
317        * from working.
318        */
319     }
320   }
321
322   return do_map(ctx->udev, pool, image, snap, buf, pname);
323 }
324
325 static int devno_to_krbd_id(struct udev *udev, dev_t devno, string *pid)
326 {
327   struct udev_enumerate *enm;
328   struct udev_list_entry *l;
329   struct udev_device *dev;
330   int r;
331
332   enm = udev_enumerate_new(udev);
333   if (!enm)
334     return -ENOMEM;
335
336   r = udev_enumerate_add_match_subsystem(enm, "rbd");
337   if (r < 0)
338     goto out_enm;
339
340   r = udev_enumerate_add_match_sysattr(enm, "major",
341                                        stringify(major(devno)).c_str());
342   if (r < 0)
343     goto out_enm;
344
345   if (have_minor_attr()) {
346     r = udev_enumerate_add_match_sysattr(enm, "minor",
347                                          stringify(minor(devno)).c_str());
348     if (r < 0)
349       goto out_enm;
350   }
351
352   r = udev_enumerate_scan_devices(enm);
353   if (r < 0)
354     goto out_enm;
355
356   l = udev_enumerate_get_list_entry(enm);
357   if (!l) {
358     r = -ENOENT;
359     goto out_enm;
360   }
361
362   /* make sure there is only one match */
363   assert(!udev_list_entry_get_next(l));
364
365   dev = udev_device_new_from_syspath(udev, udev_list_entry_get_name(l));
366   if (!dev) {
367     r = -ENOMEM;
368     goto out_enm;
369   }
370
371   *pid = udev_device_get_sysname(dev);
372
373   udev_device_unref(dev);
374 out_enm:
375   udev_enumerate_unref(enm);
376   return r;
377 }
378
379 static int spec_to_devno_and_krbd_id(struct udev *udev, const char *pool,
380                                      const char *image, const char *snap,
381                                      dev_t *pdevno, string *pid)
382 {
383   struct udev_enumerate *enm;
384   struct udev_list_entry *l;
385   struct udev_device *dev;
386   unsigned int maj, min = 0;
387   string err;
388   int r;
389
390   enm = udev_enumerate_new(udev);
391   if (!enm)
392     return -ENOMEM;
393
394   r = udev_enumerate_add_match_subsystem(enm, "rbd");
395   if (r < 0)
396     goto out_enm;
397
398   r = udev_enumerate_add_match_sysattr(enm, "pool", pool);
399   if (r < 0)
400     goto out_enm;
401
402   r = udev_enumerate_add_match_sysattr(enm, "name", image);
403   if (r < 0)
404     goto out_enm;
405
406   r = udev_enumerate_add_match_sysattr(enm, "current_snap", snap);
407   if (r < 0)
408     goto out_enm;
409
410   r = udev_enumerate_scan_devices(enm);
411   if (r < 0)
412     goto out_enm;
413
414   l = udev_enumerate_get_list_entry(enm);
415   if (!l) {
416     r = -ENOENT;
417     goto out_enm;
418   }
419
420   dev = udev_device_new_from_syspath(udev, udev_list_entry_get_name(l));
421   if (!dev) {
422     r = -ENOMEM;
423     goto out_enm;
424   }
425
426   maj = strict_strtoll(udev_device_get_sysattr_value(dev, "major"), 10, &err);
427   if (!err.empty()) {
428     cerr << "rbd: couldn't parse major: " << err << std::endl;
429     r = -EINVAL;
430     goto out_dev;
431   }
432   if (have_minor_attr()) {
433     min = strict_strtoll(udev_device_get_sysattr_value(dev, "minor"), 10, &err);
434     if (!err.empty()) {
435       cerr << "rbd: couldn't parse minor: " << err << std::endl;
436       r = -EINVAL;
437       goto out_dev;
438     }
439   }
440
441   /*
442    * If an image is mapped more than once don't bother trying to unmap
443    * all devices - let users run unmap the same number of times they
444    * ran map.
445    */
446   if (udev_list_entry_get_next(l))
447     cerr << "rbd: " << pool << "/" << image << "@" << snap
448          << ": mapped more than once, unmapping "
449          << get_kernel_rbd_name(udev_device_get_sysname(dev))
450          << " only" << std::endl;
451
452   *pdevno = makedev(maj, min);
453   *pid = udev_device_get_sysname(dev);
454
455 out_dev:
456   udev_device_unref(dev);
457 out_enm:
458   udev_enumerate_unref(enm);
459   return r;
460 }
461
462 static string build_unmap_buf(const string& id, const char *options)
463 {
464   string buf(id);
465   if (strcmp(options, "") != 0) {
466     buf += " ";
467     buf += options;
468   }
469   return buf;
470 }
471
472 static int wait_for_udev_remove(struct udev_monitor *mon, dev_t devno)
473 {
474   for (;;) {
475     struct pollfd fds[1];
476     struct udev_device *dev;
477
478     fds[0].fd = udev_monitor_get_fd(mon);
479     fds[0].events = POLLIN;
480     if (poll(fds, 1, POLL_TIMEOUT) < 0)
481       return -errno;
482
483     dev = udev_monitor_receive_device(mon);
484     if (!dev)
485       continue;
486
487     if (strcmp(udev_device_get_action(dev), "remove") == 0 &&
488         udev_device_get_devnum(dev) == devno) {
489       udev_device_unref(dev);
490       break;
491     }
492
493     udev_device_unref(dev);
494   }
495
496   return 0;
497 }
498
499 static int do_unmap(struct udev *udev, dev_t devno, const string& buf)
500 {
501   struct udev_monitor *mon;
502   int r;
503
504   mon = udev_monitor_new_from_netlink(udev, "udev");
505   if (!mon)
506     return -ENOMEM;
507
508   r = udev_monitor_filter_add_match_subsystem_devtype(mon, "block", "disk");
509   if (r < 0)
510     goto out_mon;
511
512   r = udev_monitor_enable_receiving(mon);
513   if (r < 0)
514     goto out_mon;
515
516   /*
517    * On final device close(), kernel sends a block change event, in
518    * response to which udev apparently runs blkid on the device.  This
519    * makes unmap fail with EBUSY, if issued right after final close().
520    * Try to circumvent this with a retry before turning to udev.
521    */
522   for (int tries = 0; ; tries++) {
523     r = sysfs_write_rbd_remove(buf);
524     if (r >= 0) {
525       break;
526     } else if (r == -EBUSY && tries < 2) {
527       if (!tries) {
528         usleep(250 * 1000);
529       } else {
530         /*
531          * libudev does not provide the "wait until the queue is empty"
532          * API or the sufficient amount of primitives to build it from.
533          */
534         string err = run_cmd("udevadm", "settle", "--timeout", "10", NULL);
535         if (!err.empty())
536           cerr << "rbd: " << err << std::endl;
537       }
538     } else {
539       cerr << "rbd: sysfs write failed" << std::endl;
540       goto out_mon;
541     }
542   }
543
544   r = wait_for_udev_remove(mon, devno);
545   if (r < 0) {
546     cerr << "rbd: wait failed" << std::endl;
547     goto out_mon;
548   }
549
550 out_mon:
551   udev_monitor_unref(mon);
552   return r;
553 }
554
555 static int unmap_image(struct krbd_ctx *ctx, const char *devnode,
556                        const char *options)
557 {
558   struct stat sb;
559   dev_t wholedevno = 0;
560   string id;
561   int r;
562
563   if (stat(devnode, &sb) < 0 || !S_ISBLK(sb.st_mode)) {
564     cerr << "rbd: '" << devnode << "' is not a block device" << std::endl;
565     return -EINVAL;
566   }
567
568   r = blkid_devno_to_wholedisk(sb.st_rdev, NULL, 0, &wholedevno);
569   if (r < 0) {
570     cerr << "rbd: couldn't compute wholedevno: " << cpp_strerror(r)
571          << std::endl;
572     /*
573      * Ignore the error: we are given whole disks most of the time, and
574      * if it turns out this is a partition we will fail later anyway.
575      */
576     wholedevno = sb.st_rdev;
577   }
578
579   r = devno_to_krbd_id(ctx->udev, wholedevno, &id);
580   if (r < 0) {
581     if (r == -ENOENT) {
582       cerr << "rbd: '" << devnode << "' is not an rbd device" << std::endl;
583       r = -EINVAL;
584     }
585     return r;
586   }
587
588   return do_unmap(ctx->udev, wholedevno, build_unmap_buf(id, options));
589 }
590
591 static int unmap_image(struct krbd_ctx *ctx, const char *pool,
592                        const char *image, const char *snap,
593                        const char *options)
594 {
595   dev_t devno = 0;
596   string id;
597   int r;
598
599   if (!snap)
600     snap = "-";
601
602   r = spec_to_devno_and_krbd_id(ctx->udev, pool, image, snap, &devno, &id);
603   if (r < 0) {
604     if (r == -ENOENT) {
605       cerr << "rbd: " << pool << "/" << image << "@" << snap
606            << ": not a mapped image or snapshot" << std::endl;
607       r = -EINVAL;
608     }
609     return r;
610   }
611
612   return do_unmap(ctx->udev, devno, build_unmap_buf(id, options));
613 }
614
615 static bool dump_one_image(Formatter *f, TextTable *tbl,
616                            struct udev_device *dev)
617 {
618   const char *id = udev_device_get_sysname(dev);
619   const char *pool = udev_device_get_sysattr_value(dev, "pool");
620   const char *image = udev_device_get_sysattr_value(dev, "name");
621   const char *snap = udev_device_get_sysattr_value(dev, "current_snap");
622   string kname = get_kernel_rbd_name(id);
623
624   if (!pool || !image || !snap)
625     return false;
626
627   if (f) {
628     f->open_object_section(id);
629     f->dump_string("pool", pool);
630     f->dump_string("name", image);
631     f->dump_string("snap", snap);
632     f->dump_string("device", kname);
633     f->close_section();
634   } else {
635     *tbl << id << pool << image << snap << kname << TextTable::endrow;
636   }
637
638   return true;
639 }
640
641 static int do_dump(struct udev *udev, Formatter *f, TextTable *tbl)
642 {
643   struct udev_enumerate *enm;
644   struct udev_list_entry *l;
645   bool have_output = false;
646   int r;
647
648   enm = udev_enumerate_new(udev);
649   if (!enm)
650     return -ENOMEM;
651
652   r = udev_enumerate_add_match_subsystem(enm, "rbd");
653   if (r < 0)
654     goto out_enm;
655
656   r = udev_enumerate_scan_devices(enm);
657   if (r < 0)
658     goto out_enm;
659
660   udev_list_entry_foreach(l, udev_enumerate_get_list_entry(enm)) {
661     struct udev_device *dev;
662
663     dev = udev_device_new_from_syspath(udev, udev_list_entry_get_name(l));
664     if (dev) {
665       have_output |= dump_one_image(f, tbl, dev);
666       udev_device_unref(dev);
667     }
668   }
669
670   r = have_output;
671 out_enm:
672   udev_enumerate_unref(enm);
673   return r;
674 }
675
676 int dump_images(struct krbd_ctx *ctx, Formatter *f)
677 {
678   TextTable tbl;
679   int r;
680
681   if (f) {
682     f->open_object_section("devices");
683   } else {
684     tbl.define_column("id", TextTable::LEFT, TextTable::LEFT);
685     tbl.define_column("pool", TextTable::LEFT, TextTable::LEFT);
686     tbl.define_column("image", TextTable::LEFT, TextTable::LEFT);
687     tbl.define_column("snap", TextTable::LEFT, TextTable::LEFT);
688     tbl.define_column("device", TextTable::LEFT, TextTable::LEFT);
689   }
690
691   r = do_dump(ctx->udev, f, &tbl);
692
693   if (f) {
694     f->close_section();
695     f->flush(cout);
696   } else {
697     if (r > 0)
698       cout << tbl;
699   }
700
701   return r;
702 }
703
704 extern "C" int krbd_create_from_context(rados_config_t cct,
705                                         struct krbd_ctx **pctx)
706 {
707   struct krbd_ctx *ctx = new struct krbd_ctx();
708
709   ctx->cct = reinterpret_cast<CephContext *>(cct);
710   ctx->udev = udev_new();
711   if (!ctx->udev) {
712     delete ctx;
713     return -ENOMEM;
714   }
715
716   *pctx = ctx;
717   return 0;
718 }
719
720 extern "C" void krbd_destroy(struct krbd_ctx *ctx)
721 {
722   if (!ctx)
723     return;
724
725   udev_unref(ctx->udev);
726
727   delete ctx;
728 }
729
730 extern "C" int krbd_map(struct krbd_ctx *ctx, const char *pool,
731                         const char *image, const char *snap,
732                         const char *options, char **pdevnode)
733 {
734   string name;
735   char *devnode;
736   int r;
737
738   r = map_image(ctx, pool, image, snap, options, &name);
739   if (r < 0)
740     return r;
741
742   devnode = strdup(name.c_str());
743   if (!devnode)
744     return -ENOMEM;
745
746   *pdevnode = devnode;
747   return r;
748 }
749
750 extern "C" int krbd_unmap(struct krbd_ctx *ctx, const char *devnode,
751                           const char *options)
752 {
753   return unmap_image(ctx, devnode, options);
754 }
755
756 extern "C" int krbd_unmap_by_spec(struct krbd_ctx *ctx, const char *pool,
757                                   const char *image, const char *snap,
758                                   const char *options)
759 {
760   return unmap_image(ctx, pool, image, snap, options);
761 }
762
763 int krbd_showmapped(struct krbd_ctx *ctx, Formatter *f)
764 {
765   return dump_images(ctx, f);
766 }