]> git.proxmox.com Git - ceph.git/blob - ceph/src/rbd_fuse/rbd-fuse.cc
update sources to v12.1.3
[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
24 #if defined(__FreeBSD__)
25 #include <sys/param.h>
26 #endif
27
28 #include "include/compat.h"
29 #include "include/rbd/librbd.h"
30
31 static int gotrados = 0;
32 char *pool_name;
33 char *mount_image_name;
34 rados_t cluster;
35 rados_ioctx_t ioctx;
36
37 std::mutex readdir_lock;
38
39 struct rbd_stat {
40 u_char valid;
41 rbd_image_info_t rbd_info;
42 };
43
44 struct rbd_options {
45 char *ceph_config;
46 char *pool_name;
47 char *image_name;
48 };
49
50 struct rbd_image {
51 char *image_name;
52 struct rbd_image *next;
53 };
54 struct rbd_image_data {
55 struct rbd_image *images;
56 void *buf;
57 };
58 struct rbd_image_data rbd_image_data;
59
60 struct rbd_openimage {
61 char *image_name;
62 rbd_image_t image;
63 struct rbd_stat rbd_stat;
64 };
65 #define MAX_RBD_IMAGES 128
66 struct rbd_openimage opentbl[MAX_RBD_IMAGES];
67
68 struct rbd_options rbd_options = {(char*) "/etc/ceph/ceph.conf", (char*) "rbd",
69 NULL};
70
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
74
75 uint64_t imagesize = 1024ULL * 1024 * 1024;
76 uint64_t imageorder = 22ULL;
77 uint64_t imagefeatures = 1ULL;
78
79 // Minimize calls to rbd_list: marks bracketing of opendir/<ops>/releasedir
80 int in_opendir;
81
82 /* prototypes */
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);
87
88 void simple_err(const char *msg, int err);
89
90 void
91 enumerate_images(struct rbd_image_data *data)
92 {
93 struct rbd_image **head = &data->images;
94 char *ibuf = NULL;
95 size_t ibuf_len = 0;
96 struct rbd_image *im, *next;
97 char *ip;
98 int ret;
99
100 if (*head != NULL) {
101 for (im = *head; im != NULL;) {
102 next = im->next;
103 free(im);
104 im = next;
105 }
106 *head = NULL;
107 free(data->buf);
108 data->buf = NULL;
109 }
110
111 ret = rbd_list(ioctx, ibuf, &ibuf_len);
112 if (ret == -ERANGE) {
113 assert(ibuf_len > 0);
114 ibuf = (char*) malloc(ibuf_len);
115 if (!ibuf) {
116 simple_err("Failed to get ibuf", -ENOMEM);
117 return;
118 }
119 } else if (ret < 0) {
120 simple_err("Failed to get ibuf_len", ret);
121 return;
122 }
123
124 ret = rbd_list(ioctx, ibuf, &ibuf_len);
125 if (ret < 0) {
126 simple_err("Failed to populate ibuf", ret);
127 free(ibuf);
128 return;
129 }
130 assert(ret == (int)ibuf_len);
131
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)));
139 im->image_name = ip;
140 im->next = *head;
141 *head = im;
142 }
143 }
144 fprintf(stderr, "\n");
145 data->buf = ibuf;
146 }
147
148 int
149 find_openrbd(const char *path)
150 {
151 int i;
152
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)) {
157 return i;
158 }
159 }
160 return -1;
161 }
162
163 int
164 open_rbd_image(const char *image_name)
165 {
166 struct rbd_image *im;
167 struct rbd_openimage *rbd = NULL;
168 int fd;
169
170 if (image_name == (char *)NULL)
171 return -1;
172
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) {
176 break;
177 }
178 }
179 if (im == NULL)
180 return -1;
181
182 /* find in opentbl[] entry if already open */
183 if ((fd = find_openrbd(image_name)) != -1) {
184 rbd = &opentbl[fd];
185 } else {
186 int i;
187 // allocate an opentbl[] and open the image
188 for (i = 0; i < MAX_RBD_IMAGES; i++) {
189 if (opentbl[i].image == NULL) {
190 fd = i;
191 rbd = &opentbl[fd];
192 rbd->image_name = strdup(image_name);
193 break;
194 }
195 }
196 if (i == MAX_RBD_IMAGES || !rbd)
197 return -1;
198 int ret = rbd_open(ioctx, rbd->image_name, &(rbd->image), NULL);
199 if (ret < 0) {
200 simple_err("open_rbd_image: can't open: ", ret);
201 return ret;
202 }
203 }
204 rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info),
205 sizeof(rbd_image_info_t));
206 rbd->rbd_stat.valid = 1;
207 return fd;
208 }
209
210 static void
211 iter_images(void *cookie,
212 void (*iter)(void *cookie, const char *image))
213 {
214 struct rbd_image *im;
215
216 readdir_lock.lock();
217
218 for (im = rbd_image_data.images; im != NULL; im = im->next)
219 iter(cookie, im->image_name);
220 readdir_lock.unlock();
221 }
222
223 static void count_images_cb(void *cookie, const char *image)
224 {
225 (*((unsigned int *)cookie))++;
226 }
227
228 static int count_images(void)
229 {
230 unsigned int count = 0;
231
232 readdir_lock.lock();
233 enumerate_images(&rbd_image_data);
234 readdir_lock.unlock();
235
236 iter_images(&count, count_images_cb);
237 return count;
238 }
239
240 extern "C" {
241
242 static int rbdfs_getattr(const char *path, struct stat *stbuf)
243 {
244 int fd;
245 time_t now;
246
247 if (!gotrados)
248 return -ENXIO;
249
250 if (path[0] == 0)
251 return -ENOENT;
252
253 memset(stbuf, 0, sizeof(struct stat));
254
255 if (strcmp(path, "/") == 0) {
256
257 now = time(NULL);
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;
268
269 return 0;
270 }
271
272 if (!in_opendir) {
273 readdir_lock.lock();
274 enumerate_images(&rbd_image_data);
275 readdir_lock.unlock();
276 }
277 fd = open_rbd_image(path + 1);
278 if (fd < 0)
279 return -ENOENT;
280
281 now = time(NULL);
282 stbuf->st_mode = S_IFREG | 0666;
283 stbuf->st_nlink = 1;
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;
292
293 return 0;
294 }
295
296
297 static int rbdfs_open(const char *path, struct fuse_file_info *fi)
298 {
299 int fd;
300
301 if (!gotrados)
302 return -ENXIO;
303
304 if (path[0] == 0)
305 return -ENOENT;
306
307 readdir_lock.lock();
308 enumerate_images(&rbd_image_data);
309 readdir_lock.unlock();
310 fd = open_rbd_image(path + 1);
311 if (fd < 0)
312 return -ENOENT;
313
314 fi->fh = fd;
315 return 0;
316 }
317
318 static int rbdfs_read(const char *path, char *buf, size_t size,
319 off_t offset, struct fuse_file_info *fi)
320 {
321 size_t numread;
322 struct rbd_openimage *rbd;
323
324 if (!gotrados)
325 return -ENXIO;
326
327 rbd = &opentbl[fi->fh];
328 numread = 0;
329 while (size > 0) {
330 ssize_t ret;
331
332 ret = rbd_read(rbd->image, offset, size, buf);
333
334 if (ret <= 0)
335 break;
336 buf += ret;
337 size -= ret;
338 offset += ret;
339 numread += ret;
340 }
341
342 return numread;
343 }
344
345 static int rbdfs_write(const char *path, const char *buf, size_t size,
346 off_t offset, struct fuse_file_info *fi)
347 {
348 size_t numwritten;
349 struct rbd_openimage *rbd;
350
351 if (!gotrados)
352 return -ENXIO;
353
354 rbd = &opentbl[fi->fh];
355 numwritten = 0;
356 while (size > 0) {
357 ssize_t ret;
358
359 if ((size_t)(offset + size) > rbdsize(fi->fh)) {
360 int r;
361 fprintf(stderr, "rbdfs_write resizing %s to 0x%" PRIxMAX "\n",
362 path, offset+size);
363 r = rbd_resize(rbd->image, offset+size);
364 if (r < 0)
365 return r;
366
367 r = rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info),
368 sizeof(rbd_image_info_t));
369 if (r < 0)
370 return r;
371 }
372 ret = rbd_write(rbd->image, offset, size, buf);
373
374 if (ret < 0)
375 break;
376 buf += ret;
377 size -= ret;
378 offset += ret;
379 numwritten += ret;
380 }
381
382 return numwritten;
383 }
384
385 static void rbdfs_statfs_image_cb(void *num, const char *image)
386 {
387 int fd;
388
389 ((uint64_t *)num)[0]++;
390
391 fd = open_rbd_image(image);
392 if (fd >= 0)
393 ((uint64_t *)num)[1] += rbdsize(fd);
394 }
395
396 static int rbdfs_statfs(const char *path, struct statvfs *buf)
397 {
398 uint64_t num[2];
399
400 if (!gotrados)
401 return -ENXIO;
402
403 num[0] = 1;
404 num[1] = 0;
405 readdir_lock.lock();
406 enumerate_images(&rbd_image_data);
407 readdir_lock.unlock();
408 iter_images(num, rbdfs_statfs_image_cb);
409
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;
414 buf->f_bfree = 0;
415 buf->f_bavail = 0;
416 buf->f_files = num[0];
417 buf->f_ffree = 0;
418 buf->f_favail = 0;
419 buf->f_fsid = 0;
420 buf->f_flag = 0;
421 buf->f_namemax = PATH_MAX;
422
423 return 0;
424 }
425
426 static int rbdfs_fsync(const char *path, int datasync,
427 struct fuse_file_info *fi)
428 {
429 if (!gotrados)
430 return -ENXIO;
431 rbd_flush(opentbl[fi->fh].image);
432 return 0;
433 }
434
435 static int rbdfs_opendir(const char *path, struct fuse_file_info *fi)
436 {
437 // only one directory, so global "in_opendir" flag should be fine
438 readdir_lock.lock();
439 in_opendir++;
440 enumerate_images(&rbd_image_data);
441 readdir_lock.unlock();
442 return 0;
443 }
444
445 struct rbdfs_readdir_info {
446 void *buf;
447 fuse_fill_dir_t filler;
448 };
449
450 static void rbdfs_readdir_cb(void *_info, const char *name)
451 {
452 struct rbdfs_readdir_info *info = (struct rbdfs_readdir_info*) _info;
453
454 info->filler(info->buf, name, NULL, 0);
455 }
456
457 static int rbdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
458 off_t offset, struct fuse_file_info *fi)
459 {
460 struct rbdfs_readdir_info info = { buf, filler };
461
462 if (!gotrados)
463 return -ENXIO;
464 if (!in_opendir)
465 fprintf(stderr, "in readdir, but not inside opendir?\n");
466
467 if (strcmp(path, "/") != 0)
468 return -ENOENT;
469
470 filler(buf, ".", NULL, 0);
471 filler(buf, "..", NULL, 0);
472 iter_images(&info, rbdfs_readdir_cb);
473
474 return 0;
475 }
476 static int rbdfs_releasedir(const char *path, struct fuse_file_info *fi)
477 {
478 // see opendir comments
479 readdir_lock.lock();
480 in_opendir--;
481 readdir_lock.unlock();
482 return 0;
483 }
484
485 void *
486 rbdfs_init(struct fuse_conn_info *conn)
487 {
488 int ret;
489
490 // init cannot fail, so if we fail here, gotrados remains at 0,
491 // causing other operations to fail immediately with ENXIO
492
493 ret = connect_to_cluster(&cluster);
494 if (ret < 0)
495 exit(90);
496
497 pool_name = rbd_options.pool_name;
498 mount_image_name = rbd_options.image_name;
499 ret = rados_ioctx_create(cluster, pool_name, &ioctx);
500 if (ret < 0)
501 exit(91);
502 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
503 conn->want |= FUSE_CAP_BIG_WRITES;
504 #endif
505 gotrados = 1;
506
507 // init's return value shows up in fuse_context.private_data,
508 // also to void (*destroy)(void *); useful?
509 return NULL;
510 }
511
512 void
513 rbdfs_destroy(void *unused)
514 {
515 if (!gotrados)
516 return;
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;
521 }
522 }
523 rados_ioctx_destroy(ioctx);
524 rados_shutdown(cluster);
525 }
526
527 int
528 rbdfs_checkname(const char *checkname)
529 {
530 const char *extra[] = {"@", "/"};
531 std::string strCheckName(checkname);
532
533 if (strCheckName.empty())
534 return -EINVAL;
535
536 unsigned int sz = sizeof(extra) / sizeof(const char*);
537 for (unsigned int i = 0; i < sz; i++)
538 {
539 std::string ex(extra[i]);
540 if (std::string::npos != strCheckName.find(ex))
541 return -EINVAL;
542 }
543
544 return 0;
545 }
546
547 // return -errno on error. fi->fh is not set until open time
548
549 int
550 rbdfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
551 {
552 int r;
553 int order = imageorder;
554
555 r = rbdfs_checkname(path+1);
556 if (r != 0)
557 {
558 return r;
559 }
560
561 r = rbd_create2(ioctx, path+1, imagesize, imagefeatures, &order);
562 return r;
563 }
564
565 int
566 rbdfs_rename(const char *path, const char *destname)
567 {
568 int r;
569
570 r = rbdfs_checkname(destname+1);
571 if (r != 0)
572 {
573 return r;
574 }
575
576 if (strcmp(path, "/") == 0)
577 return -EINVAL;
578
579 return rbd_rename(ioctx, path+1, destname+1);
580 }
581
582 int
583 rbdfs_utime(const char *path, struct utimbuf *utime)
584 {
585 // called on create; not relevant
586 return 0;
587 }
588
589 int
590 rbdfs_unlink(const char *path)
591 {
592 int fd = find_openrbd(path+1);
593 if (fd != -1) {
594 struct rbd_openimage *rbd = &opentbl[fd];
595 rbd_close(rbd->image);
596 rbd->image = 0;
597 free(rbd->image_name);
598 rbd->rbd_stat.valid = 0;
599 }
600 return rbd_remove(ioctx, path+1);
601 }
602
603
604 int
605 rbdfs_truncate(const char *path, off_t size)
606 {
607 int fd;
608 int r;
609 struct rbd_openimage *rbd;
610
611 if ((fd = open_rbd_image(path+1)) < 0)
612 return -ENOENT;
613
614 rbd = &opentbl[fd];
615 fprintf(stderr, "truncate %s to %" PRIdMAX " (0x%" PRIxMAX ")\n",
616 path, size, size);
617 r = rbd_resize(rbd->image, size);
618 if (r < 0)
619 return r;
620
621 r = rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info),
622 sizeof(rbd_image_info_t));
623 if (r < 0)
624 return r;
625 return 0;
626 }
627
628 /**
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.
632 *
633 * We accept xattrs only on the root node.
634 *
635 * All values converted with strtoull, so can be expressed in any base
636 */
637
638 struct rbdfuse_attr {
639 char *attrname;
640 uint64_t *attrvalp;
641 } attrs[] = {
642 { (char*) "user.rbdfuse.imagesize", &imagesize },
643 { (char*) "user.rbdfuse.imageorder", &imageorder },
644 { (char*) "user.rbdfuse.imagefeatures", &imagefeatures },
645 { NULL, NULL }
646 };
647
648 int
649 rbdfs_setxattr(const char *path, const char *name, const char *value,
650 size_t size,
651 int flags
652 #if defined(DARWIN)
653 ,uint32_t pos
654 #endif
655 )
656 {
657 struct rbdfuse_attr *ap;
658 if (strcmp(path, "/") != 0)
659 return -EINVAL;
660
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);
666 return 0;
667 }
668 }
669 return -EINVAL;
670 }
671
672 int
673 rbdfs_getxattr(const char *path, const char *name, char *value,
674 size_t size
675 #if defined(DARWIN)
676 ,uint32_t position
677 #endif
678 )
679 {
680 struct rbdfuse_attr *ap;
681 char buf[128];
682 // allow gets on other files; ls likes to ask for things like
683 // security.*
684
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))
689 strcpy(value, buf);
690 fprintf(stderr, "rbd-fuse: get %s\n", ap->attrname);
691 return (strlen(buf));
692 }
693 }
694 return 0;
695 }
696
697 int
698 rbdfs_listxattr(const char *path, char *list, size_t len)
699 {
700 struct rbdfuse_attr *ap;
701 size_t required_len = 0;
702
703 if (strcmp(path, "/") != 0)
704 return -EINVAL;
705
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;
712 }
713 }
714 return required_len;
715 }
716
717 const static struct fuse_operations rbdfs_oper = {
718 getattr: rbdfs_getattr,
719 readlink: 0,
720 getdir: 0,
721 mknod: 0,
722 mkdir: 0,
723 unlink: rbdfs_unlink,
724 rmdir: 0,
725 symlink: 0,
726 rename: rbdfs_rename,
727 link: 0,
728 chmod: 0,
729 chown: 0,
730 truncate: rbdfs_truncate,
731 utime: rbdfs_utime,
732 open: rbdfs_open,
733 read: rbdfs_read,
734 write: rbdfs_write,
735 statfs: rbdfs_statfs,
736 flush: 0,
737 release: 0,
738 fsync: rbdfs_fsync,
739 setxattr: rbdfs_setxattr,
740 getxattr: rbdfs_getxattr,
741 listxattr: rbdfs_listxattr,
742 removexattr: 0,
743 opendir: rbdfs_opendir,
744 readdir: rbdfs_readdir,
745 releasedir: rbdfs_releasedir,
746 fsyncdir: 0,
747 init: rbdfs_init,
748 destroy: rbdfs_destroy,
749 access: 0,
750 create: rbdfs_create,
751 /* skip unimplemented */
752 };
753
754 } /* extern "C" */
755
756 enum {
757 KEY_HELP,
758 KEY_VERSION,
759 KEY_CEPH_CONFIG,
760 KEY_CEPH_CONFIG_LONG,
761 KEY_RADOS_POOLNAME,
762 KEY_RADOS_POOLNAME_LONG,
763 KEY_RBD_IMAGENAME,
764 KEY_RBD_IMAGENAME_LONG
765 };
766
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},
781 };
782
783 static void usage(const char *progname)
784 {
785 fprintf(stderr,
786 "Usage: %s mountpoint [options]\n"
787 "\n"
788 "General 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"
794 "\n", progname);
795 }
796
797 static int rbdfs_opt_proc(void *data, const char *arg, int key,
798 struct fuse_args *outargs)
799 {
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);
804 exit(1);
805 }
806
807 if (key == KEY_VERSION) {
808 fuse_opt_add_arg(outargs, "--version");
809 fuse_main(outargs->argc, outargs->argv, &rbdfs_oper, NULL);
810 exit(0);
811 }
812
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;
817 }
818 rbd_options.ceph_config = strdup(arg+2);
819 return 0;
820 }
821
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;
826 }
827 rbd_options.pool_name = strdup(arg+2);
828 return 0;
829 }
830
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;
835 }
836 rbd_options.image_name = strdup(arg+2);
837 return 0;
838 }
839
840 return 1;
841 }
842
843 void
844 simple_err(const char *msg, int err)
845 {
846 fprintf(stderr, "%s: %s\n", msg, strerror(-err));
847 return;
848 }
849
850 int
851 connect_to_cluster(rados_t *pcluster)
852 {
853 int r;
854
855 r = rados_create(pcluster, NULL);
856 if (r < 0) {
857 simple_err("Could not create cluster handle", r);
858 return r;
859 }
860 rados_conf_parse_env(*pcluster, NULL);
861 r = rados_conf_read_file(*pcluster, rbd_options.ceph_config);
862 if (r < 0) {
863 simple_err("Error reading Ceph config file", r);
864 goto failed_shutdown;
865 }
866 r = rados_connect(*pcluster);
867 if (r < 0) {
868 simple_err("Error connecting to cluster", r);
869 goto failed_shutdown;
870 }
871
872 return 0;
873
874 failed_shutdown:
875 rados_shutdown(*pcluster);
876 return r;
877 }
878
879 int main(int argc, char *argv[])
880 {
881 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
882
883 if (fuse_opt_parse(&args, &rbd_options, rbdfs_opts, rbdfs_opt_proc) == -1) {
884 exit(1);
885 }
886
887 return fuse_main(args.argc, args.argv, &rbdfs_oper, NULL);
888 }