Mercurial > nomad > experimental
view src/fs/nomadfs.c @ 1276:6dd652e45be5
fs: remove debug hexdumping of file data
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Sun, 18 Dec 2022 09:54:35 -0500 |
parents | 90d2af779270 |
children | ea51bd7cb9f5 |
line wrap: on
line source
/* * Copyright (c) 2016-2020,2022 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define FUSE_USE_VERSION 31 #include <fuse_lowlevel.h> #include <jeffpc/error.h> #include <jeffpc/sock.h> #include <nomad/rpc.h> #include <nomad/fscall.h> #define REPLY_TIMEOUT 1.0 #define ATTR_TIMEOUT 1.0 #define ENTRY_TIMEOUT 1.0 /* * Since we use <allocator host id, uniq> as the inode number, we must make * sure that the inode number type is large enough to hold the two pieces. */ STATIC_ASSERT(sizeof(fuse_ino_t) >= (sizeof(uint32_t) * 2)); /* * fuse assumes that the root inode number is FUSE_ROOT_ID. Since that's * not guaranteed, we swap the root object's inode number with whatever * object happens to be using FUSE_ROOT_ID for its inode number. */ static fuse_ino_t root_ino_buddy; static struct fscall_state state; static inline uint64_t ino_fuse2nomad(fuse_ino_t ino) { if (ino == FUSE_ROOT_ID) return root_ino_buddy; else if (ino == root_ino_buddy) return FUSE_ROOT_ID; else return ino; } static inline fuse_ino_t ino_nomad2fuse(uint64_t ino) { if (ino == FUSE_ROOT_ID) return root_ino_buddy; else if (ino == root_ino_buddy) return FUSE_ROOT_ID; else return ino; } /* * Helpers to wrap fscall into more high-level operations */ static int __getattr(const struct noid *oid, uint64_t ino, struct nattr *nattr) { uint32_t ohandle; int ret; ret = fscall_open(&state, oid, ino, &ohandle); if (ret) return ret; ret = fscall_getattr(&state, ohandle, nattr); if (ret) goto err_close; return fscall_close(&state, ohandle); err_close: fscall_close(&state, ohandle); return ret; } static int __create(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t dev, struct noid *child_oid) { const struct fuse_ctx *fuse_ctx; uint32_t dir_ohandle; int ret; fuse_ctx = fuse_req_ctx(req); if (!fuse_ctx) return -EPERM; /* TODO: is there a better errno? */ ret = fscall_open(&state, NULL, ino_fuse2nomad(parent), &dir_ohandle); if (ret) return ret; STATIC_ASSERT(sizeof(dev_t) <= sizeof(uint64_t)); /* dev needs to be zero for everything except char/block devices */ if (!(S_ISBLK(mode) || S_ISCHR(mode))) dev = 0; ret = fscall_create(&state, dir_ohandle, name, fuse_ctx->uid, fuse_ctx->gid, mode_to_nmode(mode), dev, child_oid); if (ret) goto err; return fscall_close(&state, dir_ohandle); err: fscall_close(&state, dir_ohandle); return ret; } /* * Fuse operations */ static void nomadfs_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { struct nattr nattr; struct stat statbuf; int ret; ret = __getattr(NULL, ino_fuse2nomad(ino), &nattr); if (ret) goto err; nattr_to_stat(&nattr, &statbuf); statbuf.st_ino = ino_nomad2fuse(nattr.ino); /* XXX: somehow, we're returning good data, but gets interpreted wrong */ /* XXX: seems to be a 32-bit. vs. 64-bit problem */ fuse_reply_attr(req, &statbuf, REPLY_TIMEOUT); return; err: fuse_reply_err(req, -nerr_to_errno(ret)); } static void nomadfs_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi) { struct stat statbuf; struct nattr nattr; uint32_t ohandle; int ret; /* * If we're not setting the mode (and therefore didn't get one), we * need to make a fake but valid mode for the benefit of stat_to_nattr */ if (!(to_set & FUSE_SET_ATTR_MODE)) attr->st_mode = S_IFREG; stat_to_nattr(attr, &nattr); ret = fscall_open(&state, NULL, ino_fuse2nomad(ino), &ohandle); if (ret) goto err; ret = fscall_setattr(&state, ohandle, &nattr, (to_set & FUSE_SET_ATTR_MODE) ? true : false, (to_set & FUSE_SET_ATTR_SIZE) ? true : false, false, /* FIXME: atime vs. atime_now */ false, /* btime */ false, /* ctime */ false, /* FIXME: mtime vs. mtime_now */ (to_set & FUSE_SET_ATTR_UID) ? true : false, (to_set & FUSE_SET_ATTR_GID) ? true : false); if (ret) goto err_close; ret = fscall_close(&state, ohandle); if (ret) goto err; nattr_to_stat(&nattr, &statbuf); statbuf.st_ino = ino_nomad2fuse(nattr.ino); fuse_reply_attr(req, &statbuf, REPLY_TIMEOUT); return; err_close: fscall_close(&state, ohandle); err: fuse_reply_err(req, -nerr_to_errno(ret)); } static void nomadfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { struct fuse_entry_param e; uint32_t child_ohandle; uint32_t dir_ohandle; struct noid child_oid; struct nattr nattr; int ret; if (parent == FUSE_ROOT_ID) { dir_ohandle = state.root_ohandle; } else { ret = fscall_open(&state, NULL, ino_fuse2nomad(parent), &dir_ohandle); if (ret) goto err; } ret = fscall_lookup(&state, dir_ohandle, name, &child_oid); if (ret) goto err_close_dir; ret = fscall_open(&state, &child_oid, 0, &child_ohandle); if (ret) goto err_close_dir; ret = fscall_getattr(&state, child_ohandle, &nattr); if (ret) goto err_close_child; ret = fscall_close(&state, child_ohandle); if (ret) goto err_close_dir; if (parent != FUSE_ROOT_ID) fscall_close(&state, dir_ohandle); memset(&e, 0, sizeof(e)); nattr_to_stat(&nattr, &e.attr); e.ino = e.attr.st_ino = ino_nomad2fuse(nattr.ino); e.attr_timeout = ATTR_TIMEOUT; e.entry_timeout = ENTRY_TIMEOUT; fuse_reply_entry(req, &e); return; err_close_child: fscall_close(&state, child_ohandle); err_close_dir: if (parent != FUSE_ROOT_ID) fscall_close(&state, dir_ohandle); err: fuse_reply_err(req, -nerr_to_errno(ret)); } static void nomadfs_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t dev) { struct fuse_entry_param e; struct noid child_oid; struct nattr nattr; int ret; ret = __create(req, parent, name, mode, dev, &child_oid); if (ret) goto err; ret = __getattr(&child_oid, 0, &nattr); if (ret) goto err; memset(&e, 0, sizeof(e)); nattr_to_stat(&nattr, &e.attr); e.ino = e.attr.st_ino = ino_nomad2fuse(nattr.ino); e.attr_timeout = ATTR_TIMEOUT; e.entry_timeout = ENTRY_TIMEOUT; fuse_reply_entry(req, &e); return; err: fuse_reply_err(req, -nerr_to_errno(ret)); } static void nomadfs_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) { nomadfs_mknod(req, parent, name, mode, 0); } static void __unlink(fuse_req_t req, fuse_ino_t parent, const char *name, bool rmdir) { uint32_t dir_ohandle; int ret; ret = fscall_open(&state, NULL, ino_fuse2nomad(parent), &dir_ohandle); if (ret) goto err; ret = fscall_unlink(&state, dir_ohandle, name, NULL, rmdir); if (ret) goto err_close; ret = fscall_close(&state, dir_ohandle); if (ret) goto err; fuse_reply_err(req, 0); return; err_close: fscall_close(&state, dir_ohandle); err: fuse_reply_err(req, -nerr_to_errno(ret)); } static void nomadfs_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) { __unlink(req, parent, name, false); } static void nomadfs_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { __unlink(req, parent, name, true); } static int reply_slice(fuse_req_t req, void *buf, size_t bufsize, off_t fuse_off, size_t fuse_size) { if (fuse_off < bufsize) return fuse_reply_buf(req, buf + fuse_off, (bufsize - fuse_off < fuse_size) ? (bufsize - fuse_off) : fuse_size); else return fuse_reply_buf(req, NULL, 0); } static int dirent_add(fuse_req_t req, void **_buf, size_t *_bufsize, const char *name, const struct noid *oid, uint64_t ino) { const size_t oldbufsize = *_bufsize; size_t bufsize = *_bufsize; struct stat statbuf; void *buf = *_buf; void *tmp; bufsize += fuse_add_direntry(req, NULL, 0, name, NULL, 0); tmp = realloc(buf, bufsize); if (!tmp) return -ENOMEM; *_buf = buf = tmp; *_bufsize = bufsize; memset(&statbuf, 0, sizeof(statbuf)); statbuf.st_ino = ino_nomad2fuse(ino); fuse_add_direntry(req, buf + oldbufsize, bufsize - oldbufsize, name, &statbuf, bufsize); return 0; } static void nomadfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t fuse_size, off_t fuse_off, struct fuse_file_info *fi) { uint32_t ohandle = fi->fh; uint64_t off; size_t bufsize; void *buf; int ret; bufsize = 0; buf = NULL; off = 0; do { struct ndirent dirent; ret = fscall_getdent(&state, ohandle, off, &dirent); if (ret && ret != NERR_ENOENT) goto err; if (ret == NERR_ENOENT) break; ASSERT3U(dirent.type, !=, NDIRENT_TYPE_GRAFT); ret = dirent_add(req, &buf, &bufsize, dirent.name, &dirent.oid, dirent.ino); if (ret) { fuse_reply_err(req, -ret); return; } off = dirent.dir_offset + 1; } while (!ret); reply_slice(req, buf, bufsize, fuse_off, fuse_size); free(buf); return; err: fuse_reply_err(req, -nerr_to_errno(ret)); } static void nomadfs_create(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi) { struct fuse_entry_param e; struct noid child_oid; struct nattr nattr; uint32_t ohandle; int ret; ret = __create(req, parent, name, mode, 0, &child_oid); if (ret) goto err; ret = fscall_open(&state, &child_oid, 0, &ohandle); if (ret) goto err; ret = fscall_getattr(&state, ohandle, &nattr); if (ret) goto err_close; fi->fh = ohandle; memset(&e, 0, sizeof(e)); nattr_to_stat(&nattr, &e.attr); e.ino = e.attr.st_ino = ino_nomad2fuse(nattr.ino); e.attr_timeout = ATTR_TIMEOUT; e.entry_timeout = ENTRY_TIMEOUT; fuse_reply_create(req, &e, fi); return; err_close: fscall_close(&state, ohandle); err: fuse_reply_err(req, -nerr_to_errno(ret)); } static void nomadfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { uint32_t ohandle; int ret; ret = fscall_open(&state, NULL, ino_fuse2nomad(ino), &ohandle); if (ret) goto err; fi->fh = ohandle; fuse_reply_open(req, fi); return; err: fuse_reply_err(req, -nerr_to_errno(ret)); } static void nomadfs_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { uint32_t ohandle = fi->fh; int ret; ret = fscall_close(&state, ohandle); if (ret) goto err; fuse_reply_err(req, 0); return; err: fuse_reply_err(req, -nerr_to_errno(ret)); } static void nomadfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { uint32_t ohandle = fi->fh; char *buf; int ret; buf = alloca(size); ret = fscall_read(&state, ohandle, buf, size, off); if (ret) goto err; fuse_reply_buf(req, buf, size); return; err: fuse_reply_err(req, -nerr_to_errno(ret)); } static void nomadfs_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { uint32_t ohandle = fi->fh; int ret; ret = fscall_write(&state, ohandle, buf, size, off); if (ret) fuse_reply_err(req, -nerr_to_errno(ret)); else fuse_reply_write(req, size); } static struct fuse_lowlevel_ops nomad_ops = { .getattr = nomadfs_getattr, .setattr = nomadfs_setattr, .lookup = nomadfs_lookup, .mknod = nomadfs_mknod, .mkdir = nomadfs_mkdir, .unlink = nomadfs_unlink, .rmdir = nomadfs_rmdir, .readdir = nomadfs_readdir, .create = nomadfs_create, .open = nomadfs_open, .release = nomadfs_release, .opendir = nomadfs_open, .releasedir = nomadfs_release, .read = nomadfs_read, .write = nomadfs_write, }; int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_session *se; struct fuse_chan *ch; struct nattr root_attrs; const char *volstr; struct xuuid tmp; char *mountpoint; int ret; int fd; volstr = getenv("VOL"); if (!volstr) panic("missing VOL env var"); xuuid_parse(&tmp, volstr); fd = connect_ip("localhost", 2323, true, true, IP_TCP); if (fd < 0) panic("failed to connect to nomad-client: %s", xstrerror(fd)); ret = fscall_connect(&state, fd); if (ret) panic("failed RPC handshake with nomad-client: %s", xstrerror(ret)); ret = fscall_mount(&state, &tmp); if (ret) panic("failed to mount volume: %s", xstrerror(ret)); ret = __getattr(&state.root_oid, 0, &root_attrs); if (ret) panic("failed to getattr volume root: %s", xstrerror(ret)); /* see comment by root_ino_buddy definition */ root_ino_buddy = root_attrs.ino; ret = 1; if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) == -1) goto err; if ((ch = fuse_mount(mountpoint, &args)) == NULL) goto err; se = fuse_lowlevel_new(&args, &nomad_ops, sizeof(nomad_ops), NULL); if (!se) goto err_unmount; if (fuse_set_signal_handlers(se) == -1) goto err_session; fuse_session_add_chan(se, ch); ret = fuse_session_loop(se); fuse_remove_signal_handlers(se); fuse_session_remove_chan(ch); err_session: fuse_session_destroy(se); err_unmount: fuse_unmount(mountpoint, ch); err: fuse_opt_free_args(&args); return ret ? 1 : 0; }