]> git.proxmox.com Git - ceph.git/blame - ceph/src/rbd_fuse/rbd-fuse.cc
import 15.2.2 octopus source
[ceph.git] / ceph / src / rbd_fuse / rbd-fuse.cc
CommitLineData
7c673cae
FG
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>
d2e6a577 22#include <mutex>
11fdf7f2 23#include <limits.h>
7c673cae
FG
24
25#if defined(__FreeBSD__)
26#include <sys/param.h>
27#endif
28
29#include "include/compat.h"
30#include "include/rbd/librbd.h"
11fdf7f2
TL
31#include "include/ceph_assert.h"
32
33#include "common/ceph_argparse.h"
34#include "common/ceph_context.h"
1911f103 35#include "include/ceph_fuse.h"
11fdf7f2
TL
36
37#include "global/global_init.h"
38#include "global/global_context.h"
7c673cae
FG
39
40static int gotrados = 0;
41char *pool_name;
11fdf7f2 42char *nspace_name;
7c673cae
FG
43char *mount_image_name;
44rados_t cluster;
45rados_ioctx_t ioctx;
46
d2e6a577 47std::mutex readdir_lock;
7c673cae
FG
48
49struct rbd_stat {
50 u_char valid;
51 rbd_image_info_t rbd_info;
52};
53
54struct rbd_options {
7c673cae 55 char *pool_name;
11fdf7f2 56 char *nspace_name;
7c673cae
FG
57 char *image_name;
58};
59
60struct rbd_image {
61 char *image_name;
62 struct rbd_image *next;
63};
64struct rbd_image_data {
11fdf7f2
TL
65 struct rbd_image *images;
66 rbd_image_spec_t *image_specs;
67 size_t image_spec_count;
7c673cae
FG
68};
69struct rbd_image_data rbd_image_data;
70
71struct rbd_openimage {
72 char *image_name;
73 rbd_image_t image;
74 struct rbd_stat rbd_stat;
75};
76#define MAX_RBD_IMAGES 128
77struct rbd_openimage opentbl[MAX_RBD_IMAGES];
78
11fdf7f2 79struct rbd_options rbd_options = {(char*) "rbd", (char*) "", NULL};
7c673cae
FG
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
85uint64_t imagesize = 1024ULL * 1024 * 1024;
86uint64_t imageorder = 22ULL;
87uint64_t imagefeatures = 1ULL;
88
89// Minimize calls to rbd_list: marks bracketing of opendir/<ops>/releasedir
90int in_opendir;
91
92/* prototypes */
93int connect_to_cluster(rados_t *pcluster);
94void enumerate_images(struct rbd_image_data *data);
95int open_rbd_image(const char *image_name);
96int find_openrbd(const char *path);
97
98void simple_err(const char *msg, int err);
99
100void
101enumerate_images(struct rbd_image_data *data)
102{
103 struct rbd_image **head = &data->images;
7c673cae 104 struct rbd_image *im, *next;
7c673cae
FG
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;
11fdf7f2
TL
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;
7c673cae
FG
119 }
120
11fdf7f2
TL
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;
7c673cae 132 }
7c673cae
FG
133 }
134
11fdf7f2
TL
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);
7c673cae 139 }
11fdf7f2 140 for (size_t idx = 0; idx < data->image_spec_count; ++idx) {
7c673cae
FG
141 if ((mount_image_name == NULL) ||
142 ((strlen(mount_image_name) > 0) &&
11fdf7f2
TL
143 (strcmp(data->image_specs[idx].name, mount_image_name) == 0))) {
144 fprintf(stderr, "%s, ", data->image_specs[idx].name);
7c673cae 145 im = static_cast<rbd_image*>(malloc(sizeof(*im)));
11fdf7f2 146 im->image_name = data->image_specs[idx].name;
7c673cae
FG
147 im->next = *head;
148 *head = im;
149 }
150 }
151 fprintf(stderr, "\n");
7c673cae
FG
152}
153
154int
155find_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
169int
170open_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
216static void
217iter_images(void *cookie,
218 void (*iter)(void *cookie, const char *image))
219{
220 struct rbd_image *im;
221
d2e6a577
FG
222 readdir_lock.lock();
223
7c673cae
FG
224 for (im = rbd_image_data.images; im != NULL; im = im->next)
225 iter(cookie, im->image_name);
d2e6a577 226 readdir_lock.unlock();
7c673cae
FG
227}
228
229static void count_images_cb(void *cookie, const char *image)
230{
231 (*((unsigned int *)cookie))++;
232}
233
234static int count_images(void)
235{
236 unsigned int count = 0;
237
d2e6a577 238 readdir_lock.lock();
7c673cae 239 enumerate_images(&rbd_image_data);
d2e6a577 240 readdir_lock.unlock();
7c673cae
FG
241
242 iter_images(&count, count_images_cb);
243 return count;
244}
245
246extern "C" {
247
1911f103
TL
248static 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 )
7c673cae
FG
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) {
d2e6a577 283 readdir_lock.lock();
7c673cae 284 enumerate_images(&rbd_image_data);
d2e6a577 285 readdir_lock.unlock();
7c673cae
FG
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
307static 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
d2e6a577 317 readdir_lock.lock();
7c673cae 318 enumerate_images(&rbd_image_data);
d2e6a577 319 readdir_lock.unlock();
7c673cae
FG
320 fd = open_rbd_image(path + 1);
321 if (fd < 0)
322 return -ENOENT;
323
324 fi->fh = fd;
325 return 0;
326}
327
328static 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
355static 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
395static 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
406static 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;
d2e6a577 415 readdir_lock.lock();
7c673cae 416 enumerate_images(&rbd_image_data);
d2e6a577 417 readdir_lock.unlock();
7c673cae
FG
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
436static 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
445static int rbdfs_opendir(const char *path, struct fuse_file_info *fi)
446{
447 // only one directory, so global "in_opendir" flag should be fine
d2e6a577 448 readdir_lock.lock();
7c673cae
FG
449 in_opendir++;
450 enumerate_images(&rbd_image_data);
d2e6a577 451 readdir_lock.unlock();
7c673cae
FG
452 return 0;
453}
454
455struct rbdfs_readdir_info {
456 void *buf;
457 fuse_fill_dir_t filler;
458};
459
460static void rbdfs_readdir_cb(void *_info, const char *name)
461{
462 struct rbdfs_readdir_info *info = (struct rbdfs_readdir_info*) _info;
463
1911f103 464 filler_compat(info->filler, info->buf, name, NULL, 0);
7c673cae
FG
465}
466
467static int rbdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
1911f103
TL
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 )
7c673cae
FG
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
1911f103
TL
484 filler_compat(filler, buf, ".", NULL, 0);
485 filler_compat(filler, buf, "..", NULL, 0);
7c673cae
FG
486 iter_images(&info, rbdfs_readdir_cb);
487
488 return 0;
489}
490static int rbdfs_releasedir(const char *path, struct fuse_file_info *fi)
491{
492 // see opendir comments
d2e6a577 493 readdir_lock.lock();
7c673cae 494 in_opendir--;
d2e6a577 495 readdir_lock.unlock();
7c673cae
FG
496 return 0;
497}
498
499void *
1911f103
TL
500rbdfs_init(struct fuse_conn_info *conn
501#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
502 , struct fuse_config *cfg
503#endif
504 )
7c673cae
FG
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;
11fdf7f2 516 nspace_name = rbd_options.nspace_name;
7c673cae
FG
517 mount_image_name = rbd_options.image_name;
518 ret = rados_ioctx_create(cluster, pool_name, &ioctx);
519 if (ret < 0)
520 exit(91);
1911f103 521#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) && FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
7c673cae
FG
522 conn->want |= FUSE_CAP_BIG_WRITES;
523#endif
11fdf7f2 524 rados_ioctx_set_namespace(ioctx, nspace_name);
7c673cae
FG
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
532void
533rbdfs_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
547int
548rbdfs_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
569int
570rbdfs_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
585int
1911f103
TL
586rbdfs_rename(const char *path, const char *destname
587#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
588 , unsigned int flags
589#endif
590 )
7c673cae
FG
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
606int
1911f103
TL
607rbdfs_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 )
7c673cae
FG
612{
613 // called on create; not relevant
614 return 0;
615}
616
617int
618rbdfs_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
632int
1911f103
TL
633rbdfs_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 )
7c673cae
FG
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
670struct 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
680int
681rbdfs_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
704int
705rbdfs_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
729int
730rbdfs_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
749const static struct fuse_operations rbdfs_oper = {
750 getattr: rbdfs_getattr,
751 readlink: 0,
1911f103 752#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
7c673cae 753 getdir: 0,
1911f103 754#endif
7c673cae
FG
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,
1911f103
TL
765#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
766 utime: 0,
767#endif
7c673cae
FG
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,
1911f103
TL
787#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
788 ftruncate: 0,
789 fgetattr: 0,
790#endif
791 lock: 0,
792 utimens: rbdfs_utimens,
7c673cae
FG
793 /* skip unimplemented */
794};
795
796} /* extern "C" */
797
798enum {
799 KEY_HELP,
800 KEY_VERSION,
7c673cae
FG
801 KEY_RADOS_POOLNAME,
802 KEY_RADOS_POOLNAME_LONG,
11fdf7f2
TL
803 KEY_RADOS_NSPACENAME,
804 KEY_RADOS_NSPACENAME_LONG,
7c673cae
FG
805 KEY_RBD_IMAGENAME,
806 KEY_RBD_IMAGENAME_LONG
807};
808
809static 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),
7c673cae
FG
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},
11fdf7f2
TL
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},
7c673cae
FG
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},
11fdf7f2 823 FUSE_OPT_END
7c673cae
FG
824};
825
826static 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"
11fdf7f2 834" -c --conf ceph configuration file [/etc/ceph/ceph.conf]\n"
7c673cae 835" -p --poolname rados pool name [rbd]\n"
11fdf7f2 836" -s --namespace rados namespace name []\n"
7c673cae
FG
837" -r --image RBD image name\n"
838"\n", progname);
839}
840
841static 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
7c673cae
FG
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
11fdf7f2
TL
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
7c673cae
FG
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
887void
888simple_err(const char *msg, int err)
889{
890 fprintf(stderr, "%s: %s\n", msg, strerror(-err));
891 return;
892}
893
894int
895connect_to_cluster(rados_t *pcluster)
896{
897 int r;
11fdf7f2
TL
898 global_init_postfork_start(g_ceph_context);
899 common_init_finish(g_ceph_context);
900 global_init_postfork_finish(g_ceph_context);
7c673cae 901
11fdf7f2 902 r = rados_create_with_context(pcluster, g_ceph_context);
7c673cae
FG
903 if (r < 0) {
904 simple_err("Could not create cluster handle", r);
905 return r;
906 }
11fdf7f2 907
7c673cae
FG
908 r = rados_connect(*pcluster);
909 if (r < 0) {
910 simple_err("Error connecting to cluster", r);
11fdf7f2
TL
911 rados_shutdown(*pcluster);
912 return r;
7c673cae
FG
913 }
914
915 return 0;
7c673cae
FG
916}
917
11fdf7f2 918int main(int argc, const char *argv[])
7c673cae 919{
11fdf7f2
TL
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 }
7c673cae 952
11fdf7f2
TL
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) {
7c673cae
FG
957 exit(1);
958 }
959
960 return fuse_main(args.argc, args.argv, &rbdfs_oper, NULL);
961}