4 #define FUSE_USE_VERSION 30
6 #include "include/int_types.h"
17 #include <sys/types.h>
23 #if defined(__FreeBSD__)
24 #include <sys/param.h>
27 #include "include/compat.h"
28 #include "include/rbd/librbd.h"
29 #include "common/Mutex.h"
31 static int gotrados
= 0;
33 char *mount_image_name
;
37 Mutex
readdir_lock("read_dir");
41 rbd_image_info_t rbd_info
;
52 struct rbd_image
*next
;
54 struct rbd_image_data
{
55 struct rbd_image
*images
;
58 struct rbd_image_data rbd_image_data
;
60 struct rbd_openimage
{
63 struct rbd_stat rbd_stat
;
65 #define MAX_RBD_IMAGES 128
66 struct rbd_openimage opentbl
[MAX_RBD_IMAGES
];
68 struct rbd_options rbd_options
= {(char*) "/etc/ceph/ceph.conf", (char*) "rbd",
71 #define rbdsize(fd) opentbl[fd].rbd_stat.rbd_info.size
72 #define rbdblksize(fd) opentbl[fd].rbd_stat.rbd_info.obj_size
73 #define rbdblkcnt(fd) opentbl[fd].rbd_stat.rbd_info.num_objs
75 uint64_t imagesize
= 1024ULL * 1024 * 1024;
76 uint64_t imageorder
= 22ULL;
77 uint64_t imagefeatures
= 1ULL;
79 // Minimize calls to rbd_list: marks bracketing of opendir/<ops>/releasedir
83 int connect_to_cluster(rados_t
*pcluster
);
84 void enumerate_images(struct rbd_image_data
*data
);
85 int open_rbd_image(const char *image_name
);
86 int find_openrbd(const char *path
);
88 void simple_err(const char *msg
, int err
);
91 enumerate_images(struct rbd_image_data
*data
)
93 struct rbd_image
**head
= &data
->images
;
96 struct rbd_image
*im
, *next
;
101 for (im
= *head
; im
!= NULL
;) {
111 ret
= rbd_list(ioctx
, ibuf
, &ibuf_len
);
112 if (ret
== -ERANGE
) {
113 assert(ibuf_len
> 0);
114 ibuf
= (char*) malloc(ibuf_len
);
116 simple_err("Failed to get ibuf", -ENOMEM
);
119 } else if (ret
< 0) {
120 simple_err("Failed to get ibuf_len", ret
);
124 ret
= rbd_list(ioctx
, ibuf
, &ibuf_len
);
126 simple_err("Failed to populate ibuf", ret
);
130 assert(ret
== (int)ibuf_len
);
132 fprintf(stderr
, "pool %s: ", pool_name
);
133 for (ip
= ibuf
; ip
< &ibuf
[ibuf_len
]; ip
+= strlen(ip
) + 1) {
134 if ((mount_image_name
== NULL
) ||
135 ((strlen(mount_image_name
) > 0) &&
136 (strcmp(ip
, mount_image_name
) == 0))) {
137 fprintf(stderr
, "%s, ", ip
);
138 im
= static_cast<rbd_image
*>(malloc(sizeof(*im
)));
144 fprintf(stderr
, "\n");
149 find_openrbd(const char *path
)
153 /* find in opentbl[] entry if already open */
154 for (i
= 0; i
< MAX_RBD_IMAGES
; i
++) {
155 if ((opentbl
[i
].image_name
!= NULL
) &&
156 (strcmp(opentbl
[i
].image_name
, path
) == 0)) {
164 open_rbd_image(const char *image_name
)
166 struct rbd_image
*im
;
167 struct rbd_openimage
*rbd
= NULL
;
170 if (image_name
== (char *)NULL
)
173 // relies on caller to keep rbd_image_data up to date
174 for (im
= rbd_image_data
.images
; im
!= NULL
; im
= im
->next
) {
175 if (strcmp(im
->image_name
, image_name
) == 0) {
182 /* find in opentbl[] entry if already open */
183 if ((fd
= find_openrbd(image_name
)) != -1) {
187 // allocate an opentbl[] and open the image
188 for (i
= 0; i
< MAX_RBD_IMAGES
; i
++) {
189 if (opentbl
[i
].image
== NULL
) {
192 rbd
->image_name
= strdup(image_name
);
196 if (i
== MAX_RBD_IMAGES
|| !rbd
)
198 int ret
= rbd_open(ioctx
, rbd
->image_name
, &(rbd
->image
), NULL
);
200 simple_err("open_rbd_image: can't open: ", ret
);
204 rbd_stat(rbd
->image
, &(rbd
->rbd_stat
.rbd_info
),
205 sizeof(rbd_image_info_t
));
206 rbd
->rbd_stat
.valid
= 1;
211 iter_images(void *cookie
,
212 void (*iter
)(void *cookie
, const char *image
))
214 struct rbd_image
*im
;
218 for (im
= rbd_image_data
.images
; im
!= NULL
; im
= im
->next
)
219 iter(cookie
, im
->image_name
);
220 readdir_lock
.Unlock();
223 static void count_images_cb(void *cookie
, const char *image
)
225 (*((unsigned int *)cookie
))++;
228 static int count_images(void)
230 unsigned int count
= 0;
233 enumerate_images(&rbd_image_data
);
234 readdir_lock
.Unlock();
236 iter_images(&count
, count_images_cb
);
242 static int rbdfs_getattr(const char *path
, struct stat
*stbuf
)
253 memset(stbuf
, 0, sizeof(struct stat
));
255 if (strcmp(path
, "/") == 0) {
258 stbuf
->st_mode
= S_IFDIR
+ 0755;
259 stbuf
->st_nlink
= 2+count_images();
260 stbuf
->st_uid
= getuid();
261 stbuf
->st_gid
= getgid();
262 stbuf
->st_size
= 1024;
263 stbuf
->st_blksize
= 1024;
264 stbuf
->st_blocks
= 1;
265 stbuf
->st_atime
= now
;
266 stbuf
->st_mtime
= now
;
267 stbuf
->st_ctime
= now
;
274 enumerate_images(&rbd_image_data
);
275 readdir_lock
.Unlock();
277 fd
= open_rbd_image(path
+ 1);
282 stbuf
->st_mode
= S_IFREG
| 0666;
284 stbuf
->st_uid
= getuid();
285 stbuf
->st_gid
= getgid();
286 stbuf
->st_size
= rbdsize(fd
);
287 stbuf
->st_blksize
= rbdblksize(fd
);
288 stbuf
->st_blocks
= rbdblkcnt(fd
);
289 stbuf
->st_atime
= now
;
290 stbuf
->st_mtime
= now
;
291 stbuf
->st_ctime
= now
;
297 static int rbdfs_open(const char *path
, struct fuse_file_info
*fi
)
308 enumerate_images(&rbd_image_data
);
309 readdir_lock
.Unlock();
310 fd
= open_rbd_image(path
+ 1);
318 static int rbdfs_read(const char *path
, char *buf
, size_t size
,
319 off_t offset
, struct fuse_file_info
*fi
)
322 struct rbd_openimage
*rbd
;
327 rbd
= &opentbl
[fi
->fh
];
332 ret
= rbd_read(rbd
->image
, offset
, size
, buf
);
345 static int rbdfs_write(const char *path
, const char *buf
, size_t size
,
346 off_t offset
, struct fuse_file_info
*fi
)
349 struct rbd_openimage
*rbd
;
354 rbd
= &opentbl
[fi
->fh
];
359 if ((size_t)(offset
+ size
) > rbdsize(fi
->fh
)) {
361 fprintf(stderr
, "rbdfs_write resizing %s to 0x%" PRIxMAX
"\n",
363 r
= rbd_resize(rbd
->image
, offset
+size
);
367 r
= rbd_stat(rbd
->image
, &(rbd
->rbd_stat
.rbd_info
),
368 sizeof(rbd_image_info_t
));
372 ret
= rbd_write(rbd
->image
, offset
, size
, buf
);
385 static void rbdfs_statfs_image_cb(void *num
, const char *image
)
389 ((uint64_t *)num
)[0]++;
391 fd
= open_rbd_image(image
);
393 ((uint64_t *)num
)[1] += rbdsize(fd
);
396 static int rbdfs_statfs(const char *path
, struct statvfs
*buf
)
406 enumerate_images(&rbd_image_data
);
407 readdir_lock
.Unlock();
408 iter_images(num
, rbdfs_statfs_image_cb
);
410 #define RBDFS_BSIZE 4096
411 buf
->f_bsize
= RBDFS_BSIZE
;
412 buf
->f_frsize
= RBDFS_BSIZE
;
413 buf
->f_blocks
= num
[1] / RBDFS_BSIZE
;
416 buf
->f_files
= num
[0];
421 buf
->f_namemax
= PATH_MAX
;
426 static int rbdfs_fsync(const char *path
, int datasync
,
427 struct fuse_file_info
*fi
)
431 rbd_flush(opentbl
[fi
->fh
].image
);
435 static int rbdfs_opendir(const char *path
, struct fuse_file_info
*fi
)
437 // only one directory, so global "in_opendir" flag should be fine
440 enumerate_images(&rbd_image_data
);
441 readdir_lock
.Unlock();
445 struct rbdfs_readdir_info
{
447 fuse_fill_dir_t filler
;
450 static void rbdfs_readdir_cb(void *_info
, const char *name
)
452 struct rbdfs_readdir_info
*info
= (struct rbdfs_readdir_info
*) _info
;
454 info
->filler(info
->buf
, name
, NULL
, 0);
457 static int rbdfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
458 off_t offset
, struct fuse_file_info
*fi
)
460 struct rbdfs_readdir_info info
= { buf
, filler
};
465 fprintf(stderr
, "in readdir, but not inside opendir?\n");
467 if (strcmp(path
, "/") != 0)
470 filler(buf
, ".", NULL
, 0);
471 filler(buf
, "..", NULL
, 0);
472 iter_images(&info
, rbdfs_readdir_cb
);
476 static int rbdfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
478 // see opendir comments
481 readdir_lock
.Unlock();
486 rbdfs_init(struct fuse_conn_info
*conn
)
490 // init cannot fail, so if we fail here, gotrados remains at 0,
491 // causing other operations to fail immediately with ENXIO
493 ret
= connect_to_cluster(&cluster
);
497 pool_name
= rbd_options
.pool_name
;
498 mount_image_name
= rbd_options
.image_name
;
499 ret
= rados_ioctx_create(cluster
, pool_name
, &ioctx
);
502 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
503 conn
->want
|= FUSE_CAP_BIG_WRITES
;
507 // init's return value shows up in fuse_context.private_data,
508 // also to void (*destroy)(void *); useful?
513 rbdfs_destroy(void *unused
)
517 for (int i
= 0; i
< MAX_RBD_IMAGES
; ++i
) {
518 if (opentbl
[i
].image
) {
519 rbd_close(opentbl
[i
].image
);
520 opentbl
[i
].image
= NULL
;
523 rados_ioctx_destroy(ioctx
);
524 rados_shutdown(cluster
);
528 rbdfs_checkname(const char *checkname
)
530 const char *extra
[] = {"@", "/"};
531 std::string
strCheckName(checkname
);
533 if (strCheckName
.empty())
536 unsigned int sz
= sizeof(extra
) / sizeof(const char*);
537 for (unsigned int i
= 0; i
< sz
; i
++)
539 std::string
ex(extra
[i
]);
540 if (std::string::npos
!= strCheckName
.find(ex
))
547 // return -errno on error. fi->fh is not set until open time
550 rbdfs_create(const char *path
, mode_t mode
, struct fuse_file_info
*fi
)
553 int order
= imageorder
;
555 r
= rbdfs_checkname(path
+1);
561 r
= rbd_create2(ioctx
, path
+1, imagesize
, imagefeatures
, &order
);
566 rbdfs_rename(const char *path
, const char *destname
)
570 r
= rbdfs_checkname(destname
+1);
576 if (strcmp(path
, "/") == 0)
579 return rbd_rename(ioctx
, path
+1, destname
+1);
583 rbdfs_utime(const char *path
, struct utimbuf
*utime
)
585 // called on create; not relevant
590 rbdfs_unlink(const char *path
)
592 int fd
= find_openrbd(path
+1);
594 struct rbd_openimage
*rbd
= &opentbl
[fd
];
595 rbd_close(rbd
->image
);
597 free(rbd
->image_name
);
598 rbd
->rbd_stat
.valid
= 0;
600 return rbd_remove(ioctx
, path
+1);
605 rbdfs_truncate(const char *path
, off_t size
)
609 struct rbd_openimage
*rbd
;
611 if ((fd
= open_rbd_image(path
+1)) < 0)
615 fprintf(stderr
, "truncate %s to %" PRIdMAX
" (0x%" PRIxMAX
")\n",
617 r
= rbd_resize(rbd
->image
, size
);
621 r
= rbd_stat(rbd
->image
, &(rbd
->rbd_stat
.rbd_info
),
622 sizeof(rbd_image_info_t
));
629 * set an xattr on path, with name/value, length size.
630 * Presumably flags are from Linux, as in XATTR_CREATE or
631 * XATTR_REPLACE (both "set", but fail if exist vs fail if not exist.
633 * We accept xattrs only on the root node.
635 * All values converted with strtoull, so can be expressed in any base
638 struct rbdfuse_attr
{
642 { (char*) "user.rbdfuse.imagesize", &imagesize
},
643 { (char*) "user.rbdfuse.imageorder", &imageorder
},
644 { (char*) "user.rbdfuse.imagefeatures", &imagefeatures
},
649 rbdfs_setxattr(const char *path
, const char *name
, const char *value
,
657 struct rbdfuse_attr
*ap
;
658 if (strcmp(path
, "/") != 0)
661 for (ap
= attrs
; ap
->attrname
!= NULL
; ap
++) {
662 if (strcmp(name
, ap
->attrname
) == 0) {
663 *ap
->attrvalp
= strtoull(value
, NULL
, 0);
664 fprintf(stderr
, "rbd-fuse: %s set to 0x%" PRIx64
"\n",
665 ap
->attrname
, *ap
->attrvalp
);
673 rbdfs_getxattr(const char *path
, const char *name
, char *value
,
680 struct rbdfuse_attr
*ap
;
682 // allow gets on other files; ls likes to ask for things like
685 for (ap
= attrs
; ap
->attrname
!= NULL
; ap
++) {
686 if (strcmp(name
, ap
->attrname
) == 0) {
687 sprintf(buf
, "%" PRIu64
, *ap
->attrvalp
);
688 if (value
!= NULL
&& size
>= strlen(buf
))
690 fprintf(stderr
, "rbd-fuse: get %s\n", ap
->attrname
);
691 return (strlen(buf
));
698 rbdfs_listxattr(const char *path
, char *list
, size_t len
)
700 struct rbdfuse_attr
*ap
;
701 size_t required_len
= 0;
703 if (strcmp(path
, "/") != 0)
706 for (ap
= attrs
; ap
->attrname
!= NULL
; ap
++)
707 required_len
+= strlen(ap
->attrname
) + 1;
708 if (len
>= required_len
) {
709 for (ap
= attrs
; ap
->attrname
!= NULL
; ap
++) {
710 sprintf(list
, "%s", ap
->attrname
);
711 list
+= strlen(ap
->attrname
) + 1;
717 const static struct fuse_operations rbdfs_oper
= {
718 getattr
: rbdfs_getattr
,
723 unlink
: rbdfs_unlink
,
726 rename
: rbdfs_rename
,
730 truncate
: rbdfs_truncate
,
735 statfs
: rbdfs_statfs
,
739 setxattr
: rbdfs_setxattr
,
740 getxattr
: rbdfs_getxattr
,
741 listxattr
: rbdfs_listxattr
,
743 opendir
: rbdfs_opendir
,
744 readdir
: rbdfs_readdir
,
745 releasedir
: rbdfs_releasedir
,
748 destroy
: rbdfs_destroy
,
750 create
: rbdfs_create
,
751 /* skip unimplemented */
760 KEY_CEPH_CONFIG_LONG
,
762 KEY_RADOS_POOLNAME_LONG
,
764 KEY_RBD_IMAGENAME_LONG
767 static struct fuse_opt rbdfs_opts
[] = {
768 FUSE_OPT_KEY("-h", KEY_HELP
),
769 FUSE_OPT_KEY("--help", KEY_HELP
),
770 FUSE_OPT_KEY("-V", KEY_VERSION
),
771 FUSE_OPT_KEY("--version", KEY_VERSION
),
772 {"-c %s", offsetof(struct rbd_options
, ceph_config
), KEY_CEPH_CONFIG
},
773 {"--configfile=%s", offsetof(struct rbd_options
, ceph_config
),
774 KEY_CEPH_CONFIG_LONG
},
775 {"-p %s", offsetof(struct rbd_options
, pool_name
), KEY_RADOS_POOLNAME
},
776 {"--poolname=%s", offsetof(struct rbd_options
, pool_name
),
777 KEY_RADOS_POOLNAME_LONG
},
778 {"-r %s", offsetof(struct rbd_options
, image_name
), KEY_RBD_IMAGENAME
},
779 {"--image=%s", offsetof(struct rbd_options
, image_name
),
780 KEY_RBD_IMAGENAME_LONG
},
783 static void usage(const char *progname
)
786 "Usage: %s mountpoint [options]\n"
789 " -h --help print help\n"
790 " -V --version print version\n"
791 " -c --configfile ceph configuration file [/etc/ceph/ceph.conf]\n"
792 " -p --poolname rados pool name [rbd]\n"
793 " -r --image RBD image name\n"
797 static int rbdfs_opt_proc(void *data
, const char *arg
, int key
,
798 struct fuse_args
*outargs
)
800 if (key
== KEY_HELP
) {
801 usage(outargs
->argv
[0]);
802 fuse_opt_add_arg(outargs
, "-ho");
803 fuse_main(outargs
->argc
, outargs
->argv
, &rbdfs_oper
, NULL
);
807 if (key
== KEY_VERSION
) {
808 fuse_opt_add_arg(outargs
, "--version");
809 fuse_main(outargs
->argc
, outargs
->argv
, &rbdfs_oper
, NULL
);
813 if (key
== KEY_CEPH_CONFIG
) {
814 if (rbd_options
.ceph_config
!= NULL
) {
815 free(rbd_options
.ceph_config
);
816 rbd_options
.ceph_config
= NULL
;
818 rbd_options
.ceph_config
= strdup(arg
+2);
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
;
827 rbd_options
.pool_name
= strdup(arg
+2);
831 if (key
== KEY_RBD_IMAGENAME
) {
832 if (rbd_options
.image_name
!= NULL
) {
833 free(rbd_options
.image_name
);
834 rbd_options
.image_name
= NULL
;
836 rbd_options
.image_name
= strdup(arg
+2);
844 simple_err(const char *msg
, int err
)
846 fprintf(stderr
, "%s: %s\n", msg
, strerror(-err
));
851 connect_to_cluster(rados_t
*pcluster
)
855 r
= rados_create(pcluster
, NULL
);
857 simple_err("Could not create cluster handle", r
);
860 rados_conf_parse_env(*pcluster
, NULL
);
861 r
= rados_conf_read_file(*pcluster
, rbd_options
.ceph_config
);
863 simple_err("Error reading Ceph config file", r
);
864 goto failed_shutdown
;
866 r
= rados_connect(*pcluster
);
868 simple_err("Error connecting to cluster", r
);
869 goto failed_shutdown
;
875 rados_shutdown(*pcluster
);
879 int main(int argc
, char *argv
[])
881 struct fuse_args args
= FUSE_ARGS_INIT(argc
, argv
);
883 if (fuse_opt_parse(&args
, &rbd_options
, rbdfs_opts
, rbdfs_opt_proc
) == -1) {
887 return fuse_main(args
.argc
, args
.argv
, &rbdfs_oper
, NULL
);