4 #define FUSE_USE_VERSION 30
6 #include "include/int_types.h"
17 #include <sys/types.h>
24 #if defined(__FreeBSD__)
25 #include <sys/param.h>
28 #include "include/compat.h"
29 #include "include/rbd/librbd.h"
31 static int gotrados = 0;
33 char *mount_image_name;
37 std::mutex readdir_lock;
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);