#include "auth/Crypto.h"
#include "client/Client.h"
#include "librados/RadosClient.h"
+#include "common/async/context_pool.h"
#include "common/ceph_argparse.h"
#include "common/common_init.h"
#include "common/config.h"
#include "common/version.h"
#include "mon/MonClient.h"
#include "include/str_list.h"
+#include "include/stringify.h"
#include "messages/MMonMap.h"
#include "msg/Messenger.h"
#include "include/ceph_assert.h"
#define DEFAULT_UMASK 002
+using namespace std;
+
static mode_t umask_cb(void *);
+namespace {
+// Set things up this way so we don't start up threads until mount and
+// kill them off when the last mount goes away, but are tolerant to
+// multiple mounts of overlapping duration.
+std::shared_ptr<ceph::async::io_context_pool> get_icp(CephContext* cct)
+{
+ static std::mutex m;
+ static std::weak_ptr<ceph::async::io_context_pool> icwp;
+
+
+ std::unique_lock l(m);
+
+ auto icp = icwp.lock();
+ if (icp)
+ return icp;
+
+ icp = std::make_shared<ceph::async::io_context_pool>();
+ icwp = icp;
+ icp->start(cct->_conf.get_val<std::uint64_t>("client_asio_thread_count"));
+ return icp;
+}
+}
struct ceph_mount_info
{
mode_t umask = DEFAULT_UMASK;
+ std::shared_ptr<ceph::async::io_context_pool> icp;
public:
explicit ceph_mount_info(CephContext *cct_)
: default_perms(),
{
int ret;
- if (cct->_conf->log_early &&
- !cct->_log->is_started()) {
+ if (!cct->_log->is_started()) {
cct->_log->start();
}
+ icp = get_icp(cct);
{
- MonClient mc_bootstrap(cct);
+ MonClient mc_bootstrap(cct, icp->get_io_context());
ret = mc_bootstrap.get_monmap_and_config();
if (ret < 0)
return ret;
common_init_finish(cct);
//monmap
- monclient = new MonClient(cct);
+ monclient = new MonClient(cct, icp->get_io_context());
ret = -CEPHFS_ERROR_MON_MAP_BUILD; //defined in libcephfs.h;
if (monclient->build_initial_monmap() < 0)
goto fail;
//at last the client
ret = -CEPHFS_ERROR_NEW_CLIENT; //defined in libcephfs.h;
- client = new StandaloneClient(messenger, monclient);
+ client = new StandaloneClient(messenger, monclient, icp->get_io_context());
if (!client)
goto fail;
delete messenger;
messenger = nullptr;
}
+ icp.reset();
if (monclient) {
delete monclient;
monclient = nullptr;
int conf_parse_argv(int argc, const char **argv)
{
- int ret;
- vector<const char*> args;
- argv_to_vec(argc, argv, args);
- ret = cct->_conf.parse_argv(args);
+ auto args = argv_to_vec(argc, argv);
+ int ret = cct->_conf.parse_argv(args);
if (ret)
return ret;
cct->_conf.apply_changes(nullptr);
return cmount->conf_get(option, buf, len);
}
+extern "C" int ceph_set_mount_timeout(struct ceph_mount_info *cmount, uint32_t timeout) {
+ if (cmount->is_mounted()) {
+ return -EINVAL;
+ }
+
+ auto timeout_str = stringify(timeout);
+ return ceph_conf_set(cmount, "client_mount_timeout", timeout_str.c_str());
+}
+
extern "C" int ceph_mds_command(struct ceph_mount_info *cmount,
const char *mds_spec,
const char **cmd,
return cmount->get_client()->opendir(name, (dir_result_t **)dirpp, cmount->default_perms);
}
+extern "C" int ceph_fdopendir(struct ceph_mount_info *cmount, int dirfd,
+ struct ceph_dir_result **dirpp)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->fdopendir(dirfd, (dir_result_t **)dirpp, cmount->default_perms);
+}
+
extern "C" int ceph_closedir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp)
{
if (!cmount->is_mounted())
cmount->get_client()->seekdir(reinterpret_cast<dir_result_t*>(dirp), offset);
}
+extern "C" int ceph_may_delete(struct ceph_mount_info *cmount, const char *path)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->may_delete(path, cmount->default_perms);
+}
+
extern "C" int ceph_link (struct ceph_mount_info *cmount, const char *existing,
const char *newname)
{
return cmount->get_client()->unlink(path, cmount->default_perms);
}
+extern "C" int ceph_unlinkat(struct ceph_mount_info *cmount, int dirfd, const char *relpath, int flags)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->unlinkat(dirfd, relpath, flags, cmount->default_perms);
+}
+
extern "C" int ceph_rename(struct ceph_mount_info *cmount, const char *from,
const char *to)
{
return cmount->get_client()->mkdir(path, mode, cmount->default_perms);
}
+extern "C" int ceph_mkdirat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ mode_t mode)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->mkdirat(dirfd, relpath, mode, cmount->default_perms);
+}
+
+extern "C" int ceph_mksnap(struct ceph_mount_info *cmount, const char *path, const char *name,
+ mode_t mode, struct snap_metadata *snap_metadata, size_t nr_snap_metadata)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ size_t i = 0;
+ std::map<std::string, std::string> metadata;
+ while (i < nr_snap_metadata) {
+ metadata.emplace(snap_metadata[i].key, snap_metadata[i].value);
+ ++i;
+ }
+ return cmount->get_client()->mksnap(path, name, cmount->default_perms, mode, metadata);
+}
+
+extern "C" int ceph_rmsnap(struct ceph_mount_info *cmount, const char *path, const char *name)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->rmsnap(path, name, cmount->default_perms, true);
+}
+
extern "C" int ceph_mkdirs(struct ceph_mount_info *cmount, const char *path, mode_t mode)
{
if (!cmount->is_mounted())
return cmount->get_client()->readlink(path, buf, size, cmount->default_perms);
}
+extern "C" int ceph_readlinkat(struct ceph_mount_info *cmount, int dirfd,
+ const char *relpath, char *buf, int64_t size)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->readlinkat(dirfd, relpath, buf, size, cmount->default_perms);
+}
+
extern "C" int ceph_symlink(struct ceph_mount_info *cmount, const char *existing,
const char *newname)
{
return cmount->get_client()->symlink(existing, newname, cmount->default_perms);
}
+extern "C" int ceph_symlinkat(struct ceph_mount_info *cmount, const char *existing, int dirfd,
+ const char *newname)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->symlinkat(existing, dirfd, newname, cmount->default_perms);
+}
+
extern "C" int ceph_fstatx(struct ceph_mount_info *cmount, int fd, struct ceph_statx *stx,
unsigned int want, unsigned int flags)
{
want, flags);
}
+extern "C" int ceph_statxat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ struct ceph_statx *stx, unsigned int want, unsigned int flags)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ if (flags & ~CEPH_REQ_FLAG_MASK)
+ return -EINVAL;
+ return cmount->get_client()->statxat(dirfd, relpath, stx, cmount->default_perms,
+ want, flags);
+}
+
extern "C" int ceph_statx(struct ceph_mount_info *cmount, const char *path,
struct ceph_statx *stx, unsigned int want, unsigned int flags)
{
return -ENOTCONN;
return cmount->get_client()->chmod(path, mode, cmount->default_perms);
}
+extern "C" int ceph_lchmod(struct ceph_mount_info *cmount, const char *path, mode_t mode)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->lchmod(path, mode, cmount->default_perms);
+}
extern "C" int ceph_fchmod(struct ceph_mount_info *cmount, int fd, mode_t mode)
{
if (!cmount->is_mounted())
return -ENOTCONN;
return cmount->get_client()->fchmod(fd, mode, cmount->default_perms);
}
+
+extern "C" int ceph_chmodat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ mode_t mode, int flags) {
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->chmodat(dirfd, relpath, mode, flags, cmount->default_perms);
+}
+
extern "C" int ceph_chown(struct ceph_mount_info *cmount, const char *path,
int uid, int gid)
{
return cmount->get_client()->lchown(path, uid, gid, cmount->default_perms);
}
+extern "C" int ceph_chownat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ uid_t uid, gid_t gid, int flags) {
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->chownat(dirfd, relpath, uid, gid, flags, cmount->default_perms);
+}
extern "C" int ceph_utime(struct ceph_mount_info *cmount, const char *path,
struct utimbuf *buf)
return cmount->get_client()->futimens(fd, times, cmount->default_perms);
}
+extern "C" int ceph_utimensat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ struct timespec times[2], int flags) {
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->utimensat(dirfd, relpath, times, flags, cmount->default_perms);
+}
+
extern "C" int ceph_flock(struct ceph_mount_info *cmount, int fd, int operation,
uint64_t owner)
{
return cmount->get_client()->open(path, flags, cmount->default_perms, mode);
}
+extern "C" int ceph_openat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ int flags, mode_t mode)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->openat(dirfd, relpath, flags, cmount->default_perms, mode);
+}
+
extern "C" int ceph_open_layout(struct ceph_mount_info *cmount, const char *path, int flags,
mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool)
{
}
+extern "C" int ceph_ll_lookup_vino(
+ struct ceph_mount_info *cmount,
+ vinodeno_t vino,
+ Inode **inode)
+{
+ return (cmount->get_client())->ll_lookup_vino(vino, cmount->default_perms, inode);
+}
+
/**
* Populates the client cache with the requested inode, and its
* parent dentry.
cmount->get_client()->finish_reclaim();
}
+// This is deprecated, use ceph_ll_register_callbacks2 instead.
extern "C" void ceph_ll_register_callbacks(class ceph_mount_info *cmount,
struct ceph_client_callback_args *args)
{
cmount->get_client()->ll_register_callbacks(args);
}
+
+extern "C" int ceph_ll_register_callbacks2(class ceph_mount_info *cmount,
+ struct ceph_client_callback_args *args)
+{
+ return cmount->get_client()->ll_register_callbacks2(args);
+}
+
+
+extern "C" int ceph_get_snap_info(struct ceph_mount_info *cmount,
+ const char *path, struct snap_info *snap_info) {
+ Client::SnapInfo info;
+ int r = cmount->get_client()->get_snap_info(path, cmount->default_perms, &info);
+ if (r < 0) {
+ return r;
+ }
+
+ size_t i = 0;
+ auto nr_metadata = info.metadata.size();
+
+ snap_info->id = info.id.val;
+ snap_info->nr_snap_metadata = nr_metadata;
+ if (nr_metadata) {
+ snap_info->snap_metadata = (struct snap_metadata *)calloc(nr_metadata, sizeof(struct snap_metadata));
+ if (!snap_info->snap_metadata) {
+ return -ENOMEM;
+ }
+
+ // fill with key, value pairs
+ for (auto &[key, value] : info.metadata) {
+ // len(key) + '\0' + len(value) + '\0'
+ char *kvp = (char *)malloc(key.size() + value.size() + 2);
+ if (!kvp) {
+ break;
+ }
+ char *_key = kvp;
+ char *_value = kvp + key.size() + 1;
+
+ memcpy(_key, key.c_str(), key.size());
+ _key[key.size()] = '\0';
+ memcpy(_value, value.c_str(), value.size());
+ _value[value.size()] = '\0';
+
+ snap_info->snap_metadata[i].key = _key;
+ snap_info->snap_metadata[i].value = _value;
+ ++i;
+ }
+ }
+
+ if (nr_metadata && i != nr_metadata) {
+ ceph_free_snap_info_buffer(snap_info);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+extern "C" void ceph_free_snap_info_buffer(struct snap_info *snap_info) {
+ for (size_t i = 0; i < snap_info->nr_snap_metadata; ++i) {
+ free((void *)snap_info->snap_metadata[i].key); // malloc'd memory is key+value composite
+ }
+ free(snap_info->snap_metadata);
+}