]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/rbd_fuse/rbd-fuse.cc
import ceph quincy 17.2.4
[ceph.git] / ceph / src / rbd_fuse / rbd-fuse.cc
index 6295097ca7fce5a868943137b012886067960e9c..12e30ceb04c61d638eae810d6d219a8e34492172 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * rbd-fuse
  */
-#define FUSE_USE_VERSION 30
-
 #include "include/int_types.h"
 
 #include <stdio.h>
@@ -11,7 +9,6 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <fuse.h>
 #include <pthread.h>
 #include <string.h>
 #include <sys/types.h>
@@ -20,6 +17,7 @@
 #include <assert.h>
 #include <string>
 #include <mutex>
+#include <limits.h>
 
 #if defined(__FreeBSD__)
 #include <sys/param.h>
 
 #include "include/compat.h"
 #include "include/rbd/librbd.h"
+#include "include/ceph_assert.h"
+
+#include "common/ceph_argparse.h"
+#include "common/ceph_context.h"
+#include "include/ceph_fuse.h"
+
+#include "global/global_init.h"
+#include "global/global_context.h"
 
 static int gotrados = 0;
 char *pool_name;
+char *nspace_name;
 char *mount_image_name;
 rados_t cluster;
 rados_ioctx_t ioctx;
@@ -42,8 +49,8 @@ struct rbd_stat {
 };
 
 struct rbd_options {
-       char *ceph_config;
        char *pool_name;
+       char *nspace_name;
        char *image_name;
 };
 
@@ -52,8 +59,9 @@ struct rbd_image {
        struct rbd_image *next;
 };
 struct rbd_image_data {
-    struct rbd_image *images;
-    void *buf;
+       struct rbd_image *images;
+       rbd_image_spec_t *image_specs;
+       size_t image_spec_count;
 };
 struct rbd_image_data rbd_image_data;
 
@@ -65,8 +73,7 @@ struct rbd_openimage {
 #define MAX_RBD_IMAGES         128
 struct rbd_openimage opentbl[MAX_RBD_IMAGES];
 
-struct rbd_options rbd_options = {(char*) "/etc/ceph/ceph.conf", (char*) "rbd",
-                                 NULL};
+struct rbd_options rbd_options = {(char*) "rbd", (char*) "", NULL};
 
 #define rbdsize(fd)    opentbl[fd].rbd_stat.rbd_info.size
 #define rbdblksize(fd) opentbl[fd].rbd_stat.rbd_info.obj_size
@@ -91,10 +98,7 @@ void
 enumerate_images(struct rbd_image_data *data)
 {
        struct rbd_image **head = &data->images;
-       char *ibuf = NULL;
-       size_t ibuf_len = 0;
        struct rbd_image *im, *next;
-       char *ip;
        int ret;
 
        if (*head != NULL) {
@@ -104,45 +108,44 @@ enumerate_images(struct rbd_image_data *data)
                        im = next;
                }
                *head = NULL;
-               free(data->buf);
-               data->buf = NULL;
+               rbd_image_spec_list_cleanup(data->image_specs,
+                                           data->image_spec_count);
+               free(data->image_specs);
+               data->image_specs = NULL;
+               data->image_spec_count = 0;
        }
 
-       ret = rbd_list(ioctx, ibuf, &ibuf_len);
-       if (ret == -ERANGE) {
-               assert(ibuf_len > 0);
-               ibuf = (char*) malloc(ibuf_len);
-               if (!ibuf) {
-                       simple_err("Failed to get ibuf", -ENOMEM);
-                       return;
+       while (true) {
+               ret = rbd_list2(ioctx, data->image_specs,
+                               &data->image_spec_count);
+               if (ret == -ERANGE) {
+                       data->image_specs = static_cast<rbd_image_spec_t *>(
+                               realloc(data->image_specs,
+                                       sizeof(rbd_image_spec_t) * data->image_spec_count));
+               } else if (ret < 0) {
+                       simple_err("Failed to list images", ret);
+               } else {
+                       break;
                }
-       } else if (ret < 0) {
-               simple_err("Failed to get ibuf_len", ret);
-               return;
        }
 
-       ret = rbd_list(ioctx, ibuf, &ibuf_len);
-       if (ret < 0) {
-               simple_err("Failed to populate ibuf", ret);
-               free(ibuf);
-               return;
+       if (*nspace_name != '\0') {
+           fprintf(stderr, "pool/namespace %s/%s: ", pool_name, nspace_name);
+       } else {
+           fprintf(stderr, "pool %s: ", pool_name);
        }
-       assert(ret == (int)ibuf_len);
-
-       fprintf(stderr, "pool %s: ", pool_name);
-       for (ip = ibuf; ip < &ibuf[ibuf_len]; ip += strlen(ip) + 1)  {
+       for (size_t idx = 0; idx < data->image_spec_count; ++idx) {
                if ((mount_image_name == NULL) ||
                    ((strlen(mount_image_name) > 0) &&
-                   (strcmp(ip, mount_image_name) == 0))) {
-                       fprintf(stderr, "%s, ", ip);
+                   (strcmp(data->image_specs[idx].name, mount_image_name) == 0))) {
+                       fprintf(stderr, "%s, ", data->image_specs[idx].name);
                        im = static_cast<rbd_image*>(malloc(sizeof(*im)));
-                       im->image_name = ip;
+                       im->image_name = data->image_specs[idx].name;
                        im->next = *head;
                        *head = im;
                }
        }
        fprintf(stderr, "\n");
-       data->buf = ibuf;
 }
 
 int
@@ -239,7 +242,11 @@ static int count_images(void)
 
 extern "C" {
 
-static int rbdfs_getattr(const char *path, struct stat *stbuf)
+static int rbdfs_getattr(const char *path, struct stat *stbuf
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                         , struct fuse_file_info *fi
+#endif
+                        )
 {
        int fd;
        time_t now;
@@ -451,11 +458,15 @@ static void rbdfs_readdir_cb(void *_info, const char *name)
 {
        struct rbdfs_readdir_info *info = (struct rbdfs_readdir_info*) _info;
 
-       info->filler(info->buf, name, NULL, 0);
+        filler_compat(info->filler, info->buf, name, NULL, 0);
 }
 
 static int rbdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
-                          off_t offset, struct fuse_file_info *fi)
+                        off_t offset, struct fuse_file_info *fi
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                         , enum fuse_readdir_flags
+#endif
+                         )
 {
        struct rbdfs_readdir_info info = { buf, filler };
 
@@ -467,8 +478,8 @@ static int rbdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
        if (strcmp(path, "/") != 0)
                return -ENOENT;
 
-       filler(buf, ".", NULL, 0);
-       filler(buf, "..", NULL, 0);
+       filler_compat(filler, buf, ".", NULL, 0);
+       filler_compat(filler, buf, "..", NULL, 0);
        iter_images(&info, rbdfs_readdir_cb);
 
        return 0;
@@ -483,7 +494,11 @@ static int rbdfs_releasedir(const char *path, struct fuse_file_info *fi)
 }
 
 void *
-rbdfs_init(struct fuse_conn_info *conn)
+rbdfs_init(struct fuse_conn_info *conn
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+           , struct fuse_config *cfg
+#endif
+          )
 {
        int ret;
 
@@ -495,13 +510,15 @@ rbdfs_init(struct fuse_conn_info *conn)
                exit(90);
 
        pool_name = rbd_options.pool_name;
+       nspace_name = rbd_options.nspace_name;
        mount_image_name = rbd_options.image_name;
        ret = rados_ioctx_create(cluster, pool_name, &ioctx);
        if (ret < 0)
                exit(91);
-#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) && FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
        conn->want |= FUSE_CAP_BIG_WRITES;
 #endif
+       rados_ioctx_set_namespace(ioctx, nspace_name);
        gotrados = 1;
 
        // init's return value shows up in fuse_context.private_data,
@@ -563,7 +580,11 @@ rbdfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
 }
 
 int
-rbdfs_rename(const char *path, const char *destname)
+rbdfs_rename(const char *path, const char *destname
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+             , unsigned int flags
+#endif
+            )
 {
     int r;
 
@@ -580,7 +601,11 @@ rbdfs_rename(const char *path, const char *destname)
 }
 
 int
-rbdfs_utime(const char *path, struct utimbuf *utime)
+rbdfs_utimens(const char *path, const struct timespec tv[2]
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+              , struct fuse_file_info *fi
+#endif
+             )
 {
        // called on create; not relevant
        return 0;
@@ -602,7 +627,11 @@ rbdfs_unlink(const char *path)
 
 
 int
-rbdfs_truncate(const char *path, off_t size)
+rbdfs_truncate(const char *path, off_t size
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+               , struct fuse_file_info *fi
+#endif
+              )
 {
        int fd;
        int r;
@@ -717,7 +746,9 @@ rbdfs_listxattr(const char *path, char *list, size_t len)
 const static struct fuse_operations rbdfs_oper = {
   getattr:    rbdfs_getattr,
   readlink:   0,
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
   getdir:     0,
+#endif
   mknod:      0,
   mkdir:      0,
   unlink:     rbdfs_unlink,
@@ -728,7 +759,9 @@ const static struct fuse_operations rbdfs_oper = {
   chmod:      0,
   chown:      0,
   truncate:   rbdfs_truncate,
-  utime:      rbdfs_utime,
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
+  utime:      0,
+#endif
   open:              rbdfs_open,
   read:              rbdfs_read,
   write:      rbdfs_write,
@@ -748,6 +781,12 @@ const static struct fuse_operations rbdfs_oper = {
   destroy:    rbdfs_destroy,
   access:     0,
   create:     rbdfs_create,
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
+  ftruncate:  0,
+  fgetattr:   0,
+#endif
+  lock:       0,
+  utimens:    rbdfs_utimens,
   /* skip unimplemented */
 };
 
@@ -756,10 +795,10 @@ const static struct fuse_operations rbdfs_oper = {
 enum {
        KEY_HELP,
        KEY_VERSION,
-       KEY_CEPH_CONFIG,
-       KEY_CEPH_CONFIG_LONG,
        KEY_RADOS_POOLNAME,
        KEY_RADOS_POOLNAME_LONG,
+       KEY_RADOS_NSPACENAME,
+       KEY_RADOS_NSPACENAME_LONG,
        KEY_RBD_IMAGENAME,
        KEY_RBD_IMAGENAME_LONG
 };
@@ -769,15 +808,16 @@ static struct fuse_opt rbdfs_opts[] = {
        FUSE_OPT_KEY("--help", KEY_HELP),
        FUSE_OPT_KEY("-V", KEY_VERSION),
        FUSE_OPT_KEY("--version", KEY_VERSION),
-       {"-c %s", offsetof(struct rbd_options, ceph_config), KEY_CEPH_CONFIG},
-       {"--configfile=%s", offsetof(struct rbd_options, ceph_config),
-        KEY_CEPH_CONFIG_LONG},
        {"-p %s", offsetof(struct rbd_options, pool_name), KEY_RADOS_POOLNAME},
        {"--poolname=%s", offsetof(struct rbd_options, pool_name),
         KEY_RADOS_POOLNAME_LONG},
+       {"-s %s", offsetof(struct rbd_options, nspace_name), KEY_RADOS_NSPACENAME},
+       {"--namespace=%s", offsetof(struct rbd_options, nspace_name),
+        KEY_RADOS_NSPACENAME_LONG},
        {"-r %s", offsetof(struct rbd_options, image_name), KEY_RBD_IMAGENAME},
        {"--image=%s", offsetof(struct rbd_options, image_name),
        KEY_RBD_IMAGENAME_LONG},
+       FUSE_OPT_END
 };
 
 static void usage(const char *progname)
@@ -788,8 +828,9 @@ static void usage(const char *progname)
 "General options:\n"
 "    -h   --help            print help\n"
 "    -V   --version         print version\n"
-"    -c   --configfile      ceph configuration file [/etc/ceph/ceph.conf]\n"
+"    -c   --conf            ceph configuration file [/etc/ceph/ceph.conf]\n"
 "    -p   --poolname        rados pool name [rbd]\n"
+"    -s   --namespace       rados namespace name []\n"
 "    -r   --image           RBD image name\n"
 "\n", progname);
 }
@@ -810,15 +851,6 @@ static int rbdfs_opt_proc(void *data, const char *arg, int key,
                exit(0);
        }
 
-       if (key == KEY_CEPH_CONFIG) {
-               if (rbd_options.ceph_config != NULL) {
-                       free(rbd_options.ceph_config);
-                       rbd_options.ceph_config = NULL;
-               }
-               rbd_options.ceph_config = strdup(arg+2);
-               return 0;
-       }
-
        if (key == KEY_RADOS_POOLNAME) {
                if (rbd_options.pool_name != NULL) {
                        free(rbd_options.pool_name);
@@ -828,6 +860,15 @@ static int rbdfs_opt_proc(void *data, const char *arg, int key,
                return 0;
        }
 
+       if (key == KEY_RADOS_NSPACENAME) {
+               if (rbd_options.nspace_name != NULL) {
+                       free(rbd_options.nspace_name);
+                       rbd_options.nspace_name = NULL;
+               }
+               rbd_options.nspace_name = strdup(arg+2);
+               return 0;
+       }
+
        if (key == KEY_RBD_IMAGENAME) {
                if (rbd_options.image_name!= NULL) {
                        free(rbd_options.image_name);
@@ -851,36 +892,74 @@ int
 connect_to_cluster(rados_t *pcluster)
 {
        int r;
+       global_init_postfork_start(g_ceph_context);
+       common_init_finish(g_ceph_context);
+       global_init_postfork_finish(g_ceph_context);
 
-       r = rados_create(pcluster, NULL);
+       r = rados_create_with_context(pcluster, g_ceph_context);
        if (r < 0) {
                simple_err("Could not create cluster handle", r);
                return r;
        }
-       rados_conf_parse_env(*pcluster, NULL);
-       r = rados_conf_read_file(*pcluster, rbd_options.ceph_config);
-       if (r < 0) {
-               simple_err("Error reading Ceph config file", r);
-               goto failed_shutdown;
-       }
+
        r = rados_connect(*pcluster);
        if (r < 0) {
                simple_err("Error connecting to cluster", r);
-               goto failed_shutdown;
+               rados_shutdown(*pcluster);
+               return r;
        }
 
        return 0;
-
-failed_shutdown:
-       rados_shutdown(*pcluster);
-       return r;
 }
 
-int main(int argc, char *argv[])
+#define OPT_NOT_FOUND -1
+
+int main(int argc, const char *argv[])
 {
-       struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+       memset(&rbd_image_data, 0, sizeof(rbd_image_data));
+
+       // librados will filter out -r/-f/-d options from command-line
+       std::map<std::string, int> filter_options = {
+               {"-r", OPT_NOT_FOUND},
+               {"-f", OPT_NOT_FOUND},
+               {"-d", OPT_NOT_FOUND}};
+
+       std::set<std::string> require_arg_options = {"-r"};
+
+       std::vector<const char*> arg_vector;
+       for (auto idx = 0; idx < argc; ++idx) {
+               auto it = filter_options.find(argv[idx]);
+               if (it != filter_options.end()) {
+                       it->second = idx;
+               }
+               arg_vector.push_back(argv[idx]);
+       }
+
+       auto cct = global_init(NULL, arg_vector, CEPH_ENTITY_TYPE_CLIENT,
+                              CODE_ENVIRONMENT_DAEMON,
+                              CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS);
+       g_ceph_context->_conf.set_val_or_die("pid_file", "");
+       g_ceph_context->_conf.set_val_or_die("daemonize", "true");
+
+       if (global_init_prefork(g_ceph_context) < 0) {
+               fprintf(stderr, "Failed to initialize librados\n");
+               exit(1);
+       }
+
+       for (auto& it : filter_options) {
+               if (it.second != OPT_NOT_FOUND) {
+                       arg_vector.push_back(it.first.c_str());
+                       if (require_arg_options.count(it.first) &&
+                           it.second + 1 < argc) {
+                               arg_vector.push_back(argv[it.second + 1]);
+                       }
+               }
+       }
 
-       if (fuse_opt_parse(&args, &rbd_options, rbdfs_opts, rbdfs_opt_proc) == -1) {
+       struct fuse_args args = FUSE_ARGS_INIT((int)arg_vector.size(),
+                                              (char**)&arg_vector.front());
+       if (fuse_opt_parse(&args, &rbd_options, rbdfs_opts,
+                          rbdfs_opt_proc) == -1) {
                exit(1);
        }