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