summaryrefslogtreecommitdiffstats
path: root/src/libcephfs_proxy/libcephfs_proxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcephfs_proxy/libcephfs_proxy.c')
-rw-r--r--src/libcephfs_proxy/libcephfs_proxy.c869
1 files changed, 869 insertions, 0 deletions
diff --git a/src/libcephfs_proxy/libcephfs_proxy.c b/src/libcephfs_proxy/libcephfs_proxy.c
new file mode 100644
index 00000000000..149fae123f7
--- /dev/null
+++ b/src/libcephfs_proxy/libcephfs_proxy.c
@@ -0,0 +1,869 @@
+
+#include <stdlib.h>
+
+#include "include/cephfs/libcephfs.h"
+
+#include "proxy_log.h"
+#include "proxy_helpers.h"
+#include "proxy_requests.h"
+
+/* We override the definition of the ceph_mount_info structure to contain
+ * internal proxy information. This is already a black box for libcephfs users,
+ * so this won't be noticed. */
+struct ceph_mount_info {
+ proxy_link_t link;
+ uint64_t cmount;
+};
+
+/* The global_cmount is used to stablish an initial connection to serve requests
+ * not related to a real cmount, like ceph_version or ceph_userperm_new. */
+static struct ceph_mount_info global_cmount = { PROXY_LINK_DISCONNECTED, 0 };
+
+static bool client_stop(proxy_link_t *link)
+{
+ return false;
+}
+
+static int32_t proxy_connect(proxy_link_t *link)
+{
+ CEPH_REQ(hello, req, 0, ans, 0);
+ char *path, *env;
+ int32_t sd, err;
+
+ path = PROXY_SOCKET;
+ env = getenv(PROXY_SOCKET_ENV);
+ if (env != NULL) {
+ path = env;
+ }
+
+ sd = proxy_link_client(link, path, client_stop);
+ if (sd < 0) {
+ return sd;
+ }
+
+ req.id = LIBCEPHFS_LIB_CLIENT;
+ err = proxy_link_send(sd, req_iov, 1);
+ if (err < 0) {
+ goto failed;
+ }
+ err = proxy_link_recv(sd, ans_iov, 1);
+ if (err < 0) {
+ goto failed;
+ }
+
+ proxy_log(LOG_INFO, 0, "Connected to libcephfsd version %d.%d",
+ ans.major, ans.minor);
+
+ if ((ans.major != LIBCEPHFSD_MAJOR) ||
+ (ans.minor != LIBCEPHFSD_MINOR)) {
+ err = proxy_log(LOG_ERR, ENOTSUP, "Version not supported");
+ goto failed;
+ }
+
+ return sd;
+
+failed:
+ proxy_link_close(link);
+
+ return err;
+}
+
+static void proxy_disconnect(proxy_link_t *link)
+{
+ proxy_link_close(link);
+}
+
+static int32_t proxy_global_connect(void)
+{
+ int32_t err;
+
+ err = 0;
+
+ if (!proxy_link_is_connected(&global_cmount.link)) {
+ err = proxy_connect(&global_cmount.link);
+ }
+
+ return err;
+}
+
+static int32_t proxy_check(struct ceph_mount_info *cmount, int32_t err,
+ int32_t result)
+{
+ if (err < 0) {
+ proxy_disconnect(&cmount->link);
+ proxy_log(LOG_ERR, err, "Disconnected from libcephfsd");
+
+ return err;
+ }
+
+ return result;
+}
+
+/* Macros to simplify communication with the server. */
+#define CEPH_RUN(_cmount, _op, _req, _ans) \
+ ({ \
+ int32_t __err = \
+ CEPH_CALL((_cmount)->link.sd, _op, _req, _ans); \
+ __err = proxy_check(_cmount, __err, (_ans).header.result); \
+ __err; \
+ })
+
+#define CEPH_PROCESS(_cmount, _op, _req, _ans) \
+ ({ \
+ int32_t __err = -ENOTCONN; \
+ if (proxy_link_is_connected(&(_cmount)->link)) { \
+ (_req).cmount = (_cmount)->cmount; \
+ __err = CEPH_RUN(_cmount, _op, _req, _ans); \
+ } \
+ __err; \
+ })
+
+__public int ceph_chdir(struct ceph_mount_info *cmount, const char *path)
+{
+ CEPH_REQ(ceph_chdir, req, 1, ans, 0);
+
+ CEPH_STR_ADD(req, path, path);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_CHDIR, req, ans);
+}
+
+__public int ceph_conf_get(struct ceph_mount_info *cmount, const char *option,
+ char *buf, size_t len)
+{
+ CEPH_REQ(ceph_conf_get, req, 1, ans, 1);
+
+ req.size = len;
+
+ CEPH_STR_ADD(req, option, option);
+ CEPH_BUFF_ADD(ans, buf, len);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_CONF_GET, req, ans);
+}
+
+__public int ceph_conf_read_file(struct ceph_mount_info *cmount,
+ const char *path_list)
+{
+ CEPH_REQ(ceph_conf_read_file, req, 1, ans, 0);
+
+ CEPH_STR_ADD(req, path, path_list);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_CONF_READ_FILE, req, ans);
+}
+
+__public int ceph_conf_set(struct ceph_mount_info *cmount, const char *option,
+ const char *value)
+{
+ CEPH_REQ(ceph_conf_set, req, 2, ans, 0);
+
+ CEPH_STR_ADD(req, option, option);
+ CEPH_STR_ADD(req, value, value);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_CONF_SET, req, ans);
+}
+
+__public int ceph_create(struct ceph_mount_info **cmount, const char *const id)
+{
+ CEPH_REQ(ceph_create, req, 1, ans, 0);
+ struct ceph_mount_info *ceph_mount;
+ int32_t sd, err;
+
+ ceph_mount = proxy_malloc(sizeof(struct ceph_mount_info));
+ if (ceph_mount == NULL) {
+ return -ENOMEM;
+ }
+
+ err = proxy_connect(&ceph_mount->link);
+ if (err < 0) {
+ goto failed;
+ }
+ sd = err;
+
+ CEPH_STR_ADD(req, id, id);
+
+ err = CEPH_CALL(sd, LIBCEPHFSD_OP_CREATE, req, ans);
+ if ((err < 0) || ((err = ans.header.result) < 0)) {
+ goto failed_link;
+ }
+
+ ceph_mount->cmount = ans.cmount;
+
+ *cmount = ceph_mount;
+
+ return 0;
+
+failed_link:
+ proxy_disconnect(&ceph_mount->link);
+
+failed:
+ proxy_free(ceph_mount);
+
+ return err;
+}
+
+__public const char *ceph_getcwd(struct ceph_mount_info *cmount)
+{
+ static char cwd[PATH_MAX];
+ int32_t err;
+
+ CEPH_REQ(ceph_getcwd, req, 0, ans, 1);
+
+ CEPH_BUFF_ADD(ans, cwd, sizeof(cwd));
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_GETCWD, req, ans);
+ if (err >= 0) {
+ return cwd;
+ }
+
+ errno = -err;
+
+ return NULL;
+}
+
+__public int ceph_init(struct ceph_mount_info *cmount)
+{
+ CEPH_REQ(ceph_init, req, 0, ans, 0);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_INIT, req, ans);
+}
+
+__public int ceph_ll_close(struct ceph_mount_info *cmount,
+ struct Fh *filehandle)
+{
+ CEPH_REQ(ceph_ll_close, req, 0, ans, 0);
+
+ req.fh = ptr_value(filehandle);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_CLOSE, req, ans);
+}
+
+__public int ceph_ll_create(struct ceph_mount_info *cmount, Inode *parent,
+ const char *name, mode_t mode, int oflags,
+ Inode **outp, Fh **fhp, struct ceph_statx *stx,
+ unsigned want, unsigned lflags,
+ const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_create, req, 1, ans, 1);
+ int32_t err;
+
+ req.userperm = ptr_value(perms);
+ req.parent = ptr_value(parent);
+ req.mode = mode;
+ req.oflags = oflags;
+ req.want = want;
+ req.flags = lflags;
+
+ CEPH_STR_ADD(req, name, name);
+ CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_CREATE, req, ans);
+ if (err >= 0) {
+ *outp = value_ptr(ans.inode);
+ *fhp = value_ptr(ans.fh);
+ }
+
+ return err;
+}
+
+__public int ceph_ll_fallocate(struct ceph_mount_info *cmount, struct Fh *fh,
+ int mode, int64_t offset, int64_t length)
+{
+ CEPH_REQ(ceph_ll_fallocate, req, 0, ans, 0);
+
+ req.fh = ptr_value(fh);
+ req.mode = mode;
+ req.offset = offset;
+ req.length = length;
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_FALLOCATE, req, ans);
+}
+
+__public int ceph_ll_fsync(struct ceph_mount_info *cmount, struct Fh *fh,
+ int syncdataonly)
+{
+ CEPH_REQ(ceph_ll_fsync, req, 0, ans, 0);
+
+ req.fh = ptr_value(fh);
+ req.dataonly = syncdataonly;
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_FSYNC, req, ans);
+}
+
+__public int ceph_ll_getattr(struct ceph_mount_info *cmount, struct Inode *in,
+ struct ceph_statx *stx, unsigned int want,
+ unsigned int flags, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_getattr, req, 0, ans, 1);
+
+ req.userperm = ptr_value(perms);
+ req.inode = ptr_value(in);
+ req.want = want;
+ req.flags = flags;
+
+ CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_GETATTR, req, ans);
+}
+
+__public int ceph_ll_getxattr(struct ceph_mount_info *cmount, struct Inode *in,
+ const char *name, void *value, size_t size,
+ const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_getxattr, req, 1, ans, 1);
+
+ req.userperm = ptr_value(perms);
+ req.inode = ptr_value(in);
+ req.size = size;
+ CEPH_STR_ADD(req, name, name);
+
+ CEPH_BUFF_ADD(ans, value, size);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_GETXATTR, req, ans);
+}
+
+__public int ceph_ll_link(struct ceph_mount_info *cmount, struct Inode *in,
+ struct Inode *newparent, const char *name,
+ const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_link, req, 1, ans, 0);
+
+ req.userperm = ptr_value(perms);
+ req.inode = ptr_value(in);
+ req.parent = ptr_value(newparent);
+ CEPH_STR_ADD(req, name, name);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_LINK, req, ans);
+}
+
+__public int ceph_ll_listxattr(struct ceph_mount_info *cmount, struct Inode *in,
+ char *list, size_t buf_size, size_t *list_size,
+ const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_listxattr, req, 0, ans, 1);
+ int32_t err;
+
+ req.userperm = ptr_value(perms);
+ req.inode = ptr_value(in);
+ req.size = buf_size;
+
+ CEPH_BUFF_ADD(ans, list, buf_size);
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_LISTXATTR, req, ans);
+ if (err >= 0) {
+ *list_size = ans.size;
+ }
+
+ return err;
+}
+
+__public int ceph_ll_lookup(struct ceph_mount_info *cmount, Inode *parent,
+ const char *name, Inode **out,
+ struct ceph_statx *stx, unsigned want,
+ unsigned flags, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_lookup, req, 1, ans, 1);
+ int32_t err;
+
+ req.userperm = ptr_value(perms);
+ req.parent = ptr_value(parent);
+ req.want = want;
+ req.flags = flags;
+ CEPH_STR_ADD(req, name, name);
+
+ CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_LOOKUP, req, ans);
+ if (err >= 0) {
+ *out = value_ptr(ans.inode);
+ }
+
+ return err;
+}
+
+__public int ceph_ll_lookup_inode(struct ceph_mount_info *cmount,
+ struct inodeno_t ino, Inode **inode)
+{
+ CEPH_REQ(ceph_ll_lookup_inode, req, 0, ans, 0);
+ int32_t err;
+
+ req.ino = ino;
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_LOOKUP_INODE, req, ans);
+ if (err >= 0) {
+ *inode = value_ptr(ans.inode);
+ }
+
+ return err;
+}
+
+__public int ceph_ll_lookup_root(struct ceph_mount_info *cmount, Inode **parent)
+{
+ CEPH_REQ(ceph_ll_lookup_root, req, 0, ans, 0);
+ int32_t err;
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_LOOKUP_ROOT, req, ans);
+ if (err >= 0) {
+ *parent = value_ptr(ans.inode);
+ }
+
+ return err;
+}
+
+__public off_t ceph_ll_lseek(struct ceph_mount_info *cmount,
+ struct Fh *filehandle, off_t offset, int whence)
+{
+ CEPH_REQ(ceph_ll_lseek, req, 0, ans, 0);
+ int32_t err;
+
+ req.fh = ptr_value(filehandle);
+ req.offset = offset;
+ req.whence = whence;
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_LSEEK, req, ans);
+ if (err >= 0) {
+ return ans.offset;
+ }
+
+ return err;
+}
+
+__public int ceph_ll_mkdir(struct ceph_mount_info *cmount, Inode *parent,
+ const char *name, mode_t mode, Inode **out,
+ struct ceph_statx *stx, unsigned want,
+ unsigned flags, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_mkdir, req, 1, ans, 1);
+ int32_t err;
+
+ req.userperm = ptr_value(perms);
+ req.parent = ptr_value(parent);
+ req.mode = mode;
+ req.want = want;
+ req.flags = flags;
+ CEPH_STR_ADD(req, name, name);
+
+ CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_MKDIR, req, ans);
+ if (err >= 0) {
+ *out = value_ptr(ans.inode);
+ }
+
+ return err;
+}
+
+__public int ceph_ll_mknod(struct ceph_mount_info *cmount, Inode *parent,
+ const char *name, mode_t mode, dev_t rdev,
+ Inode **out, struct ceph_statx *stx, unsigned want,
+ unsigned flags, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_mknod, req, 1, ans, 1);
+ int32_t err;
+
+ req.userperm = ptr_value(perms);
+ req.parent = ptr_value(parent);
+ req.mode = mode;
+ req.rdev = rdev;
+ req.want = want;
+ req.flags = flags;
+ CEPH_STR_ADD(req, name, name);
+
+ CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_MKNOD, req, ans);
+ if (err >= 0) {
+ *out = value_ptr(ans.inode);
+ }
+
+ return err;
+}
+
+__public int ceph_ll_open(struct ceph_mount_info *cmount, struct Inode *in,
+ int flags, struct Fh **fh, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_open, req, 0, ans, 0);
+ int32_t err;
+
+ req.userperm = ptr_value(perms);
+ req.inode = ptr_value(in);
+ req.flags = flags;
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_OPEN, req, ans);
+ if (err >= 0) {
+ *fh = value_ptr(ans.fh);
+ }
+
+ return err;
+}
+
+__public int ceph_ll_opendir(struct ceph_mount_info *cmount, struct Inode *in,
+ struct ceph_dir_result **dirpp,
+ const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_opendir, req, 0, ans, 0);
+ int32_t err;
+
+ req.userperm = ptr_value(perms);
+ req.inode = ptr_value(in);
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_OPENDIR, req, ans);
+ if (err >= 0) {
+ *dirpp = value_ptr(ans.dir);
+ }
+
+ return err;
+}
+
+__public int ceph_ll_put(struct ceph_mount_info *cmount, struct Inode *in)
+{
+ CEPH_REQ(ceph_ll_put, req, 0, ans, 0);
+
+ req.inode = ptr_value(in);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_PUT, req, ans);
+}
+
+__public int ceph_ll_read(struct ceph_mount_info *cmount, struct Fh *filehandle,
+ int64_t off, uint64_t len, char *buf)
+{
+ CEPH_REQ(ceph_ll_read, req, 0, ans, 1);
+
+ req.fh = ptr_value(filehandle);
+ req.offset = off;
+ req.len = len;
+
+ CEPH_BUFF_ADD(ans, buf, len);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_READ, req, ans);
+}
+
+__public int ceph_ll_readlink(struct ceph_mount_info *cmount, struct Inode *in,
+ char *buf, size_t bufsize, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_readlink, req, 0, ans, 1);
+
+ req.userperm = ptr_value(perms);
+ req.inode = ptr_value(in);
+ req.size = bufsize;
+
+ CEPH_BUFF_ADD(ans, buf, bufsize);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_READLINK, req, ans);
+}
+
+__public int ceph_ll_releasedir(struct ceph_mount_info *cmount,
+ struct ceph_dir_result *dir)
+{
+ CEPH_REQ(ceph_ll_releasedir, req, 0, ans, 0);
+
+ req.dir = ptr_value(dir);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_RELEASEDIR, req, ans);
+}
+
+__public int ceph_ll_removexattr(struct ceph_mount_info *cmount,
+ struct Inode *in, const char *name,
+ const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_removexattr, req, 1, ans, 0);
+
+ req.userperm = ptr_value(perms);
+ req.inode = ptr_value(in);
+ CEPH_STR_ADD(req, name, name);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_REMOVEXATTR, req, ans);
+}
+
+__public int ceph_ll_rename(struct ceph_mount_info *cmount,
+ struct Inode *parent, const char *name,
+ struct Inode *newparent, const char *newname,
+ const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_rename, req, 2, ans, 0);
+
+ req.userperm = ptr_value(perms);
+ req.old_parent = ptr_value(parent);
+ req.new_parent = ptr_value(newparent);
+ CEPH_STR_ADD(req, old_name, name);
+ CEPH_STR_ADD(req, new_name, newname);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_RENAME, req, ans);
+}
+
+__public void ceph_rewinddir(struct ceph_mount_info *cmount,
+ struct ceph_dir_result *dirp)
+{
+ CEPH_REQ(ceph_rewinddir, req, 0, ans, 0);
+
+ req.dir = ptr_value(dirp);
+
+ CEPH_PROCESS(cmount, LIBCEPHFSD_OP_REWINDDIR, req, ans);
+}
+
+__public int ceph_ll_rmdir(struct ceph_mount_info *cmount, struct Inode *in,
+ const char *name, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_rmdir, req, 1, ans, 0);
+
+ req.userperm = ptr_value(perms);
+ req.parent = ptr_value(in);
+ CEPH_STR_ADD(req, name, name);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_RMDIR, req, ans);
+}
+
+__public int ceph_ll_setattr(struct ceph_mount_info *cmount, struct Inode *in,
+ struct ceph_statx *stx, int mask,
+ const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_setattr, req, 1, ans, 0);
+
+ req.userperm = ptr_value(perms);
+ req.inode = ptr_value(in);
+ req.mask = mask;
+ CEPH_BUFF_ADD(req, stx, sizeof(*stx));
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_SETATTR, req, ans);
+}
+
+__public int ceph_ll_setxattr(struct ceph_mount_info *cmount, struct Inode *in,
+ const char *name, const void *value, size_t size,
+ int flags, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_setxattr, req, 2, ans, 0);
+
+ req.userperm = ptr_value(perms);
+ req.inode = ptr_value(in);
+ req.size = size;
+ req.flags = flags;
+ CEPH_STR_ADD(req, name, name);
+ CEPH_BUFF_ADD(req, value, size);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_SETXATTR, req, ans);
+}
+
+__public int ceph_ll_statfs(struct ceph_mount_info *cmount, struct Inode *in,
+ struct statvfs *stbuf)
+{
+ CEPH_REQ(ceph_ll_statfs, req, 0, ans, 1);
+
+ req.inode = ptr_value(in);
+
+ CEPH_BUFF_ADD(ans, stbuf, sizeof(*stbuf));
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_STATFS, req, ans);
+}
+
+__public int ceph_ll_symlink(struct ceph_mount_info *cmount, Inode *in,
+ const char *name, const char *value, Inode **out,
+ struct ceph_statx *stx, unsigned want,
+ unsigned flags, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_symlink, req, 2, ans, 1);
+ int32_t err;
+
+ req.userperm = ptr_value(perms);
+ req.parent = ptr_value(in);
+ req.want = want;
+ req.flags = flags;
+ CEPH_STR_ADD(req, name, name);
+ CEPH_STR_ADD(req, target, value);
+
+ CEPH_BUFF_ADD(req, stx, sizeof(*stx));
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_SYMLINK, req, ans);
+ if (err >= 0) {
+ *out = value_ptr(ans.inode);
+ }
+
+ return err;
+}
+
+__public int ceph_ll_unlink(struct ceph_mount_info *cmount, struct Inode *in,
+ const char *name, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_unlink, req, 1, ans, 0);
+
+ req.userperm = ptr_value(perms);
+ req.parent = ptr_value(in);
+ CEPH_STR_ADD(req, name, name);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_UNLINK, req, ans);
+}
+
+__public int ceph_ll_walk(struct ceph_mount_info *cmount, const char *name,
+ Inode **i, struct ceph_statx *stx, unsigned int want,
+ unsigned int flags, const UserPerm *perms)
+{
+ CEPH_REQ(ceph_ll_walk, req, 1, ans, 1);
+ int32_t err;
+
+ req.userperm = ptr_value(perms);
+ req.want = want;
+ req.flags = flags;
+ CEPH_STR_ADD(req, path, name);
+
+ CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_WALK, req, ans);
+ if (err >= 0) {
+ *i = value_ptr(ans.inode);
+ }
+
+ return err;
+}
+
+__public int ceph_ll_write(struct ceph_mount_info *cmount,
+ struct Fh *filehandle, int64_t off, uint64_t len,
+ const char *data)
+{
+ CEPH_REQ(ceph_ll_write, req, 1, ans, 0);
+
+ req.fh = ptr_value(filehandle);
+ req.offset = off;
+ req.len = len;
+ CEPH_BUFF_ADD(req, data, len);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_WRITE, req, ans);
+}
+
+__public int ceph_mount(struct ceph_mount_info *cmount, const char *root)
+{
+ CEPH_REQ(ceph_mount, req, 1, ans, 0);
+
+ CEPH_STR_ADD(req, root, root);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_MOUNT, req, ans);
+}
+
+__public struct dirent *ceph_readdir(struct ceph_mount_info *cmount,
+ struct ceph_dir_result *dirp)
+{
+ static struct dirent de;
+ int32_t err;
+
+ CEPH_REQ(ceph_readdir, req, 0, ans, 1);
+
+ req.dir = ptr_value(dirp);
+
+ CEPH_BUFF_ADD(ans, &de, sizeof(de));
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_READDIR, req, ans);
+ if (err < 0) {
+ errno = -err;
+ return NULL;
+ }
+ if (ans.eod) {
+ return NULL;
+ }
+
+ return &de;
+}
+
+__public int ceph_release(struct ceph_mount_info *cmount)
+{
+ CEPH_REQ(ceph_release, req, 0, ans, 0);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_RELEASE, req, ans);
+}
+
+__public int ceph_select_filesystem(struct ceph_mount_info *cmount,
+ const char *fs_name)
+{
+ CEPH_REQ(ceph_select_filesystem, req, 1, ans, 0);
+
+ CEPH_STR_ADD(req, fs, fs_name);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_SELECT_FILESYSTEM, req, ans);
+}
+
+__public int ceph_unmount(struct ceph_mount_info *cmount)
+{
+ CEPH_REQ(ceph_unmount, req, 0, ans, 0);
+
+ return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_UNMOUNT, req, ans);
+}
+
+__public void ceph_userperm_destroy(UserPerm *perms)
+{
+ CEPH_REQ(ceph_userperm_destroy, req, 0, ans, 0);
+
+ req.userperm = ptr_value(perms);
+
+ CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_USERPERM_DESTROY, req, ans);
+}
+
+__public UserPerm *ceph_userperm_new(uid_t uid, gid_t gid, int ngids,
+ gid_t *gidlist)
+{
+ CEPH_REQ(ceph_userperm_new, req, 1, ans, 0);
+ int32_t err;
+
+ req.uid = uid;
+ req.gid = gid;
+ req.groups = ngids;
+ CEPH_BUFF_ADD(req, gidlist, sizeof(gid_t) * ngids);
+
+ err = proxy_global_connect();
+ if (err >= 0) {
+ err = CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_USERPERM_NEW, req,
+ ans);
+ }
+ if (err >= 0) {
+ return value_ptr(ans.userperm);
+ }
+
+ errno = -err;
+
+ return NULL;
+}
+
+__public const char *ceph_version(int *major, int *minor, int *patch)
+{
+ static char cached_version[128];
+ static int32_t cached_major = -1, cached_minor, cached_patch;
+
+ if (cached_major < 0) {
+ CEPH_REQ(ceph_version, req, 0, ans, 1);
+ int32_t err;
+
+ CEPH_BUFF_ADD(ans, cached_version, sizeof(cached_version));
+
+ err = proxy_global_connect();
+ if (err >= 0) {
+ err = CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_VERSION,
+ req, ans);
+ }
+
+ if (err < 0) {
+ *major = 0;
+ *minor = 0;
+ *patch = 0;
+
+ return "Unknown";
+ }
+
+ cached_major = ans.major;
+ cached_minor = ans.minor;
+ cached_patch = ans.patch;
+ }
+
+ *major = cached_major;
+ *minor = cached_minor;
+ *patch = cached_patch;
+
+ return cached_version;
+}
+
+__public UserPerm *ceph_mount_perms(struct ceph_mount_info *cmount)
+{
+ CEPH_REQ(ceph_mount_perms, req, 0, ans, 0);
+ int32_t err;
+
+ err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_MOUNT_PERMS, req, ans);
+ if (err < 0) {
+ errno = -err;
+ return NULL;
+ }
+
+ return value_ptr(ans.userperm);
+}