/*
* rbd-fuse
*/
-#define FUSE_USE_VERSION 30
-
#include "include/int_types.h"
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <fuse.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <getopt.h>
#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 "common/Mutex.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;
-Mutex readdir_lock("read_dir");
+std::mutex readdir_lock;
struct rbd_stat {
u_char valid;
};
struct rbd_options {
- char *ceph_config;
char *pool_name;
+ char *nspace_name;
char *image_name;
};
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;
#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
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) {
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
{
struct rbd_image *im;
- readdir_lock.Lock();
-
+ readdir_lock.lock();
+
for (im = rbd_image_data.images; im != NULL; im = im->next)
iter(cookie, im->image_name);
- readdir_lock.Unlock();
+ readdir_lock.unlock();
}
static void count_images_cb(void *cookie, const char *image)
{
unsigned int count = 0;
- readdir_lock.Lock();
+ readdir_lock.lock();
enumerate_images(&rbd_image_data);
- readdir_lock.Unlock();
+ readdir_lock.unlock();
iter_images(&count, count_images_cb);
return count;
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;
}
if (!in_opendir) {
- readdir_lock.Lock();
+ readdir_lock.lock();
enumerate_images(&rbd_image_data);
- readdir_lock.Unlock();
+ readdir_lock.unlock();
}
fd = open_rbd_image(path + 1);
if (fd < 0)
if (path[0] == 0)
return -ENOENT;
- readdir_lock.Lock();
+ readdir_lock.lock();
enumerate_images(&rbd_image_data);
- readdir_lock.Unlock();
+ readdir_lock.unlock();
fd = open_rbd_image(path + 1);
if (fd < 0)
return -ENOENT;
num[0] = 1;
num[1] = 0;
- readdir_lock.Lock();
+ readdir_lock.lock();
enumerate_images(&rbd_image_data);
- readdir_lock.Unlock();
+ readdir_lock.unlock();
iter_images(num, rbdfs_statfs_image_cb);
#define RBDFS_BSIZE 4096
static int rbdfs_opendir(const char *path, struct fuse_file_info *fi)
{
// only one directory, so global "in_opendir" flag should be fine
- readdir_lock.Lock();
+ readdir_lock.lock();
in_opendir++;
enumerate_images(&rbd_image_data);
- readdir_lock.Unlock();
+ readdir_lock.unlock();
return 0;
}
{
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 };
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;
static int rbdfs_releasedir(const char *path, struct fuse_file_info *fi)
{
// see opendir comments
- readdir_lock.Lock();
+ readdir_lock.lock();
in_opendir--;
- readdir_lock.Unlock();
+ readdir_lock.unlock();
return 0;
}
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;
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,
}
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;
}
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;
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;
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,
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,
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 */
};
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
};
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)
"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);
}
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);
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);
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);
}