]> git.proxmox.com Git - ceph.git/blob - ceph/src/rbd_fuse/rbd-fuse.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rbd_fuse / rbd-fuse.cc
1 /*
2 * rbd-fuse
3 */
4 #define FUSE_USE_VERSION 30
5
6 #include "include/int_types.h"
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stddef.h>
11 #include <dirent.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <fuse.h>
15 #include <pthread.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <getopt.h>
20 #include <assert.h>
21 #include <string>
22 #include <mutex>
23 #include <limits.h>
24
25 #if defined(__FreeBSD__)
26 #include <sys/param.h>
27 #endif
28
29 #include "include/compat.h"
30 #include "include/rbd/librbd.h"
31 #include "include/ceph_assert.h"
32
33 #include "common/ceph_argparse.h"
34 #include "common/ceph_context.h"
35
36 #include "global/global_init.h"
37 #include "global/global_context.h"
38
39 static int gotrados = 0;
40 char *pool_name;
41 char *nspace_name;
42 char *mount_image_name;
43 rados_t cluster;
44 rados_ioctx_t ioctx;
45
46 std::mutex readdir_lock;
47
48 struct rbd_stat {
49 u_char valid;
50 rbd_image_info_t rbd_info;
51 };
52
53 struct rbd_options {
54 char *pool_name;
55 char *nspace_name;
56 char *image_name;
57 };
58
59 struct rbd_image {
60 char *image_name;
61 struct rbd_image *next;
62 };
63 struct rbd_image_data {
64 struct rbd_image *images;
65 rbd_image_spec_t *image_specs;
66 size_t image_spec_count;
67 };
68 struct rbd_image_data rbd_image_data;
69
70 struct rbd_openimage {
71 char *image_name;
72 rbd_image_t image;
73 struct rbd_stat rbd_stat;
74 };
75 #define MAX_RBD_IMAGES 128
76 struct rbd_openimage opentbl[MAX_RBD_IMAGES];
77
78 struct rbd_options rbd_options = {(char*) "rbd", (char*) "", NULL};
79
80 #define rbdsize(fd) opentbl[fd].rbd_stat.rbd_info.size
81 #define rbdblksize(fd) opentbl[fd].rbd_stat.rbd_info.obj_size
82 #define rbdblkcnt(fd) opentbl[fd].rbd_stat.rbd_info.num_objs
83
84 uint64_t imagesize = 1024ULL * 1024 * 1024;
85 uint64_t imageorder = 22ULL;
86 uint64_t imagefeatures = 1ULL;
87
88 // Minimize calls to rbd_list: marks bracketing of opendir/<ops>/releasedir
89 int in_opendir;
90
91 /* prototypes */
92 int connect_to_cluster(rados_t *pcluster);
93 void enumerate_images(struct rbd_image_data *data);
94 int open_rbd_image(const char *image_name);
95 int find_openrbd(const char *path);
96
97 void simple_err(const char *msg, int err);
98
99 void
100 enumerate_images(struct rbd_image_data *data)
101 {
102 struct rbd_image **head = &data->images;
103 struct rbd_image *im, *next;
104 int ret;
105
106 if (*head != NULL) {
107 for (im = *head; im != NULL;) {
108 next = im->next;
109 free(im);
110 im = next;
111 }
112 *head = NULL;
113 rbd_image_spec_list_cleanup(data->image_specs,
114 data->image_spec_count);
115 free(data->image_specs);
116 data->image_specs = NULL;
117 data->image_spec_count = 0;
118 }
119
120 while (true) {
121 ret = rbd_list2(ioctx, data->image_specs,
122 &data->image_spec_count);
123 if (ret == -ERANGE) {
124 data->image_specs = static_cast<rbd_image_spec_t *>(
125 realloc(data->image_specs,
126 sizeof(rbd_image_spec_t) * data->image_spec_count));
127 } else if (ret < 0) {
128 simple_err("Failed to list images", ret);
129 } else {
130 break;
131 }
132 }
133
134 if (*nspace_name != '\0') {
135 fprintf(stderr, "pool/namespace %s/%s: ", pool_name, nspace_name);
136 } else {
137 fprintf(stderr, "pool %s: ", pool_name);
138 }
139 for (size_t idx = 0; idx < data->image_spec_count; ++idx) {
140 if ((mount_image_name == NULL) ||
141 ((strlen(mount_image_name) > 0) &&
142 (strcmp(data->image_specs[idx].name, mount_image_name) == 0))) {
143 fprintf(stderr, "%s, ", data->image_specs[idx].name);
144 im = static_cast<rbd_image*>(malloc(sizeof(*im)));
145 im->image_name = data->image_specs[idx].name;
146 im->next = *head;
147 *head = im;
148 }
149 }
150 fprintf(stderr, "\n");
151 }
152
153 int
154 find_openrbd(const char *path)
155 {
156 int i;
157
158 /* find in opentbl[] entry if already open */
159 for (i = 0; i < MAX_RBD_IMAGES; i++) {
160 if ((opentbl[i].image_name != NULL) &&
161 (strcmp(opentbl[i].image_name, path) == 0)) {
162 return i;
163 }
164 }
165 return -1;
166 }
167
168 int
169 open_rbd_image(const char *image_name)
170 {
171 struct rbd_image *im;
172 struct rbd_openimage *rbd = NULL;
173 int fd;
174
175 if (image_name == (char *)NULL)
176 return -1;
177
178 // relies on caller to keep rbd_image_data up to date
179 for (im = rbd_image_data.images; im != NULL; im = im->next) {
180 if (strcmp(im->image_name, image_name) == 0) {
181 break;
182 }
183 }
184 if (im == NULL)
185 return -1;
186
187 /* find in opentbl[] entry if already open */
188 if ((fd = find_openrbd(image_name)) != -1) {
189 rbd = &opentbl[fd];
190 } else {
191 int i;
192 // allocate an opentbl[] and open the image
193 for (i = 0; i < MAX_RBD_IMAGES; i++) {
194 if (opentbl[i].image == NULL) {
195 fd = i;
196 rbd = &opentbl[fd];
197 rbd->image_name = strdup(image_name);
198 break;
199 }
200 }
201 if (i == MAX_RBD_IMAGES || !rbd)
202 return -1;
203 int ret = rbd_open(ioctx, rbd->image_name, &(rbd->image), NULL);
204 if (ret < 0) {
205 simple_err("open_rbd_image: can't open: ", ret);
206 return ret;
207 }
208 }
209 rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info),
210 sizeof(rbd_image_info_t));
211 rbd->rbd_stat.valid = 1;
212 return fd;
213 }
214
215 static void
216 iter_images(void *cookie,
217 void (*iter)(void *cookie, const char *image))
218 {
219 struct rbd_image *im;
220
221 readdir_lock.lock();
222
223 for (im = rbd_image_data.images; im != NULL; im = im->next)
224 iter(cookie, im->image_name);
225 readdir_lock.unlock();
226 }
227
228 static void count_images_cb(void *cookie, const char *image)
229 {
230 (*((unsigned int *)cookie))++;
231 }
232
233 static int count_images(void)
234 {
235 unsigned int count = 0;
236
237 readdir_lock.lock();
238 enumerate_images(&rbd_image_data);
239 readdir_lock.unlock();
240
241 iter_images(&count, count_images_cb);
242 return count;
243 }
244
245 extern "C" {
246
247 static int rbdfs_getattr(const char *path, struct stat *stbuf)
248 {
249 int fd;
250 time_t now;
251
252 if (!gotrados)
253 return -ENXIO;
254
255 if (path[0] == 0)
256 return -ENOENT;
257
258 memset(stbuf, 0, sizeof(struct stat));
259
260 if (strcmp(path, "/") == 0) {
261
262 now = time(NULL);
263 stbuf->st_mode = S_IFDIR + 0755;
264 stbuf->st_nlink = 2+count_images();
265 stbuf->st_uid = getuid();
266 stbuf->st_gid = getgid();
267 stbuf->st_size = 1024;
268 stbuf->st_blksize = 1024;
269 stbuf->st_blocks = 1;
270 stbuf->st_atime = now;
271 stbuf->st_mtime = now;
272 stbuf->st_ctime = now;
273
274 return 0;
275 }
276
277 if (!in_opendir) {
278 readdir_lock.lock();
279 enumerate_images(&rbd_image_data);
280 readdir_lock.unlock();
281 }
282 fd = open_rbd_image(path + 1);
283 if (fd < 0)
284 return -ENOENT;
285
286 now = time(NULL);
287 stbuf->st_mode = S_IFREG | 0666;
288 stbuf->st_nlink = 1;
289 stbuf->st_uid = getuid();
290 stbuf->st_gid = getgid();
291 stbuf->st_size = rbdsize(fd);
292 stbuf->st_blksize = rbdblksize(fd);
293 stbuf->st_blocks = rbdblkcnt(fd);
294 stbuf->st_atime = now;
295 stbuf->st_mtime = now;
296 stbuf->st_ctime = now;
297
298 return 0;
299 }
300
301
302 static int rbdfs_open(const char *path, struct fuse_file_info *fi)
303 {
304 int fd;
305
306 if (!gotrados)
307 return -ENXIO;
308
309 if (path[0] == 0)
310 return -ENOENT;
311
312 readdir_lock.lock();
313 enumerate_images(&rbd_image_data);
314 readdir_lock.unlock();
315 fd = open_rbd_image(path + 1);
316 if (fd < 0)
317 return -ENOENT;
318
319 fi->fh = fd;
320 return 0;
321 }
322
323 static int rbdfs_read(const char *path, char *buf, size_t size,
324 off_t offset, struct fuse_file_info *fi)
325 {
326 size_t numread;
327 struct rbd_openimage *rbd;
328
329 if (!gotrados)
330 return -ENXIO;
331
332 rbd = &opentbl[fi->fh];
333 numread = 0;
334 while (size > 0) {
335 ssize_t ret;
336
337 ret = rbd_read(rbd->image, offset, size, buf);
338
339 if (ret <= 0)
340 break;
341 buf += ret;
342 size -= ret;
343 offset += ret;
344 numread += ret;
345 }
346
347 return numread;
348 }
349
350 static int rbdfs_write(const char *path, const char *buf, size_t size,
351 off_t offset, struct fuse_file_info *fi)
352 {
353 size_t numwritten;
354 struct rbd_openimage *rbd;
355
356 if (!gotrados)
357 return -ENXIO;
358
359 rbd = &opentbl[fi->fh];
360 numwritten = 0;
361 while (size > 0) {
362 ssize_t ret;
363
364 if ((size_t)(offset + size) > rbdsize(fi->fh)) {
365 int r;
366 fprintf(stderr, "rbdfs_write resizing %s to 0x%" PRIxMAX "\n",
367 path, offset+size);
368 r = rbd_resize(rbd->image, offset+size);
369 if (r < 0)
370 return r;
371
372 r = rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info),
373 sizeof(rbd_image_info_t));
374 if (r < 0)
375 return r;
376 }
377 ret = rbd_write(rbd->image, offset, size, buf);
378
379 if (ret < 0)
380 break;
381 buf += ret;
382 size -= ret;
383 offset += ret;
384 numwritten += ret;
385 }
386
387 return numwritten;
388 }
389
390 static void rbdfs_statfs_image_cb(void *num, const char *image)
391 {
392 int fd;
393
394 ((uint64_t *)num)[0]++;
395
396 fd = open_rbd_image(image);
397 if (fd >= 0)
398 ((uint64_t *)num)[1] += rbdsize(fd);
399 }
400
401 static int rbdfs_statfs(const char *path, struct statvfs *buf)
402 {
403 uint64_t num[2];
404
405 if (!gotrados)
406 return -ENXIO;
407
408 num[0] = 1;
409 num[1] = 0;
410 readdir_lock.lock();
411 enumerate_images(&rbd_image_data);
412 readdir_lock.unlock();
413 iter_images(num, rbdfs_statfs_image_cb);
414
415 #define RBDFS_BSIZE 4096
416 buf->f_bsize = RBDFS_BSIZE;
417 buf->f_frsize = RBDFS_BSIZE;
418 buf->f_blocks = num[1] / RBDFS_BSIZE;
419 buf->f_bfree = 0;
420 buf->f_bavail = 0;
421 buf->f_files = num[0];
422 buf->f_ffree = 0;
423 buf->f_favail = 0;
424 buf->f_fsid = 0;
425 buf->f_flag = 0;
426 buf->f_namemax = PATH_MAX;
427
428 return 0;
429 }
430
431 static int rbdfs_fsync(const char *path, int datasync,
432 struct fuse_file_info *fi)
433 {
434 if (!gotrados)
435 return -ENXIO;
436 rbd_flush(opentbl[fi->fh].image);
437 return 0;
438 }
439
440 static int rbdfs_opendir(const char *path, struct fuse_file_info *fi)
441 {
442 // only one directory, so global "in_opendir" flag should be fine
443 readdir_lock.lock();
444 in_opendir++;
445 enumerate_images(&rbd_image_data);
446 readdir_lock.unlock();
447 return 0;
448 }
449
450 struct rbdfs_readdir_info {
451 void *buf;
452 fuse_fill_dir_t filler;
453 };
454
455 static void rbdfs_readdir_cb(void *_info, const char *name)
456 {
457 struct rbdfs_readdir_info *info = (struct rbdfs_readdir_info*) _info;
458
459 info->filler(info->buf, name, NULL, 0);
460 }
461
462 static int rbdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
463 off_t offset, struct fuse_file_info *fi)
464 {
465 struct rbdfs_readdir_info info = { buf, filler };
466
467 if (!gotrados)
468 return -ENXIO;
469 if (!in_opendir)
470 fprintf(stderr, "in readdir, but not inside opendir?\n");
471
472 if (strcmp(path, "/") != 0)
473 return -ENOENT;
474
475 filler(buf, ".", NULL, 0);
476 filler(buf, "..", NULL, 0);
477 iter_images(&info, rbdfs_readdir_cb);
478
479 return 0;
480 }
481 static int rbdfs_releasedir(const char *path, struct fuse_file_info *fi)
482 {
483 // see opendir comments
484 readdir_lock.lock();
485 in_opendir--;
486 readdir_lock.unlock();
487 return 0;
488 }
489
490 void *
491 rbdfs_init(struct fuse_conn_info *conn)
492 {
493 int ret;
494
495 // init cannot fail, so if we fail here, gotrados remains at 0,
496 // causing other operations to fail immediately with ENXIO
497
498 ret = connect_to_cluster(&cluster);
499 if (ret < 0)
500 exit(90);
501
502 pool_name = rbd_options.pool_name;
503 nspace_name = rbd_options.nspace_name;
504 mount_image_name = rbd_options.image_name;
505 ret = rados_ioctx_create(cluster, pool_name, &ioctx);
506 if (ret < 0)
507 exit(91);
508 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
509 conn->want |= FUSE_CAP_BIG_WRITES;
510 #endif
511 rados_ioctx_set_namespace(ioctx, nspace_name);
512 gotrados = 1;
513
514 // init's return value shows up in fuse_context.private_data,
515 // also to void (*destroy)(void *); useful?
516 return NULL;
517 }
518
519 void
520 rbdfs_destroy(void *unused)
521 {
522 if (!gotrados)
523 return;
524 for (int i = 0; i < MAX_RBD_IMAGES; ++i) {
525 if (opentbl[i].image) {
526 rbd_close(opentbl[i].image);
527 opentbl[i].image = NULL;
528 }
529 }
530 rados_ioctx_destroy(ioctx);
531 rados_shutdown(cluster);
532 }
533
534 int
535 rbdfs_checkname(const char *checkname)
536 {
537 const char *extra[] = {"@", "/"};
538 std::string strCheckName(checkname);
539
540 if (strCheckName.empty())
541 return -EINVAL;
542
543 unsigned int sz = sizeof(extra) / sizeof(const char*);
544 for (unsigned int i = 0; i < sz; i++)
545 {
546 std::string ex(extra[i]);
547 if (std::string::npos != strCheckName.find(ex))
548 return -EINVAL;
549 }
550
551 return 0;
552 }
553
554 // return -errno on error. fi->fh is not set until open time
555
556 int
557 rbdfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
558 {
559 int r;
560 int order = imageorder;
561
562 r = rbdfs_checkname(path+1);
563 if (r != 0)
564 {
565 return r;
566 }
567
568 r = rbd_create2(ioctx, path+1, imagesize, imagefeatures, &order);
569 return r;
570 }
571
572 int
573 rbdfs_rename(const char *path, const char *destname)
574 {
575 int r;
576
577 r = rbdfs_checkname(destname+1);
578 if (r != 0)
579 {
580 return r;
581 }
582
583 if (strcmp(path, "/") == 0)
584 return -EINVAL;
585
586 return rbd_rename(ioctx, path+1, destname+1);
587 }
588
589 int
590 rbdfs_utime(const char *path, struct utimbuf *utime)
591 {
592 // called on create; not relevant
593 return 0;
594 }
595
596 int
597 rbdfs_unlink(const char *path)
598 {
599 int fd = find_openrbd(path+1);
600 if (fd != -1) {
601 struct rbd_openimage *rbd = &opentbl[fd];
602 rbd_close(rbd->image);
603 rbd->image = 0;
604 free(rbd->image_name);
605 rbd->rbd_stat.valid = 0;
606 }
607 return rbd_remove(ioctx, path+1);
608 }
609
610
611 int
612 rbdfs_truncate(const char *path, off_t size)
613 {
614 int fd;
615 int r;
616 struct rbd_openimage *rbd;
617
618 if ((fd = open_rbd_image(path+1)) < 0)
619 return -ENOENT;
620
621 rbd = &opentbl[fd];
622 fprintf(stderr, "truncate %s to %" PRIdMAX " (0x%" PRIxMAX ")\n",
623 path, size, size);
624 r = rbd_resize(rbd->image, size);
625 if (r < 0)
626 return r;
627
628 r = rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info),
629 sizeof(rbd_image_info_t));
630 if (r < 0)
631 return r;
632 return 0;
633 }
634
635 /**
636 * set an xattr on path, with name/value, length size.
637 * Presumably flags are from Linux, as in XATTR_CREATE or
638 * XATTR_REPLACE (both "set", but fail if exist vs fail if not exist.
639 *
640 * We accept xattrs only on the root node.
641 *
642 * All values converted with strtoull, so can be expressed in any base
643 */
644
645 struct rbdfuse_attr {
646 char *attrname;
647 uint64_t *attrvalp;
648 } attrs[] = {
649 { (char*) "user.rbdfuse.imagesize", &imagesize },
650 { (char*) "user.rbdfuse.imageorder", &imageorder },
651 { (char*) "user.rbdfuse.imagefeatures", &imagefeatures },
652 { NULL, NULL }
653 };
654
655 int
656 rbdfs_setxattr(const char *path, const char *name, const char *value,
657 size_t size,
658 int flags
659 #if defined(DARWIN)
660 ,uint32_t pos
661 #endif
662 )
663 {
664 struct rbdfuse_attr *ap;
665 if (strcmp(path, "/") != 0)
666 return -EINVAL;
667
668 for (ap = attrs; ap->attrname != NULL; ap++) {
669 if (strcmp(name, ap->attrname) == 0) {
670 *ap->attrvalp = strtoull(value, NULL, 0);
671 fprintf(stderr, "rbd-fuse: %s set to 0x%" PRIx64 "\n",
672 ap->attrname, *ap->attrvalp);
673 return 0;
674 }
675 }
676 return -EINVAL;
677 }
678
679 int
680 rbdfs_getxattr(const char *path, const char *name, char *value,
681 size_t size
682 #if defined(DARWIN)
683 ,uint32_t position
684 #endif
685 )
686 {
687 struct rbdfuse_attr *ap;
688 char buf[128];
689 // allow gets on other files; ls likes to ask for things like
690 // security.*
691
692 for (ap = attrs; ap->attrname != NULL; ap++) {
693 if (strcmp(name, ap->attrname) == 0) {
694 sprintf(buf, "%" PRIu64, *ap->attrvalp);
695 if (value != NULL && size >= strlen(buf))
696 strcpy(value, buf);
697 fprintf(stderr, "rbd-fuse: get %s\n", ap->attrname);
698 return (strlen(buf));
699 }
700 }
701 return 0;
702 }
703
704 int
705 rbdfs_listxattr(const char *path, char *list, size_t len)
706 {
707 struct rbdfuse_attr *ap;
708 size_t required_len = 0;
709
710 if (strcmp(path, "/") != 0)
711 return -EINVAL;
712
713 for (ap = attrs; ap->attrname != NULL; ap++)
714 required_len += strlen(ap->attrname) + 1;
715 if (len >= required_len) {
716 for (ap = attrs; ap->attrname != NULL; ap++) {
717 sprintf(list, "%s", ap->attrname);
718 list += strlen(ap->attrname) + 1;
719 }
720 }
721 return required_len;
722 }
723
724 const static struct fuse_operations rbdfs_oper = {
725 getattr: rbdfs_getattr,
726 readlink: 0,
727 getdir: 0,
728 mknod: 0,
729 mkdir: 0,
730 unlink: rbdfs_unlink,
731 rmdir: 0,
732 symlink: 0,
733 rename: rbdfs_rename,
734 link: 0,
735 chmod: 0,
736 chown: 0,
737 truncate: rbdfs_truncate,
738 utime: rbdfs_utime,
739 open: rbdfs_open,
740 read: rbdfs_read,
741 write: rbdfs_write,
742 statfs: rbdfs_statfs,
743 flush: 0,
744 release: 0,
745 fsync: rbdfs_fsync,
746 setxattr: rbdfs_setxattr,
747 getxattr: rbdfs_getxattr,
748 listxattr: rbdfs_listxattr,
749 removexattr: 0,
750 opendir: rbdfs_opendir,
751 readdir: rbdfs_readdir,
752 releasedir: rbdfs_releasedir,
753 fsyncdir: 0,
754 init: rbdfs_init,
755 destroy: rbdfs_destroy,
756 access: 0,
757 create: rbdfs_create,
758 /* skip unimplemented */
759 };
760
761 } /* extern "C" */
762
763 enum {
764 KEY_HELP,
765 KEY_VERSION,
766 KEY_RADOS_POOLNAME,
767 KEY_RADOS_POOLNAME_LONG,
768 KEY_RADOS_NSPACENAME,
769 KEY_RADOS_NSPACENAME_LONG,
770 KEY_RBD_IMAGENAME,
771 KEY_RBD_IMAGENAME_LONG
772 };
773
774 static struct fuse_opt rbdfs_opts[] = {
775 FUSE_OPT_KEY("-h", KEY_HELP),
776 FUSE_OPT_KEY("--help", KEY_HELP),
777 FUSE_OPT_KEY("-V", KEY_VERSION),
778 FUSE_OPT_KEY("--version", KEY_VERSION),
779 {"-p %s", offsetof(struct rbd_options, pool_name), KEY_RADOS_POOLNAME},
780 {"--poolname=%s", offsetof(struct rbd_options, pool_name),
781 KEY_RADOS_POOLNAME_LONG},
782 {"-s %s", offsetof(struct rbd_options, nspace_name), KEY_RADOS_NSPACENAME},
783 {"--namespace=%s", offsetof(struct rbd_options, nspace_name),
784 KEY_RADOS_NSPACENAME_LONG},
785 {"-r %s", offsetof(struct rbd_options, image_name), KEY_RBD_IMAGENAME},
786 {"--image=%s", offsetof(struct rbd_options, image_name),
787 KEY_RBD_IMAGENAME_LONG},
788 FUSE_OPT_END
789 };
790
791 static void usage(const char *progname)
792 {
793 fprintf(stderr,
794 "Usage: %s mountpoint [options]\n"
795 "\n"
796 "General options:\n"
797 " -h --help print help\n"
798 " -V --version print version\n"
799 " -c --conf ceph configuration file [/etc/ceph/ceph.conf]\n"
800 " -p --poolname rados pool name [rbd]\n"
801 " -s --namespace rados namespace name []\n"
802 " -r --image RBD image name\n"
803 "\n", progname);
804 }
805
806 static int rbdfs_opt_proc(void *data, const char *arg, int key,
807 struct fuse_args *outargs)
808 {
809 if (key == KEY_HELP) {
810 usage(outargs->argv[0]);
811 fuse_opt_add_arg(outargs, "-ho");
812 fuse_main(outargs->argc, outargs->argv, &rbdfs_oper, NULL);
813 exit(1);
814 }
815
816 if (key == KEY_VERSION) {
817 fuse_opt_add_arg(outargs, "--version");
818 fuse_main(outargs->argc, outargs->argv, &rbdfs_oper, NULL);
819 exit(0);
820 }
821
822 if (key == KEY_RADOS_POOLNAME) {
823 if (rbd_options.pool_name != NULL) {
824 free(rbd_options.pool_name);
825 rbd_options.pool_name = NULL;
826 }
827 rbd_options.pool_name = strdup(arg+2);
828 return 0;
829 }
830
831 if (key == KEY_RADOS_NSPACENAME) {
832 if (rbd_options.nspace_name != NULL) {
833 free(rbd_options.nspace_name);
834 rbd_options.nspace_name = NULL;
835 }
836 rbd_options.nspace_name = strdup(arg+2);
837 return 0;
838 }
839
840 if (key == KEY_RBD_IMAGENAME) {
841 if (rbd_options.image_name!= NULL) {
842 free(rbd_options.image_name);
843 rbd_options.image_name = NULL;
844 }
845 rbd_options.image_name = strdup(arg+2);
846 return 0;
847 }
848
849 return 1;
850 }
851
852 void
853 simple_err(const char *msg, int err)
854 {
855 fprintf(stderr, "%s: %s\n", msg, strerror(-err));
856 return;
857 }
858
859 int
860 connect_to_cluster(rados_t *pcluster)
861 {
862 int r;
863 global_init_postfork_start(g_ceph_context);
864 common_init_finish(g_ceph_context);
865 global_init_postfork_finish(g_ceph_context);
866
867 r = rados_create_with_context(pcluster, g_ceph_context);
868 if (r < 0) {
869 simple_err("Could not create cluster handle", r);
870 return r;
871 }
872
873 r = rados_connect(*pcluster);
874 if (r < 0) {
875 simple_err("Error connecting to cluster", r);
876 rados_shutdown(*pcluster);
877 return r;
878 }
879
880 return 0;
881 }
882
883 int main(int argc, const char *argv[])
884 {
885 memset(&rbd_image_data, 0, sizeof(rbd_image_data));
886
887 // librados will filter out -f/-d options from command-line
888 std::map<std::string, bool> filter_args = {
889 {"-f", false},
890 {"-d", false}};
891
892 std::vector<const char*> arg_vector;
893 for (auto idx = 0; idx < argc; ++idx) {
894 auto it = filter_args.find(argv[idx]);
895 if (it != filter_args.end()) {
896 it->second = true;
897 }
898 arg_vector.push_back(argv[idx]);
899 }
900
901 auto cct = global_init(NULL, arg_vector, CEPH_ENTITY_TYPE_CLIENT,
902 CODE_ENVIRONMENT_DAEMON,
903 CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS);
904 g_ceph_context->_conf.set_val_or_die("pid_file", "");
905 g_ceph_context->_conf.set_val_or_die("daemonize", "true");
906
907 if (global_init_prefork(g_ceph_context) < 0) {
908 fprintf(stderr, "Failed to initialize librados\n");
909 exit(1);
910 }
911
912 for (auto& it : filter_args) {
913 if (it.second) {
914 arg_vector.push_back(it.first.c_str());
915 }
916 }
917
918 struct fuse_args args = FUSE_ARGS_INIT((int)arg_vector.size(),
919 (char**)&arg_vector.front());
920 if (fuse_opt_parse(&args, &rbd_options, rbdfs_opts,
921 rbdfs_opt_proc) == -1) {
922 exit(1);
923 }
924
925 return fuse_main(args.argc, args.argv, &rbdfs_oper, NULL);
926 }