[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH 7/8] lib/uk9p: Add 9P helper API
This patch implements an API for the operations supported by the 9P protocol. Each supported message type has an associated function with which to make requests. Signed-off-by: Cristian Banu <cristb@xxxxxxxxx> --- lib/uk9p/9p.c | 423 +++++++++++++++++++++++++++++++++++++++++++++++ lib/uk9p/Makefile.uk | 1 + lib/uk9p/exportsyms.uk | 13 ++ lib/uk9p/include/uk/9p.h | 260 +++++++++++++++++++++++++++++ 4 files changed, 697 insertions(+) create mode 100644 lib/uk9p/9p.c create mode 100644 lib/uk9p/include/uk/9p.h diff --git a/lib/uk9p/9p.c b/lib/uk9p/9p.c new file mode 100644 index 000000000000..38751b0318b0 --- /dev/null +++ b/lib/uk9p/9p.c @@ -0,0 +1,423 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Cristian Banu <cristb@xxxxxxxxx> + * + * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ + +#include <uk/config.h> +#include <uk/assert.h> +#include <uk/errptr.h> +#include <uk/9p.h> +#include <uk/9pdev.h> +#include <uk/9preq.h> +#include <uk/9pfid.h> + +struct uk_9preq *uk_9p_do_version(struct uk_9pdev *dev, + const char *requested, struct uk_9p_str *received) +{ + struct uk_9p_str requested_str; + struct uk_9preq *req; + int rc; + uint32_t new_msize; + + uk_9p_str_init(&requested_str, requested); + + uk_pr_debug("uk9p: TVERSION msize %u version %s\n", + dev->msize, requested); + + req = uk_9pdev_call(dev, UK_9P_TVERSION, __PAGE_SIZE, "ds", + dev->msize, &requested_str); + if (PTRISERR(req)) + return req; + + rc = uk_9preq_deserialize(req, "ds", &new_msize, received); + + if (rc) + return ERR2PTR(rc); + + uk_pr_debug("uk9p: RVERSION msize %u version %.*s\n", new_msize, + received->size, received->data); + + uk_9pdev_adjust_msize(dev, new_msize); + return req; +} + +struct uk_9pfid *uk_9p_do_attach(struct uk_9pdev *dev, uint32_t afid, + const char *uname, const char *aname, uint32_t n_uname) +{ + struct uk_9preq *req; + struct uk_9pfid *fid; + struct uk_9p_str uname_str; + struct uk_9p_str aname_str; + int rc; + + uk_9p_str_init(&uname_str, uname); + uk_9p_str_init(&aname_str, aname); + + fid = uk_9pdev_fid_create(dev); + if (PTRISERR(fid)) + return fid; + + uk_pr_debug("uk9p: TATTACH fid %u afid %u uname %s aname %s n_uname %u\n", + fid->fid, afid, uname, aname, n_uname); + + req = uk_9pdev_call(dev, UK_9P_TATTACH, __PAGE_SIZE, "ddssd", + fid->fid, afid, &uname_str, &aname_str, n_uname); + if (PTRISERR(req)) { + uk_9pdev_fid_release(fid); + return (void *)req; + } + + rc = uk_9preq_deserialize(req, "Q", &fid->qid); + uk_9pdev_req_remove(dev, req); + + uk_pr_debug("uk9p: RATTACH qid type %u version %u path %lu\n", + fid->qid.type, fid->qid.version, fid->qid.path); + + if (rc < 0) { + uk_9pdev_fid_release(fid); + return ERR2PTR(rc); + } + + return fid; +} + +int uk_9p_do_flush(struct uk_9pdev *dev, uint16_t oldtag) +{ + struct uk_9preq *req; + + uk_pr_debug("uk9p: TFLUSH oldtag %u\n", oldtag); + req = uk_9pdev_call(dev, UK_9P_TFLUSH, __PAGE_SIZE, "w", oldtag); + if (PTRISERR(req)) + return PTR2ERR(req); + + uk_pr_debug("uk9p: RFLUSH\n"); + uk_9pdev_req_remove(dev, req); + + return 0; +} + +#if 0 +struct uk_9pfid *uk_9p_do_walk_many(struct uk_9pdev *dev, struct uk_9pfid *fid, + const char **wname, int nwname) +{ + struct uk_9preq *req; + struct uk_9pfid *fid; +} +#endif + +struct uk_9pfid *uk_9p_do_walk(struct uk_9pdev *dev, struct uk_9pfid *fid, + const char *name) +{ + struct uk_9preq *req; + struct uk_9pfid *newfid; + struct uk_9p_str name_str; + uint16_t nwqid; + uint16_t nwname; + int rc; + + uk_9p_str_init(&name_str, name); + + newfid = uk_9pdev_fid_create(dev); + if (PTRISERR(newfid)) + return newfid; + + nwname = name ? 1 : 0; + + if (name) { + uk_pr_debug("uk9p: TWALK fid %u newfid %u nwname %d name %s\n", + fid->fid, newfid->fid, nwname, name); + req = uk_9pdev_call(dev, UK_9P_TWALK, __PAGE_SIZE, "ddws", + fid->fid, newfid->fid, nwname, &name_str); + } else { + uk_pr_debug("uk9p: TWALK fid %u newfid %u nwname %d\n", + fid->fid, newfid->fid, nwname); + req = uk_9pdev_call(dev, UK_9P_TWALK, __PAGE_SIZE, "ddw", + fid->fid, newfid->fid, nwname); + } + + if (PTRISERR(req)) { + /* + * Don't clunk if request has finished with error, as the fid + * is invalid. + */ + newfid->was_removed = 1; + rc = PTR2ERR(req); + goto out; + } + + rc = uk_9preq_deserialize(req, "w", &nwqid); + if (rc < 0) + goto out_req; + + uk_pr_debug("uk9p: RWALK nwqid %u\n", nwqid); + + if (nwqid != nwname) { + rc = -ENOENT; + goto out_req; + } + + + if (nwname) { + rc = uk_9preq_deserialize(req, "Q", &newfid->qid); + if (rc < 0) + goto out_req; + } else + newfid->qid = fid->qid; + + rc = 0; +out_req: + uk_9pdev_req_remove(dev, req); +out: + if (rc) { + uk_9pdev_fid_release(newfid); + return ERR2PTR(rc); + } + + return newfid; +} + +int uk_9p_do_open(struct uk_9pdev *dev, struct uk_9pfid *fid, uint8_t mode) +{ + struct uk_9preq *req; + int rc; + + uk_pr_debug("uk9p: TOPEN fid %u mode %u\n", fid->fid, mode); + + req = uk_9pdev_call(dev, UK_9P_TOPEN, __PAGE_SIZE, "db", + fid->fid, mode); + if (PTRISERR(req)) + return PTR2ERR(req); + + rc = uk_9preq_deserialize(req, "Qd", &fid->qid, &fid->iounit); + uk_9pdev_req_remove(dev, req); + + uk_pr_debug("uk9p: ROPEN qid type %u version %u path %lu iounit %u\n", + fid->qid.type, fid->qid.version, fid->qid.path, + fid->iounit); + + return rc; +} + +int uk_9p_do_create(struct uk_9pdev *dev, struct uk_9pfid *fid, + const char *name, uint32_t perm, uint8_t mode, + const char *extension) +{ + struct uk_9preq *req; + struct uk_9p_str name_str; + struct uk_9p_str extension_str; + int rc; + + uk_9p_str_init(&name_str, name); + uk_9p_str_init(&extension_str, extension); + + uk_pr_debug("uk9p: TCREATE fid %u name %s perm %u mode %u ext %s\n", + fid->fid, name, perm, mode, extension); + + req = uk_9pdev_call(dev, UK_9P_TCREATE, __PAGE_SIZE, "dsdbs", + fid->fid, &name_str, perm, mode, &extension_str); + if (PTRISERR(req)) + return PTR2ERR(req); + + rc = uk_9preq_deserialize(req, "Qd", &fid->qid, &fid->iounit); + uk_9pdev_req_remove(dev, req); + + uk_pr_debug("uk9p: RCREATE qid type %u version %u path %lu iounit %u\n", + fid->qid.type, fid->qid.version, fid->qid.path, + fid->iounit); + + return rc; +} + +int uk_9p_do_remove(struct uk_9pdev *dev, struct uk_9pfid *fid) +{ + struct uk_9preq *req; + + /* The fid is considered invalid even if the remove fails. */ + fid->was_removed = 1; + + uk_pr_debug("uk9p: TREMOVE fid %u\n", fid->fid); + req = uk_9pdev_call(dev, UK_9P_TREMOVE, __PAGE_SIZE, "d", fid->fid); + if (PTRISERR(req)) + return PTR2ERR(req); + + uk_9pdev_req_remove(dev, req); + uk_pr_debug("uk9p: RREMOVE\n"); + + return 0; +} + +int uk_9p_do_clunk(struct uk_9pdev *dev, struct uk_9pfid *fid) +{ + struct uk_9preq *req; + + if (fid->was_removed) + return 0; + + uk_pr_debug("uk9p: TCLUNK fid %u\n", fid->fid); + req = uk_9pdev_call(dev, UK_9P_TCLUNK, __PAGE_SIZE, "d", fid->fid); + if (PTRISERR(req)) + return PTR2ERR(req); + + uk_9pdev_req_remove(dev, req); + uk_pr_debug("uk9p: RCLUNK\n"); + + return 0; +} + +int64_t uk_9p_do_read(struct uk_9pdev *dev, struct uk_9pfid *fid, + uint64_t offset, uint32_t count, char *buf) +{ + struct uk_9preq *req; + int64_t rc; + + if (fid->iounit != 0) + count = MIN(count, fid->iounit); + count = MIN(count, dev->msize - 23); + + uk_pr_debug("uk9p: TREAD fid %u offset %lu count %u\n", fid->fid, + offset, count); + req = uk_9pdev_call(dev, UK_9P_TREAD, count + 23, "dqd", fid->fid, + offset, count); + if (PTRISERR(req)) + return PTR2ERR(req); + + rc = uk_9preq_deserialize(req, "d", &count); + if (rc < 0) + goto out; + + uk_pr_debug("uk9p: RREAD count %u\n", count); + + rc = uk_9preq_copy_to(req, buf, count); + if (rc < 0) + goto out; + + rc = count; + +out: + uk_9pdev_req_remove(dev, req); + return rc; +} + +int64_t uk_9p_do_write(struct uk_9pdev *dev, struct uk_9pfid *fid, + uint64_t offset, uint32_t count, const char *buf) +{ + struct uk_9preq *req; + int64_t rc; + + count = MIN(count, fid->iounit); + count = MIN(count, dev->msize - 23); + + uk_pr_debug("uk9p: TWRITE fid %u offset %lu count %u\n", fid->fid, + offset, count); + req = uk_9pdev_req_create(dev, UK_9P_TWRITE, count + 23); + if (PTRISERR(req)) + return PTR2ERR(req); + + rc = uk_9preq_serialize(req, "dqd", fid->fid, offset, count); + if (rc < 0) + goto out; + + rc = uk_9preq_copy_from(req, buf, count); + if (rc < 0) + goto out; + + rc = uk_9preq_ready(req); + if (rc < 0) + goto out; + + rc = uk_9pdev_request(dev, req); + if (rc < 0) + goto out; + + rc = uk_9preq_waitreply(req); + if (rc < 0) + goto out; + + rc = uk_9preq_deserialize(req, "d", &count); + if (rc < 0) + goto out; + + uk_pr_debug("uk9p: RWRITE count %u\n", count); + + rc = count; + +out: + uk_9pdev_req_remove(dev, req); + return rc; +} + +struct uk_9preq *uk_9p_do_stat(struct uk_9pdev *dev, struct uk_9pfid *fid, + struct uk_9p_stat *stat) +{ + struct uk_9preq *req; + int rc; + uint16_t dummy; + + uk_pr_debug("uk9p: TSTAT fid %u\n", fid->fid); + req = uk_9pdev_call(dev, UK_9P_TSTAT, __PAGE_SIZE, "d", fid->fid); + if (PTRISERR(req)) + return req; + + rc = uk_9preq_deserialize(req, "wS", &dummy, stat); + if (rc) + return ERR2PTR(rc); + uk_pr_debug("uk9p: RSTAT\n"); + + return req; +} + +int uk_9p_do_wstat(struct uk_9pdev *dev, struct uk_9pfid *fid, + struct uk_9p_stat *stat) +{ + struct uk_9preq *req; + + /* + * The packed size of stat is 61 bytes + the size occupied by the + * strings. + */ + stat->size = 61; + stat->size += stat->name.size; + stat->size += stat->uid.size; + stat->size += stat->gid.size; + stat->size += stat->muid.size; + stat->size += stat->extension.size; + + uk_pr_debug("uk9p: TWSTAT fid %u\n", fid->fid); + req = uk_9pdev_call(dev, UK_9P_TWSTAT, __PAGE_SIZE, "dwS", fid->fid, + stat->size + 2, stat); + if (PTRISERR(req)) + return PTR2ERR(req); + uk_9pdev_req_remove(dev, req); + uk_pr_debug("uk9p: RWSTAT"); + + return 0; +} diff --git a/lib/uk9p/Makefile.uk b/lib/uk9p/Makefile.uk index cd4bf4b8a033..efc0ee748ad4 100644 --- a/lib/uk9p/Makefile.uk +++ b/lib/uk9p/Makefile.uk @@ -7,3 +7,4 @@ LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9pdev_trans.c LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9preq.c LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9pdev.c LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9pfid.c +LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9p.c diff --git a/lib/uk9p/exportsyms.uk b/lib/uk9p/exportsyms.uk index 5cd7817bf5c8..4f950a0d3f79 100644 --- a/lib/uk9p/exportsyms.uk +++ b/lib/uk9p/exportsyms.uk @@ -28,3 +28,16 @@ uk_9pdev_req_remove uk_9pdev_fid_create uk_9pfid_get uk_9pfid_put + +uk_9p_do_version +uk_9p_do_attach +uk_9p_do_flush +uk_9p_do_walk +uk_9p_do_open +uk_9p_do_create +uk_9p_do_remove +uk_9p_do_clunk +uk_9p_do_read +uk_9p_do_write +uk_9p_do_stat +uk_9p_do_wstat diff --git a/lib/uk9p/include/uk/9p.h b/lib/uk9p/include/uk/9p.h new file mode 100644 index 000000000000..d683138e8279 --- /dev/null +++ b/lib/uk9p/include/uk/9p.h @@ -0,0 +1,260 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Cristian Banu <cristb@xxxxxxxxx> + * + * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +#ifndef __UK_9P__ +#define __UK_9P__ + +#include <stdarg.h> +#include <stdint.h> +#include <string.h> +#include <uk/config.h> +#include <uk/9p_core.h> +#include <uk/9pdev.h> +#include <uk/9preq.h> +#include <uk/9pfid.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Negotiates the version and is the first message in a 9P session. + * + * @param dev + * The Unikraft 9P Device. + * @param requested + * Requested version string. + * @param received + * Received version string. + * @return + * - (!ERRPTR): The request. It must be removed only after all accesses to + * the received version string are done. + * - ERRPTR: The error returned either by the API or by the remote server. + */ +struct uk_9preq *uk_9p_do_version(struct uk_9pdev *dev, + const char *requested, struct uk_9p_str *received); + +/** + * Negotiates the version and is the first message in a 9P session. + * + * @param dev + * The Unikraft 9P Device. + * @param afid + * Authentication fid, usually UK_9P_NOFID. + * @param uname + * User name, can be empty string for virtio/xen. + * @param aname + * The file tree to access, can be left empty for virtio/xen. + * @param n_uname + * Numeric uname, part of the 9P2000.u unix extension to the protocol. + * @return + * - (!ERRPTR): The fid of the root directory in the accessed file tree. + * - ERRPTR: The error returned either by the API or by the remote server. + */ +struct uk_9pfid *uk_9p_do_attach(struct uk_9pdev *dev, uint32_t afid, + const char *uname, const char *aname, uint32_t n_uname); + +/** + * Flushes the given request tag, canceling the corresponding request if + * the server has not yet replied to it. + * + * @param dev + * The Unikraft 9P Device. + * @param oldtag + * Request tag. + * @return + * - 0: Successful. + * - (< 0): An error occurred. + */ +int uk_9p_do_flush(struct uk_9pdev *dev, uint16_t oldtag); + +/** + * Walks the filesystem tree from the given directory fid, attempting to obtain + * the fid for the child with the given name. + * + * @param dev + * The Unikraft 9P Device. + * @param fid + * Directory fid. + * @param name + * File name. + * @return + * - (!ERRPTR): The fid of the child entry. + * - ERRPTR: The error returned either by the API or by the remote server. + */ +struct uk_9pfid *uk_9p_do_walk(struct uk_9pdev *dev, struct uk_9pfid *fid, + const char *name); + +/** + * Opens the fid with the given mode. + * + * @param dev + * The Unikraft 9P Device. + * @param fid + * 9P fid. + * @param mode + * 9P open mode. + * @return + * - 0: Successful. + * - (< 0): An error occurred. + */ +int uk_9p_do_open(struct uk_9pdev *dev, struct uk_9pfid *fid, uint8_t mode); + +/** + * Creates a new file with the given name in the directory associated with fid, + * and associates fid with the newly created file, opening it with the given + * mode. + * + * @param dev + * The Unikraft 9P Device. + * @param fid + * 9P directory fid. + * @param name + * Name of the created file. + * @param perm + * 9P permission bits. + * @param mode + * 9P open mode. + * @param extension + * String describing special files, depending on the mode bit. + * @return + * - 0: Successful. + * - (< 0): An error occurred. + */ +int uk_9p_do_create(struct uk_9pdev *dev, struct uk_9pfid *fid, + const char *name, uint32_t perm, uint8_t mode, + const char *extension); + +/** + * Removes the file associated with fid. + * + * @param dev + * The Unikraft 9P Device. + * @param fid + * 9P fid to remove. + * @return + * - 0: Successful. + * - (< 0): An error occurred. + */ +int uk_9p_do_remove(struct uk_9pdev *dev, struct uk_9pfid *fid); + +/** + * Clunks the fid, telling the server to forget its previous association. + * + * @param dev + * The Unikraft 9P Device. + * @param fid + * 9P fid to clunk. + * @return + * - 0: Successful. + * - (< 0): An error occurred. + */ +int uk_9p_do_clunk(struct uk_9pdev *dev, struct uk_9pfid *fid); + +/** + * Reads count bytes from the fid, starting from the given offset, placing + * them into the buffer. + * + * @param dev + * The Unikraft 9P Device. + * @param fid + * 9P fid to read from. + * @param offset + * Offset at which to start reading. + * @param count + * Maximum number of bytes to read. + * @param buf + * Buffer to read into. + * @return + * - (>= 0): Amount of bytes read. + * - (< 0): An error occurred. + */ +int64_t uk_9p_do_read(struct uk_9pdev *dev, struct uk_9pfid *fid, + uint64_t offset, uint32_t count, char *buf); + +/** + * Writes count bytes from buf to the fid, starting from the given offset. + * + * @param dev + * The Unikraft 9P Device. + * @param fid + * 9P fid to write to. + * @param offset + * Offset at which to start writing. + * @param count + * Maximum number of bytes to write. + * @param buf + * Data to be written. + * @return + * - (>= 0): Amount of bytes written. + * - (< 0): An error occurred. + */ +int64_t uk_9p_do_write(struct uk_9pdev *dev, struct uk_9pfid *fid, + uint64_t offset, uint32_t count, const char *buf); + +/** + * Stats the given fid and places the data into the given stat structure. + * + * @param dev + * The Unikraft 9P Device. + * @param fid + * 9P fid to stat. + * @param stat + * Where to store the stat results. + * @return + * - (!ERRPTR): The request. It must be removed only after all accesses to + * the strings in the stat structure are over. + * - ERRPTR: The error returned either by the API or by the remote server. + */ +struct uk_9preq *uk_9p_do_stat(struct uk_9pdev *dev, struct uk_9pfid *fid, + struct uk_9p_stat *stat); + +/** + * Changes the file attributes of a given fid. + * + * @param dev + * The Unikraft 9P Device. + * @param fid + * 9P fid to clunk. + * @return + * - 0: Successful. + * - (< 0): An error occurred. + */ +int uk_9p_do_wstat(struct uk_9pdev *dev, struct uk_9pfid *fid, + struct uk_9p_stat *stat); + +#ifdef __cplusplus +} +#endif + +#endif /* __UK_9P__ */ -- 2.11.0 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |