[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH] lib/vfscore: Add anonymous pipe
Hi Bogdan Thanks for this patch, we certainly need the pipe primitive for Unikraft. However, this patch needs a bit of rework. First of all, it should also compile using nolibc, but it fails now because 'sys/ioctl.h' is missing from nolibc. For the rest of the comments, please see inline. On 6/29/19 1:03 PM, Bogdan Lascu wrote: > Adds pipe function that creates an anonymous pipe and creates functions > that write and read to a pipe file descriptor. > > Signed-off-by: Bogdan Lascu <lascu.bogdan96@xxxxxxxxx> > --- > lib/vfscore/Makefile.uk | 1 + > lib/vfscore/exportsyms.uk | 1 + > lib/vfscore/include/vfscore/pipe.h | 67 ++++++ > lib/vfscore/pipe.c | 409 > +++++++++++++++++++++++++++++++++++++ > 4 files changed, 478 insertions(+) > create mode 100644 lib/vfscore/include/vfscore/pipe.h > create mode 100644 lib/vfscore/pipe.c > > diff --git a/lib/vfscore/Makefile.uk b/lib/vfscore/Makefile.uk > index 0166e612..4e519367 100644 > --- a/lib/vfscore/Makefile.uk > +++ b/lib/vfscore/Makefile.uk > @@ -14,6 +14,7 @@ LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/task.c > LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/lookup.c > LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/fops.c > LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/subr_uio.c > +LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/pipe.c > > EXTRA_LD_SCRIPT-$(CONFIG_LIBVFSCORE) += $(LIBVFSCORE_BASE)/extra.ld > > diff --git a/lib/vfscore/exportsyms.uk b/lib/vfscore/exportsyms.uk > index da7fbaea..16a0f86a 100644 > --- a/lib/vfscore/exportsyms.uk > +++ b/lib/vfscore/exportsyms.uk > @@ -57,6 +57,7 @@ writev > truncate > mknod > preadv > +pipe > ioctl > fdatasync > fdopendir > diff --git a/lib/vfscore/include/vfscore/pipe.h > b/lib/vfscore/include/vfscore/pipe.h > new file mode 100644 > index 00000000..0c25f4ed > --- /dev/null > +++ b/lib/vfscore/include/vfscore/pipe.h > @@ -0,0 +1,67 @@ > +/* pipe.h - pipe header > + * > + * Authors: Bogdan-George Lascu <lascu.bogdan96@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 <vfscore/file.h> > +#include <uk/wait.h> > +#include <uk/mutex.h> > + > +#define PIPE_MAX_SIZE (1 << 16) > + > + > +struct pipe_buf { > + char *data; > + unsigned int max_size; > + size_t len; /* Total len of buffer. */ > + unsigned int r_off; > + unsigned int w_off; > +}; > + > +struct pipe_info { > + struct pipe_buf *buf; > + int w_count; > + int r_count; > + int flags; > + struct uk_mutex pipe_lock; > + struct uk_waitq wq; > +}; It would help to add some comments for each structure and for each of the structure fields. > + > +struct pipe_buf *alloc_pipe_buf(int size); > +struct pipe_info *alloc_pipe_info(int size, int flags); > + > +void free_pipe_buf(struct pipe_buf *pipe_buf); > +void free_pipe_info(struct pipe_info *pipe_info); The same applies for these functions. > + > + > +#define PIPE_LOCK(__pipe) uk_mutex_lock(&__pipe->pipe_lock) > +#define PIPE_UNLOCK(__pipe) uk_mutex_unlock(&__pipe->pipe_lock) I fail to understand why we use this header with all these declarations considering that the only public function of the pipe implementation is the POSIX pipe(). > + > diff --git a/lib/vfscore/pipe.c b/lib/vfscore/pipe.c > new file mode 100644 > index 00000000..15137627 > --- /dev/null > +++ b/lib/vfscore/pipe.c > @@ -0,0 +1,409 @@ > +/* pipe.c - pipe implementation > + * > + * Authors: Bogdan-George Lascu <lascu.bogdan96@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 <stdio.h> > +#include <string.h> > +#include <vfscore/pipe.h> > +#include <vfscore/file.h> > +#include <vfscore/vnode.h> > +#include <vfscore/fs.h> > +#include <uk/wait.h> > +#include <sys/ioctl.h> > + > + > +size_t get_pipe_buf_free_space(struct pipe_buf *pipe_buf) > +{ > + return pipe_buf->max_size - pipe_buf->len; > +} > + > +int pipe_can_read(struct pipe_buf *pipe_buf) > +{ > + return pipe_buf->len > 0; > +} > + > +/* Write blocks until there is enough space to write the entire user buffer. > */ > +int pipe_can_write(struct pipe_buf *pipe_buf, size_t user_buf_len) > +{ > + return get_pipe_buf_free_space(pipe_buf) >= user_buf_len; > +} > + > + > +static int pipe_write(struct vnode *vnode, > + struct uio *buf, int ioflag __unused) > +{ > + struct pipe_info *pipe = vnode->v_data; > + struct pipe_buf *pipe_buf = pipe->buf; > + struct iovec iovec; > + int to_write = 0; > + int i; > + > + if (!pipe->r_count) { > + // TODO before returning the error, send a SIGPIPE signal. > + return -EPIPE; > + } > + > + for (i = 0; i < buf->uio_iovcnt; i++) > + to_write += buf->uio_iov[i].iov_len; > + > + uk_waitq_wait_event(&pipe->wq, pipe_can_write(pipe_buf, to_write)); > + PIPE_LOCK(pipe); > + for (i = 0; i < buf->uio_iovcnt; i++) { > + iovec = buf->uio_iov[i]; > + > + /* Copy the user buffer in pipe buffer. */ > + if (pipe_buf->w_off + iovec.iov_len <= pipe_buf->max_size) { > + memcpy(pipe_buf->data + pipe_buf->w_off, > + iovec.iov_base, > + iovec.iov_len); > + } else { > + int first_copy_bytes; > + int second_copy_bytes; > + > + /* Copy the from current offset to the end. */ > + first_copy_bytes = pipe_buf->max_size - pipe_buf->w_off; > + memcpy(pipe_buf->data + pipe_buf->w_off, > + iovec.iov_base, > + first_copy_bytes); > + > + /* Copy from the begging the remaining bytes. */ > + second_copy_bytes = pipe_buf->w_off > + + iovec.iov_len > + - pipe_buf->max_size; > + > + memcpy(pipe_buf->data, > + iovec.iov_base + first_copy_bytes, > + second_copy_bytes); > + > + } > + > + /* Update buffer write offset. */ > + pipe_buf->w_off = (pipe_buf->w_off + iovec.iov_len) > + % pipe_buf->max_size; > + > + /* Update pipe buf len. */ > + pipe_buf->len += iovec.iov_len; > + > + /* Update bytes written. */ > + buf->uio_resid -= iovec.iov_len; > + } > + PIPE_UNLOCK(pipe); > + uk_waitq_wake_up(&pipe->wq); > + > + return 0; > +} > + > +static int pipe_read(struct vnode *vnode, > + struct vfscore_file *vfscore_file __unused, > + struct uio *buf, int ioflag __unused) > +{ > + struct pipe_info *pipe = vnode->v_data; > + struct pipe_buf *pipe_buf = pipe->buf; > + struct iovec iovec; > + int to_read; > + int i; > + > + if ((vfscore_file->f_flags & O_NONBLOCK) && pipe_buf->len == 0) > + return -EAGAIN; > + > + uk_waitq_wait_event(&pipe->wq, pipe_can_read(pipe_buf)); > + PIPE_LOCK(pipe); > + for (i = 0; i < buf->uio_iovcnt; i++) { > + iovec = buf->uio_iov[i]; > + to_read = MIN(iovec.iov_len, pipe_buf->len); > + if (to_read == 0) > + break; > + > + /* Copy from pipe buffer to user buffer. */ > + if (pipe_buf->r_off + to_read <= pipe_buf->max_size) { > + memcpy(iovec.iov_base, > + pipe_buf->data + pipe_buf->r_off, > + to_read); > + } else { > + int first_copy_bytes; > + int second_copy_bytes; > + > + /* Copy the from current offset to the end. */ > + first_copy_bytes = pipe_buf->max_size - pipe_buf->r_off; > + memcpy(iovec.iov_base, > + pipe_buf->data + pipe_buf->r_off, > + first_copy_bytes); > + > + /* Copy from the begging the remaining bytes. */ > + second_copy_bytes = pipe_buf->r_off > + + to_read > + - pipe_buf->max_size; > + > + memcpy(iovec.iov_base + first_copy_bytes, > + pipe_buf->data, > + second_copy_bytes); > + > + } > + > + /* Update read buffer offset. */ > + pipe_buf->r_off = (pipe_buf->r_off + to_read) % > pipe_buf->max_size; You have a checkpatch warning here. I think you can put the assigned value on the next line. > + > + /* Update pipe buffer len. */ > + pipe_buf->len -= to_read; > + > + /* Update bytes read which will be returned. */ > + buf->uio_resid -= to_read; > + } > + PIPE_UNLOCK(pipe); > + uk_waitq_wake_up(&pipe->wq); > + > + return 0; > +} > + > +static int pipe_close(struct vnode *vnode, > + struct vfscore_file *file) > +{ > + struct pipe_info *pipe = vnode->v_data; > + > + PIPE_LOCK(pipe); > + > + if (file->f_flags & UK_FREAD) > + pipe->r_count--; > + > + if (file->f_flags & UK_FWRITE) > + pipe->w_count--; > + > + if (!pipe->r_count && !pipe->w_count) > + free_pipe_info(pipe); > + > + PIPE_UNLOCK(pipe); > + > + return 0; > +} > + > +static int pipe_seek(struct vnode *vnode __unused, > + struct vfscore_file *file __unused, > + off_t off1 __unused, off_t off2 __unused) > +{ > + return -EPIPE; > +} > + > +static int pipe_ioctl(struct vnode *vnode, struct vfscore_file *file > __unused, > + unsigned long com, void *data __unused) > +{ > + struct pipe_info *pipe = vnode->v_data; > + struct pipe_buf *pipe_buf __unused = pipe->buf; > + > + switch (com) { > +#ifdef FIONREAD > + case FIONREAD: > + PIPE_LOCK(pipe); > + *(int *)data = pipe_buf->len; > + PIPE_UNLOCK(pipe); > + return 0; > +#endif > + default: > + return -EINVAL; > + } > +} > + > +static struct vnops pipe_fops = { > + .vop_read = pipe_read, > + .vop_write = pipe_write, > + .vop_close = pipe_close, > + .vop_seek = pipe_seek, > + .vop_ioctl = pipe_ioctl, > +}; > + > +struct pipe_buf *alloc_pipe_buf(int max_size) > +{ > + struct pipe_buf *pipe_buf; > + > + pipe_buf = uk_calloc(uk_alloc_get_default(), 1, sizeof(*pipe_buf)); > + if (!pipe_buf) > + return NULL; > + pipe_buf->data = uk_calloc(uk_alloc_get_default(), 1, > + max_size * sizeof(char)); > + if (!pipe_buf->data) { > + uk_free(uk_alloc_get_default(), pipe_buf); > + return NULL; > + } > + > + pipe_buf->r_off = 0; > + pipe_buf->w_off = 0; > + pipe_buf->max_size = max_size; > + pipe_buf->len = 0; > + > + return pipe_buf; > +} > + > +struct pipe_info *alloc_pipe_info(int size, int flags) > +{ > + struct pipe_info *pipe_info; > + > + pipe_info = uk_calloc(uk_alloc_get_default(), 1, sizeof(*pipe_info)); > + if (!pipe_info) > + return NULL; > + > + pipe_info->r_count = 1; > + pipe_info->w_count = 1; > + pipe_info->flags = flags; > + > + pipe_info->buf = alloc_pipe_buf(size); > + if (!pipe_info->buf) { > + uk_free(uk_alloc_get_default(), pipe_info); > + return NULL; > + } > + > + uk_mutex_init(&pipe_info->pipe_lock); > + uk_waitq_init(&pipe_info->wq); > + > + return pipe_info; > +} > + > +void free_pipe_buf(struct pipe_buf *pipe_buf) > +{ > + uk_free(uk_alloc_get_default(), pipe_buf->data); > + uk_free(uk_alloc_get_default(), pipe_buf); > +} > +void free_pipe_info(struct pipe_info *pipe_info) > +{ > + free_pipe_buf(pipe_info->buf); > + uk_free(uk_alloc_get_default(), pipe_info); > +} > + > + > +int pipe(int pipefd[2]) > +{ > + int ret = 0; > + int w_fd, r_fd; > + struct dentry *w_dentry, *r_dentry; > + struct vnode *r_vnode, *w_vnode; > + struct vfscore_file *r_file, *w_file; > + struct pipe_info *pipe_info; > + > + /* Reserve file descriptor number. */ > + r_fd = vfscore_alloc_fd(); > + w_fd = vfscore_alloc_fd(); > + if (r_fd < 0 || w_fd < 0) { > + ret = -ENFILE; > + goto ERR_EXIT; > + } > + > + /* Allocate file, dentry, and vnode. */ > + r_file = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_file)); > + w_file = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_file)); > + if (!r_file || !w_file) { > + ret = -ENOMEM; > + goto ERR_MALLOC_FILE; > + } > + > + r_dentry = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_dentry)); > + w_dentry = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_dentry)); > + if (!r_dentry || !w_dentry) { > + ret = -ENOMEM; > + goto ERR_MALLOC_DENTRY; > + } > + > + r_vnode = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_vnode)); > + w_vnode = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_vnode)); > + if (!r_vnode || !w_vnode) { > + ret = -ENOMEM; > + goto ERR_MALLOC_VNODE; > + } > + > + /* Allocate pipe internal structure. */ > + pipe_info = alloc_pipe_info(PIPE_MAX_SIZE, 0); > + if (!pipe_info) { > + ret = -ENOMEM; > + goto ERR_ALLOC_PIPE_INFO; > + } > + > + /* Fill out necessary fields. */ > + r_file->fd = r_fd; > + w_file->fd = r_fd; > + > + r_file->f_count = 1; > + w_file->f_count = 1; > + > + r_file->f_flags = UK_FREAD; > + w_file->f_flags = UK_FWRITE; > + > + r_file->f_dentry = r_dentry; > + w_file->f_dentry = w_dentry; > + > + r_dentry->d_vnode = r_vnode; > + w_dentry->d_vnode = w_vnode; > + > + > + r_vnode->v_op = &pipe_fops; > + w_vnode->v_op = &pipe_fops; > + > + uk_mutex_init(&r_vnode->v_lock); > + uk_mutex_init(&w_vnode->v_lock); > + > + r_vnode->v_refcnt = 1; > + w_vnode->v_refcnt = 1; > + > + r_vnode->v_data = pipe_info; > + w_vnode->v_data = pipe_info; > + > + /* Assign the file descriptors to the corresponding vfs_file. */ > + ret = vfscore_install_fd(r_fd, r_file); > + if (ret) > + goto ERR_VFS_INSTALL; > + > + ret = vfscore_install_fd(w_fd, w_file); > + if (ret) > + goto ERR_VFS_INSTALL; > + > + /* Fill pipefd fields. */ > + pipefd[0] = r_fd; > + pipefd[1] = w_fd; There is so much duplicated code in this function, can't we make a static function at least for the common bits, the bits that have exactly the same initialization values? > + > + return ret; > + > +ERR_VFS_INSTALL: > + free_pipe_info(pipe_info); > +ERR_ALLOC_PIPE_INFO: > + uk_free(uk_alloc_get_default(), r_vnode); > + uk_free(uk_alloc_get_default(), w_vnode); > +ERR_MALLOC_VNODE: > + uk_free(uk_alloc_get_default(), r_dentry); > + uk_free(uk_alloc_get_default(), w_dentry); > +ERR_MALLOC_DENTRY: > + uk_free(uk_alloc_get_default(), r_file); > + uk_free(uk_alloc_get_default(), w_file); > +ERR_MALLOC_FILE: > + vfscore_put_fd(r_fd); > + vfscore_put_fd(w_fd); > +ERR_EXIT: > + UK_ASSERT(ret < 0); > + return ret; > +} > + > _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |