From: Fotis Xenakis <fo...@windowslive.com> Committer: Waldemar Kozaczuk <jwkozac...@gmail.com> Branch: master
virtio-fs: minor code improvements in filesystem These include: - Checking memory allocations - Using smart pointers where possible - Using static_cast instead of reinterpret_cast or C-style cast where possible - Formatting and consistency Signed-off-by: Fotis Xenakis <fo...@windowslive.com> Message-Id: <vi1pr03mb438375635d92107c6567ffa8a6...@vi1pr03mb4383.eurprd03.prod.outlook.com> --- diff --git a/fs/virtiofs/virtiofs.hh b/fs/virtiofs/virtiofs.hh --- a/fs/virtiofs/virtiofs.hh +++ b/fs/virtiofs/virtiofs.hh @@ -32,7 +32,7 @@ struct virtiofs_file_data { uint64_t file_handle; }; -void virtiofs_set_vnode(struct vnode *vnode, struct virtiofs_inode *inode); +void virtiofs_set_vnode(struct vnode* vnode, struct virtiofs_inode* inode); extern struct vfsops virtiofs_vfsops; extern struct vnops virtiofs_vnops; diff --git a/fs/virtiofs/virtiofs_i.hh b/fs/virtiofs/virtiofs_i.hh --- a/fs/virtiofs/virtiofs_i.hh +++ b/fs/virtiofs/virtiofs_i.hh @@ -12,30 +12,29 @@ #include <osv/mutex.h> #include <osv/waitqueue.hh> -struct fuse_request -{ +struct fuse_request { struct fuse_in_header in_header; struct fuse_out_header out_header; - void *input_args_data; + void* input_args_data; size_t input_args_size; - void *output_args_data; + void* output_args_data; size_t output_args_size; mutex_t req_mutex; waitqueue req_wait; }; struct fuse_strategy { - void *drv; - int (*make_request)(void*, struct fuse_request*); + void* drv; + int (*make_request)(void*, fuse_request*); }; -int fuse_req_send_and_receive_reply(fuse_strategy* strategy, uint32_t opcode, uint64_t nodeid, - void *input_args_data, size_t input_args_size, - void *output_args_data, size_t output_args_size); +int fuse_req_send_and_receive_reply(fuse_strategy* strategy, uint32_t opcode, + uint64_t nodeid, void* input_args_data, size_t input_args_size, + void* output_args_data, size_t output_args_size); -void fuse_req_wait(struct fuse_request* req); +void fuse_req_wait(fuse_request* req); #endif diff --git a/fs/virtiofs/virtiofs_vfsops.cc b/fs/virtiofs/virtiofs_vfsops.cc --- a/fs/virtiofs/virtiofs_vfsops.cc +++ b/fs/virtiofs/virtiofs_vfsops.cc @@ -13,36 +13,21 @@ #include "virtiofs.hh" #include "virtiofs_i.hh" -static int virtiofs_mount(struct mount *mp, const char *dev, int flags, const void *data); -static int virtiofs_sync(struct mount *mp); -static int virtiofs_statfs(struct mount *mp, struct statfs *statp); -static int virtiofs_unmount(struct mount *mp, int flags); +static std::atomic<uint64_t> fuse_unique_id(1); -#define virtiofs_vget ((vfsop_vget_t)vfs_nullop) - -struct vfsops virtiofs_vfsops = { - virtiofs_mount, /* mount */ - virtiofs_unmount, /* unmount */ - virtiofs_sync, /* sync */ - virtiofs_vget, /* vget */ - virtiofs_statfs, /* statfs */ - &virtiofs_vnops /* vnops */ -}; - -std::atomic<uint64_t> fuse_unique_id(1); - -int fuse_req_send_and_receive_reply(fuse_strategy* strategy, uint32_t opcode, uint64_t nodeid, - void *input_args_data, size_t input_args_size, void *output_args_data, size_t output_args_size) +int fuse_req_send_and_receive_reply(fuse_strategy* strategy, uint32_t opcode, + uint64_t nodeid, void* input_args_data, size_t input_args_size, + void* output_args_data, size_t output_args_size) { - auto *req = new (std::nothrow) fuse_request(); - - req->in_header.len = 0; //TODO + std::unique_ptr<fuse_request> req {new (std::nothrow) fuse_request()}; + if (!req) { + return ENOMEM; + } + req->in_header.len = sizeof(req->in_header) + input_args_size; req->in_header.opcode = opcode; - req->in_header.unique = fuse_unique_id.fetch_add(1, std::memory_order_relaxed); + req->in_header.unique = fuse_unique_id.fetch_add(1, + std::memory_order_relaxed); req->in_header.nodeid = nodeid; - req->in_header.uid = 0; - req->in_header.gid = 0; - req->in_header.pid = 0; req->input_args_data = input_args_data; req->input_args_size = input_args_size; @@ -51,18 +36,17 @@ int fuse_req_send_and_receive_reply(fuse_strategy* strategy, uint32_t opcode, ui req->output_args_size = output_args_size; assert(strategy->drv); - strategy->make_request(strategy->drv, req); - fuse_req_wait(req); + strategy->make_request(strategy->drv, req.get()); + fuse_req_wait(req.get()); int error = -req->out_header.error; - delete req; return error; } -void virtiofs_set_vnode(struct vnode *vnode, struct virtiofs_inode *inode) +void virtiofs_set_vnode(struct vnode* vnode, struct virtiofs_inode* inode) { - if (vnode == nullptr || inode == nullptr) { + if (!vnode || !inode) { return; } @@ -82,81 +66,85 @@ void virtiofs_set_vnode(struct vnode *vnode, struct virtiofs_inode *inode) vnode->v_size = inode->attr.size; } -static int -virtiofs_mount(struct mount *mp, const char *dev, int flags, const void *data) { - struct device *device; - int error = -1; +static int virtiofs_mount(struct mount* mp, const char* dev, int flags, + const void* data) +{ + struct device* device; - error = device_open(dev + 5, DO_RDWR, &device); + int error = device_open(dev + strlen("/dev/"), DO_RDWR, &device); if (error) { kprintf("[virtiofs] Error opening device!\n"); return error; } - mp->m_dev = device; - - auto *in_args = new(std::nothrow) fuse_init_in(); + std::unique_ptr<fuse_init_in> in_args {new (std::nothrow) fuse_init_in()}; + std::unique_ptr<fuse_init_out> out_args {new (std::nothrow) fuse_init_out}; + if (!in_args || !out_args) { + return ENOMEM; + } in_args->major = FUSE_KERNEL_VERSION; in_args->minor = FUSE_KERNEL_MINOR_VERSION; in_args->max_readahead = PAGE_SIZE; - in_args->flags = 0; //TODO Investigate which flags to set - - auto *out_args = new(std::nothrow) fuse_init_out(); + in_args->flags = 0; // TODO: Verify that we need not set any flag - auto *strategy = reinterpret_cast<fuse_strategy *>(device->private_data); + auto* strategy = static_cast<fuse_strategy*>(device->private_data); error = fuse_req_send_and_receive_reply(strategy, FUSE_INIT, FUSE_ROOT_ID, - in_args, sizeof(*in_args), out_args, sizeof(*out_args)); - - if (!error) { - virtiofs_debug("Initialized fuse filesystem with version major: %d, minor: %d\n", - out_args->major, out_args->minor); - - auto *root_node = new virtiofs_inode(); - root_node->nodeid = FUSE_ROOT_ID; - root_node->attr.mode = S_IFDIR; + in_args.get(), sizeof(*in_args), out_args.get(), sizeof(*out_args)); + if (error) { + kprintf("[virtiofs] Failed to initialize fuse filesystem!\n"); + return error; + } + // TODO: Handle version negotiation - virtiofs_set_vnode(mp->m_root->d_vnode, root_node); + virtiofs_debug("Initialized fuse filesystem with version major: %d, " + "minor: %d\n", out_args->major, out_args->minor); - mp->m_data = strategy; - mp->m_dev = device; - } else { - kprintf("[virtiofs] Failed to initialized fuse filesystem!\n"); + auto* root_node {new (std::nothrow) virtiofs_inode()}; + if (!root_node) { + return ENOMEM; } + root_node->nodeid = FUSE_ROOT_ID; + root_node->attr.mode = S_IFDIR; - delete out_args; - delete in_args; + virtiofs_set_vnode(mp->m_root->d_vnode, root_node); - return error; -} + mp->m_data = strategy; + mp->m_dev = device; -static int virtiofs_sync(struct mount *mp) { return 0; } -static int virtiofs_statfs(struct mount *mp, struct statfs *statp) +static int virtiofs_sync(struct mount* mp) { - //TODO - //struct virtiofs_info *virtiofs = (struct virtiofs_info *) mp->m_data; + return 0; +} - //statp->f_bsize = sb->block_size; +static int virtiofs_statfs(struct mount* mp, struct statfs* statp) +{ + // TODO: Call FUSE_STATFS - // Total blocks - //statp->f_blocks = sb->structure_info_blocks_count + sb->structure_info_first_block; // Read only. 0 blocks free statp->f_bfree = 0; statp->f_bavail = 0; statp->f_ffree = 0; - //statp->f_files = sb->inodes_count; //Needs to be inode count - - statp->f_namelen = 0; //FIXME return 0; } -static int -virtiofs_unmount(struct mount *mp, int flags) +static int virtiofs_unmount(struct mount* mp, int flags) { - struct device *dev = mp->m_dev; + struct device* dev = mp->m_dev; return device_close(dev); } + +#define virtiofs_vget ((vfsop_vget_t)vfs_nullop) + +struct vfsops virtiofs_vfsops = { + virtiofs_mount, /* mount */ + virtiofs_unmount, /* unmount */ + virtiofs_sync, /* sync */ + virtiofs_vget, /* vget */ + virtiofs_statfs, /* statfs */ + &virtiofs_vnops /* vnops */ +}; diff --git a/fs/virtiofs/virtiofs_vnops.cc b/fs/virtiofs/virtiofs_vnops.cc --- a/fs/virtiofs/virtiofs_vnops.cc +++ b/fs/virtiofs/virtiofs_vnops.cc @@ -27,206 +27,233 @@ #include "virtiofs.hh" #include "virtiofs_i.hh" -#define VERIFY_READ_INPUT_ARGUMENTS() \ - /* Cant read directories */\ - if (vnode->v_type == VDIR) \ - return EISDIR; \ - /* Cant read anything but reg */\ - if (vnode->v_type != VREG) \ - return EINVAL; \ - /* Cant start reading before the first byte */\ - if (uio->uio_offset < 0) \ - return EINVAL; \ - /* Need to read more than 1 byte */\ - if (uio->uio_resid == 0) \ - return 0; \ - /* Cant read after the end of the file */\ - if (uio->uio_offset >= (off_t)vnode->v_size) \ - return 0; +static constexpr uint32_t OPEN_FLAGS = O_RDONLY; -int virtiofs_init(void) { +int virtiofs_init() +{ return 0; } -static int virtiofs_lookup(struct vnode *vnode, char *name, struct vnode **vpp) +static int virtiofs_lookup(struct vnode* vnode, char* name, struct vnode** vpp) { - struct virtiofs_inode *inode = (struct virtiofs_inode *) vnode->v_data; - struct vnode *vp = nullptr; + auto* inode = static_cast<virtiofs_inode*>(vnode->v_data); if (*name == '\0') { return ENOENT; } if (!S_ISDIR(inode->attr.mode)) { - kprintf("[virtiofs] inode:%d, ABORTED lookup of %s because not a directory\n", inode->nodeid, name); + kprintf("[virtiofs] inode:%lld, ABORTED lookup of %s because not a " + "directory\n", inode->nodeid, name); return ENOTDIR; } - auto *out_args = new (std::nothrow) fuse_entry_out(); - auto input = new char[strlen(name) + 1]; - strcpy(input, name); - - auto *strategy = reinterpret_cast<fuse_strategy*>(vnode->v_mount->m_data); - int error = fuse_req_send_and_receive_reply(strategy, FUSE_LOOKUP, inode->nodeid, - input, strlen(name) + 1, out_args, sizeof(*out_args)); - - if (!error) { - if (vget(vnode->v_mount, out_args->nodeid, &vp)) { //TODO: Will it ever work? Revisit - virtiofs_debug("lookup found vp in cache!\n"); - *vpp = vp; - return 0; - } - - auto *new_inode = new virtiofs_inode(); - new_inode->nodeid = out_args->nodeid; - virtiofs_debug("inode %d, lookup found inode %d for %s!\n", inode->nodeid, new_inode->nodeid, name); - memcpy(&new_inode->attr, &out_args->attr, sizeof(out_args->attr)); + auto in_args_len = strlen(name) + 1; + std::unique_ptr<char[]> in_args {new (std::nothrow) char[in_args_len]}; + std::unique_ptr<fuse_entry_out> out_args { + new (std::nothrow) fuse_entry_out}; + if (!out_args || !in_args) { + return ENOMEM; + } + strcpy(in_args.get(), name); + + auto* strategy = static_cast<fuse_strategy*>(vnode->v_mount->m_data); + auto error = fuse_req_send_and_receive_reply(strategy, FUSE_LOOKUP, + inode->nodeid, in_args.get(), in_args_len, out_args.get(), + sizeof(*out_args)); + if (error) { + kprintf("[virtiofs] inode:%lld, lookup failed to find %s\n", + inode->nodeid, name); + // TODO: Implement proper error handling by sending FUSE_FORGET + return error; + } - virtiofs_set_vnode(vp, new_inode); + struct vnode* vp; + // TODO OPT: Should we even use the cache? (consult spec on metadata) + if (vget(vnode->v_mount, out_args->nodeid, &vp) == 1) { + virtiofs_debug("lookup found vp in cache!\n"); *vpp = vp; - } else { - kprintf("[virtiofs] inode:%d, lookup failed to find %s\n", inode->nodeid, name); - //TODO Implement proper error handling by sending FUSE_FORGET + return 0; } - delete input; - delete out_args; + auto* new_inode = new (std::nothrow) virtiofs_inode; + if (!new_inode) { + return ENOMEM; + } + new_inode->nodeid = out_args->nodeid; + virtiofs_debug("inode %lld, lookup found inode %lld for %s!\n", + inode->nodeid, new_inode->nodeid, name); + memcpy(&new_inode->attr, &out_args->attr, sizeof(out_args->attr)); - return error; + virtiofs_set_vnode(vp, new_inode); + *vpp = vp; + + return 0; } -static int virtiofs_open(struct file *fp) +static int virtiofs_open(struct file* fp) { if ((file_flags(fp) & FWRITE)) { - // Do no allow opening files to write - return (EROFS); + // Do not allow opening files to write + return EROFS; } - struct vnode *vnode = file_dentry(fp)->d_vnode; - struct virtiofs_inode *inode = (struct virtiofs_inode *) vnode->v_data; + auto* vnode = file_dentry(fp)->d_vnode; + auto* inode = static_cast<virtiofs_inode*>(vnode->v_data); - auto *out_args = new (std::nothrow) fuse_open_out(); - auto *input_args = new (std::nothrow) fuse_open_in(); - input_args->flags = O_RDONLY; - - auto *strategy = reinterpret_cast<fuse_strategy*>(vnode->v_mount->m_data); - int error = fuse_req_send_and_receive_reply(strategy, FUSE_OPEN, inode->nodeid, - input_args, sizeof(*input_args), out_args, sizeof(*out_args)); + std::unique_ptr<fuse_open_in> in_args {new (std::nothrow) fuse_open_in()}; + std::unique_ptr<fuse_open_out> out_args {new (std::nothrow) fuse_open_out}; + if (!out_args || !in_args) { + return ENOMEM; + } + in_args->flags = OPEN_FLAGS; + + auto* strategy = static_cast<fuse_strategy*>(vnode->v_mount->m_data); + auto error = fuse_req_send_and_receive_reply(strategy, FUSE_OPEN, + inode->nodeid, in_args.get(), sizeof(*in_args), out_args.get(), + sizeof(*out_args)); + if (error) { + kprintf("[virtiofs] inode %lld, open failed\n", inode->nodeid); + return error; + } - if (!error) { - virtiofs_debug("inode %d, opened\n", inode->nodeid); + virtiofs_debug("inode %lld, opened\n", inode->nodeid); - auto *file_data = new virtiofs_file_data(); - file_data->file_handle = out_args->fh; - fp->f_data = file_data; + auto* f_data = new (std::nothrow) virtiofs_file_data; + if (!f_data) { + return ENOMEM; } + f_data->file_handle = out_args->fh; + // TODO OPT: Consult and possibly act upon out_args->open_flags + file_setdata(fp, f_data); - delete input_args; - delete out_args; - - return error; + return 0; } -static int virtiofs_close(struct vnode *vnode, struct file *fp) +static int virtiofs_close(struct vnode* vnode, struct file* fp) { - struct virtiofs_inode *inode = (struct virtiofs_inode *) vnode->v_data; - - auto *input_args = new (std::nothrow) fuse_release_in(); - auto *file_data = reinterpret_cast<virtiofs_file_data*>(fp->f_data); - input_args->fh = file_data->file_handle; + auto* inode = static_cast<virtiofs_inode*>(vnode->v_data); - auto *strategy = reinterpret_cast<fuse_strategy*>(vnode->v_mount->m_data); - auto error = fuse_req_send_and_receive_reply(strategy, FUSE_RELEASE, inode->nodeid, - input_args, sizeof(*input_args), nullptr, 0); - - if (!error) { - fp->f_data = nullptr; - delete file_data; - virtiofs_debug("inode %d, closed\n", inode->nodeid); + std::unique_ptr<fuse_release_in> in_args { + new (std::nothrow) fuse_release_in()}; + if (!in_args) { + return ENOMEM; + } + auto* f_data = static_cast<virtiofs_file_data*>(file_data(fp)); + in_args->fh = f_data->file_handle; + in_args->flags = OPEN_FLAGS; // need to be same as in FUSE_OPEN + + auto* strategy = static_cast<fuse_strategy*>(vnode->v_mount->m_data); + auto error = fuse_req_send_and_receive_reply(strategy, FUSE_RELEASE, + inode->nodeid, in_args.get(), sizeof(*in_args), nullptr, 0); + if (error) { + kprintf("[virtiofs] inode %lld, close failed\n", inode->nodeid); + return error; } - //TODO: Investigate if we should send FUSE_FORGET once all handles to the file closed on our side + file_setdata(fp, nullptr); + delete f_data; + virtiofs_debug("inode %lld, closed\n", inode->nodeid); - delete input_args; + // TODO: Investigate if we should send FUSE_FORGET once all handles to the + // file closed on our side - return error; + return 0; } -static int virtiofs_readlink(struct vnode *vnode, struct uio *uio) +static int virtiofs_readlink(struct vnode* vnode, struct uio* uio) { - struct virtiofs_inode *inode = (struct virtiofs_inode *) vnode->v_data; - - auto *link_path = new (std::nothrow) char[PATH_MAX]; + auto* inode = static_cast<virtiofs_inode*>(vnode->v_data); - auto *strategy = reinterpret_cast<fuse_strategy*>(vnode->v_mount->m_data); - int error = fuse_req_send_and_receive_reply(strategy, FUSE_READLINK, inode->nodeid, - nullptr, 0, link_path, PATH_MAX); - - int ret = 0; - if (!error) { - virtiofs_debug("inode %d, read symlink [%s]\n", inode->nodeid, link_path); - ret = uiomove(link_path, strlen(link_path), uio); - } else { - kprintf("[virtiofs] Error reading data\n"); - ret = error; + std::unique_ptr<char[]> link_path {new (std::nothrow) char[PATH_MAX]}; + if (!link_path) { + return ENOMEM; } - delete link_path; + auto* strategy = static_cast<fuse_strategy*>(vnode->v_mount->m_data); + auto error = fuse_req_send_and_receive_reply(strategy, FUSE_READLINK, + inode->nodeid, nullptr, 0, link_path.get(), PATH_MAX); + if (error) { + kprintf("[virtiofs] inode %lld, readlink failed\n", inode->nodeid); + return error; + } - return ret; + virtiofs_debug("inode %lld, read symlink [%s]\n", inode->nodeid, + link_path.get()); + return uiomove(link_path.get(), strlen(link_path.get()), uio); } -//TODO: Optimize it to reduce number of exits to host (each fuse_req_send_and_receive_reply()) -// by reading eagerly "ahead/around" just like ROFS does and caching it -static int virtiofs_read(struct vnode *vnode, struct file *fp, struct uio *uio, int ioflag) +// TODO: Optimize it to reduce number of exits to host (each +// fuse_req_send_and_receive_reply()) by reading eagerly "ahead/around" just +// like ROFS does and caching it +static int virtiofs_read(struct vnode* vnode, struct file* fp, struct uio* uio, + int ioflag) { - struct virtiofs_inode *inode = (struct virtiofs_inode *) vnode->v_data; + auto* inode = static_cast<virtiofs_inode*>(vnode->v_data); - VERIFY_READ_INPUT_ARGUMENTS() + // Can't read directories + if (vnode->v_type == VDIR) { + return EISDIR; + } + // Can't read anything but reg + if (vnode->v_type != VREG) { + return EINVAL; + } + // Can't start reading before the first byte + if (uio->uio_offset < 0) { + return EINVAL; + } + // Need to read at least 1 byte + if (uio->uio_resid == 0) { + return 0; + } + // Can't read after the end of the file + if (uio->uio_offset >= vnode->v_size) { + return 0; + } // Total read amount is what they requested, or what is left - uint64_t read_amt = std::min<uint64_t>(inode->attr.size - uio->uio_offset, uio->uio_resid); - void *buf = malloc(read_amt); - - auto *input_args = new (std::nothrow) fuse_read_in(); - auto *file_data = reinterpret_cast<virtiofs_file_data*>(fp->f_data); - input_args->fh = file_data->file_handle; - input_args->offset = uio->uio_offset; - input_args->size = read_amt; - input_args->flags = ioflag; - input_args->lock_owner = 0; - - virtiofs_debug("inode %d, reading %d bytes at offset %d\n", inode->nodeid, read_amt, uio->uio_offset); - - auto *strategy = reinterpret_cast<fuse_strategy*>(vnode->v_mount->m_data); - auto error = fuse_req_send_and_receive_reply(strategy, FUSE_READ, inode->nodeid, - input_args, sizeof(*input_args), buf, read_amt); - - int ret = 0; - if (!error) { - ret = uiomove(buf, read_amt, uio); - } else { - kprintf("[virtiofs] Error reading data\n"); - ret = error; + auto read_amt = std::min<uint64_t>(uio->uio_resid, + inode->attr.size - uio->uio_offset); + std::unique_ptr<u8[]> buf {new (std::nothrow) u8[read_amt]}; + std::unique_ptr<fuse_read_in> in_args {new (std::nothrow) fuse_read_in()}; + if (!buf || !in_args) { + return ENOMEM; + } + auto* f_data = static_cast<virtiofs_file_data*>(file_data(fp)); + in_args->fh = f_data->file_handle; + in_args->offset = uio->uio_offset; + in_args->size = read_amt; + in_args->flags = ioflag; + + virtiofs_debug("inode %lld, reading %lld bytes at offset %lld\n", + inode->nodeid, read_amt, uio->uio_offset); + + auto* strategy = static_cast<fuse_strategy*>(vnode->v_mount->m_data); + auto error = fuse_req_send_and_receive_reply(strategy, FUSE_READ, + inode->nodeid, in_args.get(), sizeof(*in_args), buf.get(), read_amt); + if (error) { + kprintf("[virtiofs] inode %lld, read failed\n", inode->nodeid); + return error; } - free(buf); - free(input_args); - - return ret; + return uiomove(buf.get(), read_amt, uio); } -// -static int virtiofs_readdir(struct vnode *vnode, struct file *fp, struct dirent *dir) + +static int virtiofs_readdir(struct vnode* vnode, struct file* fp, + struct dirent* dir) { - //TODO Implement + // TODO: Implement return EPERM; } -static int virtiofs_getattr(struct vnode *vnode, struct vattr *attr) +static int virtiofs_getattr(struct vnode* vnode, struct vattr* attr) { - struct virtiofs_inode *inode = (struct virtiofs_inode *) vnode->v_data; + auto* inode = static_cast<virtiofs_inode*>(vnode->v_data); - attr->va_mode = 0555; //Is it really correct? + // TODO: Call FUSE_GETATTR? But figure out if fuse_getattr_in.fh is + // necessary (look at the flags) + attr->va_mode = 0555; // TODO: Is it really correct? if (S_ISDIR(inode->attr.mode)) { attr->va_type = VDIR; @@ -277,10 +304,11 @@ struct vnops virtiofs_vnops = { virtiofs_getattr, /* getattr */ virtiofs_setattr, /* setattr - returns error when called */ virtiofs_inactive, /* inactive */ - virtiofs_truncate, /* truncate - returns error when called*/ - virtiofs_link, /* link - returns error when called*/ - virtiofs_arc, /* arc */ //TODO: Implement to allow memory re-use when mapping files, investigate using virtio-fs DAX - virtiofs_fallocate, /* fallocate - returns error when called*/ + virtiofs_truncate, /* truncate - returns error when called */ + virtiofs_link, /* link - returns error when called */ + virtiofs_arc, /* arc */ //TODO: Implement to allow memory re-use when + // mapping files, investigate using virtio-fs DAX + virtiofs_fallocate, /* fallocate - returns error when called */ virtiofs_readlink, /* read link */ - virtiofs_symlink /* symbolic link - returns error when called*/ + virtiofs_symlink /* symbolic link - returns error when called */ }; -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/00000000000028ed3205a4667668%40google.com.