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