[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Minios-devel] [UNIKRAFT PATCH v3] lib/vfscore: Add anonymous pipe


  • To: Vlad-Andrei BĂDOIU (78692) <vlad_andrei.badoiu@xxxxxxxxxxxxxxx>, "minios-devel@xxxxxxxxxxxxx" <minios-devel@xxxxxxxxxxxxx>
  • From: Costin Lupu <costin.lupu@xxxxxxxxx>
  • Date: Fri, 20 Sep 2019 17:54:23 +0300
  • Cc: Bogdan Lascu <lascu.bogdan96@xxxxxxxxx>
  • Delivery-date: Fri, 20 Sep 2019 14:54:32 +0000
  • Ironport-phdr: 9a23:Efn5ChQ270vK8UOLjLr4nsrz2dpsv+yvbD5Q0YIujvd0So/mwa67ZRaBt8tkgFKBZ4jH8fUM07OQ7/m7HzZaqsbZ+DBaKdoQDkVD0Z1X1yUbQ+e9QXXhK/DrayFoVO9jb3RCu0+BDE5OBczlbEfTqHDhpRQbGxH4KBYnbr+tQt2agMu4zf299IPOaAtUmjW9falyLBKrpgnNq8Uam4RvJrs/xxfTvHdEZetayGB0KVmOmxrw+tq88IRs/ihNpf4t7dJMXbn/c68lUbFWETMqPnwv6sb2rxfDVwyP5nUdUmUSjBVFBhXO4Q/5UJnsrCb0r/Jx1yaGM8L4S7A0Qimi4LxwSBD0kicHNiU2/3/Rh8dtka9UuhOhpxh4w47JfIGYMed1c63Bcd8GQ2dKQ91cXDJdDIyic4QPDvIBPedGoIn7u1sOtga1CQ21CO/y1jNEmnr60Ksn2OojDA7GxhQtEc8QvnTarNv7N6kcXu66w6bK0TrNYOhb2Svk6IXSbhwtvf+BULB2fMHMyUcvDQTFjlCIpIH7ODOVzfgNs2md7+F9U+yvlnYnqxxsqTWo2sgsjZLJhp4UylDC7yl5xJs1JcWlSENgfdGkC4FctzmHN4RtWM8iWWZotT88x7Ybt5C7ey0Kx44mxx7Zc/GGfJaH4hT7VOaLJjd4hmxqd66jhxqo9kig0OL8W8+p21hJtipIisTAu38Q2xDJ6cWKSuFx8lm/1TuNzQze5PlILV07mKbGMZIswb49moANvUnNECL6glj6gLOZe0gi5+Om8f7oYq/8qZ+ZL4J0jwb+PbkwlcGnGuQ4NxQOX3Cc+eShyL3v5U35T6tOjv0xiqTZrpXaKt4apq69GQNazp0j5wynDze7y9sUh2MHLFVddBKGiYjmJU3OLejlAfqwnligijRmyvDcMrH/HJnALGLPnbn5cbZ48UFcyQ4zzd5F55JTD7EMOO78WkjqtNzEDx85NRa4w+L6CNVly4MTQn6AArSDPKPKrF+H/fgjI/OLZIMNojbyN+Al5+LyjX8+gVIdebOm3YALZ3ClBPhpOEKZYXXxjdgbF2cHugszQffliF2HSzFTZnKyU7gg6TE8DYKsFZ3DSZy1gLydwCe7GYVbZmVHClCKEHfocJ6EV+4RZy2MPM9ujDgEWKOlS48gzhGuqBT6x6BoL+XK/C0Ur5Xj1MJ65+fLjxE96SR0D9iB02GKV2x0gGcISCUr069nu0N9zEqM0bJmjPxZD9Bc/OlGXRo9NZ7d0ux3EMvyWh7cftiUUlqpWMmpASorQtIs298BeFxxG8+ljkOL4y3/Pbscm/miApAu/6Pr9dPdAOdA/DaZhPdw1RhuFtVLPGGRj6hz7QXSQYTAn0KYio6xabkQmifG7yGe1WDIpkYOFEY6VKTDXHcEI0fbs9n9zkfDVKO1T6QqNE1G08HIYv9Pa9voik4DSPr9NdD2Z2Oqh3z2FRuOgLSWY9y5VX8a2XD2D1MYkgZb2WueKEBqDSC6v2PYSjhzDU/HaFiq6fR07mm8GBxnhzqWZlFsguLmsiUeguaRHrZKhuoJ
  • Ironport-sdr: MvNXSjXQDtFcSdSuGgL+uHO2biAXgE6Ho1Ruqx+L0xTtPbziyndxg2sOwvH4MhHouBcQHGTpPe Cs8UrizgkDHg==
  • List-id: Mini-os development list <minios-devel.lists.xenproject.org>

Thanks for the review, Vlad! I've just sent the newlib patch. For your
other comments please see inline.

On 9/20/19 2:56 PM, Vlad-Andrei BĂDOIU (78692) wrote:
> Hey Costin,
> 
> Thanks for the patch. I have left two comments inline that may be useful
> for future revision of the pipe code.
> 
> Reviewed-by: Vlad-Andrei Badoiu       <vlad_andrei.badoiu@xxxxxxxxxxxxxxx>
> 
> Vlad
> 
> PS: Before upstreaming this patch, we need another patch to remove the
> pipe stub from newlib.
> 
> On 19.09.2019 14:15, Costin Lupu wrote:
>> From: Bogdan Lascu <lascu.bogdan96@xxxxxxxxx>
>>
>> This patch adds support for anonymous pipes. The underlying buffer is a ring
>> buffer whose size must be a power of 2. The creating of its file descriptors
>> follows closely the implementation for sockets in lwip glue code.
>>
>> Signed-off-by: Bogdan Lascu <lascu.bogdan96@xxxxxxxxx>
>> Signed-off-by: Costin Lupu <costin.lupu@xxxxxxxxx>
>> ---
>>  lib/vfscore/Config.uk     |  12 +-
>>  lib/vfscore/Makefile.uk   |   2 +
>>  lib/vfscore/exportsyms.uk |   1 +
>>  lib/vfscore/pipe.c        | 573 ++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 587 insertions(+), 1 deletion(-)
>>  create mode 100644 lib/vfscore/pipe.c
>>
>> diff --git a/lib/vfscore/Config.uk b/lib/vfscore/Config.uk
>> index 6cf6c63a..5deb7d04 100644
>> --- a/lib/vfscore/Config.uk
>> +++ b/lib/vfscore/Config.uk
>> @@ -1,6 +1,16 @@
>> -config LIBVFSCORE
>> +menuconfig LIBVFSCORE
>>      bool "vfscore: VFS Core Interface"
>>      default n
>>      select LIBNOLIBC if !HAVE_LIBC
>>      select LIBUKDEBUG
>>      select LIBUKLOCK
>> +
>> +if LIBVFSCORE
>> +
>> +config LIBVFSCORE_PIPE_SIZE_ORDER
>> +    int "Pipe size order"
>> +    default 16
>> +    help
>> +            The size of the internal buffer for anonymous pipes is 2^order.
>> +
>> +endif
>> diff --git a/lib/vfscore/Makefile.uk b/lib/vfscore/Makefile.uk
>> index 79878f26..e36c9217 100644
>> --- a/lib/vfscore/Makefile.uk
>> +++ b/lib/vfscore/Makefile.uk
>> @@ -14,6 +14,8 @@ 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
>> +LIBVFSCORE_PIPE_FLAGS-y += -Wno-cast-function-type
>>  LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/extra.ld
>>  
>>  
>> diff --git a/lib/vfscore/exportsyms.uk b/lib/vfscore/exportsyms.uk
>> index 46156098..70392721 100644
>> --- a/lib/vfscore/exportsyms.uk
>> +++ b/lib/vfscore/exportsyms.uk
>> @@ -109,3 +109,4 @@ vn_settimes
>>  vn_stat
>>  vn_unlock
>>  vfs_busy
>> +pipe
>> diff --git a/lib/vfscore/pipe.c b/lib/vfscore/pipe.c
>> new file mode 100644
>> index 00000000..4c561304
>> --- /dev/null
>> +++ b/lib/vfscore/pipe.c
>> @@ -0,0 +1,573 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause */
>> +/*
>> + * Authors: Bogdan-George Lascu <lascu.bogdan96@xxxxxxxxx>
>> + *          Costin Lupu <costin.lupu@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 <stdio.h>
>> +#include <string.h>
>> +#include <vfscore/file.h>
>> +#include <vfscore/fs.h>
>> +#include <vfscore/mount.h>
>> +#include <vfscore/vnode.h>
>> +#include <uk/wait.h>
>> +#include <sys/ioctl.h>
>> +
>> +/* We use the default size in Linux kernel */
>> +#define PIPE_MAX_SIZE       (1 << CONFIG_LIBVFSCORE_PIPE_SIZE_ORDER)
>> +
>> +struct pipe_buf {
>> +    /* The buffer */
>> +    char *data;
>> +    /* The buffer capacity, always a power of 2 */
>> +    unsigned long capacity;
>> +    /* Producer index */
>> +    unsigned long prod;
>> +    /* Consumer index */
>> +    unsigned long cons;
>> +
>> +    /* Read lock */
>> +    struct uk_mutex rdlock;
>> +    /* Write lock */
>> +    struct uk_mutex wrlock;
>> +
>> +    /* Readers queue */
>> +    struct uk_waitq rdwq;
>> +    /* Writers queue */
>> +    struct uk_waitq wrwq;
>> +};
>> +
>> +#define PIPE_BUF_IDX(buf, n)    ((n) & ((buf)->capacity - 1))
>> +#define PIPE_BUF_PROD_IDX(buf)  PIPE_BUF_IDX((buf), (buf)->prod)
>> +#define PIPE_BUF_CONS_IDX(buf)  PIPE_BUF_IDX((buf), (buf)->cons)
>> +
>> +struct pipe_file {
>> +    /* Pipe buffer */
>> +    struct pipe_buf *buf;
>> +    /* Write reference count */
>> +    int w_refcount;
>> +    /* Read reference count */
>> +    int r_refcount;
>> +    /* Flags */
>> +    int flags;
>> +};
>> +
>> +
>> +static struct pipe_buf *pipe_buf_alloc(int capacity)
>> +{
>> +    struct pipe_buf *pipe_buf;
>> +
>> +    UK_ASSERT(POWER_OF_2(capacity));
>> +
>> +    pipe_buf = malloc(sizeof(*pipe_buf));
>> +    if (!pipe_buf)
>> +            return NULL;
>> +
>> +    pipe_buf->data = malloc(capacity);
>> +    if (!pipe_buf->data) {
>> +            free(pipe_buf);
>> +            return NULL;
>> +    }
>> +
>> +    pipe_buf->capacity = capacity;
>> +    pipe_buf->cons = 0;
>> +    pipe_buf->prod = 0;
>> +    uk_mutex_init(&pipe_buf->rdlock);
>> +    uk_mutex_init(&pipe_buf->wrlock);
>> +    uk_waitq_init(&pipe_buf->rdwq);
>> +    uk_waitq_init(&pipe_buf->wrwq);
>> +
>> +    return pipe_buf;
>> +}
>> +
>> +void pipe_buf_free(struct pipe_buf *pipe_buf)
>> +{
>> +    free(pipe_buf->data);
>> +    free(pipe_buf);
>> +}
>> +
>> +static unsigned long pipe_buf_get_available(const struct pipe_buf *pipe_buf)
>> +{
>> +    return pipe_buf->prod - pipe_buf->cons;
>> +}
>> +
>> +static unsigned long pipe_buf_get_free_space(struct pipe_buf *pipe_buf)
>> +{
>> +    return pipe_buf->capacity - pipe_buf_get_available(pipe_buf);
>> +}
>> +
>> +static int pipe_buf_can_write(struct pipe_buf *pipe_buf)
>> +{
>> +    return pipe_buf_get_free_space(pipe_buf) > 0;
>> +}
>> +
>> +static int pipe_buf_can_read(struct pipe_buf *pipe_buf)
>> +{
>> +    return pipe_buf_get_available(pipe_buf) > 0;
>> +}
>> +
>> +static unsigned long pipe_buf_write(struct pipe_buf *pipe_buf,
>> +            struct iovec *iovec, size_t iovec_off)
>> +{
>> +    unsigned long prod_idx, to_write;
>> +    void *iovec_data = iovec->iov_base + iovec_off;
>> +    size_t iov_len = iovec->iov_len - iovec_off;
>> +
>> +    prod_idx = PIPE_BUF_PROD_IDX(pipe_buf);
>> +    to_write = MIN(pipe_buf_get_free_space(pipe_buf), iov_len);
>> +    if (to_write == 0)
>> +            goto out;
>> +
>> +    /* Copy in one piece */
>> +    if (prod_idx + to_write <= pipe_buf->capacity)
>> +            memcpy(pipe_buf->data + prod_idx, iovec_data, to_write);
>> +
>> +    else {
>> +            int first_copy_bytes, second_copy_bytes;
>> +
>> +            /* Copy the first part */
>> +            first_copy_bytes = pipe_buf->capacity - prod_idx;
>> +            memcpy(pipe_buf->data + prod_idx,
>> +                            iovec_data,
>> +                            first_copy_bytes);
>> +
>> +            /* Copy the second part */
>> +            second_copy_bytes = prod_idx + to_write - pipe_buf->capacity;
>> +            memcpy(pipe_buf->data,
>> +                            iovec_data + first_copy_bytes,
>> +                            second_copy_bytes);
>> +    }
>> +
>> +    /* Update producer */
>> +    pipe_buf->prod += to_write;
>> +
>> +out:
>> +    return to_write;
>> +}
>> +
>> +static unsigned long pipe_buf_read(struct pipe_buf *pipe_buf,
>> +            struct iovec *iovec, size_t iovec_off)
>> +{
>> +    unsigned long cons_idx, to_read;
>> +    void *iovec_data = iovec->iov_base + iovec_off;
>> +    size_t iov_len = iovec->iov_len - iovec_off;
>> +
>> +    cons_idx = PIPE_BUF_CONS_IDX(pipe_buf);
>> +    to_read = MIN(pipe_buf_get_available(pipe_buf), iov_len);
>> +    if (to_read == 0)
>> +            goto out;
>> +
>> +    /* Copy in one piece */
>> +    if (cons_idx + to_read <= pipe_buf->capacity)
>> +            memcpy(iovec_data, pipe_buf->data + cons_idx, to_read);
>> +
>> +    else {
>> +            int first_copy_bytes;
>> +            int second_copy_bytes;
>> +
>> +            /* Copy the first part */
>> +            first_copy_bytes = pipe_buf->capacity - pipe_buf->cons;
>> +            memcpy(iovec_data,
>> +                            pipe_buf->data + cons_idx,
>> +                            first_copy_bytes);
>> +
>> +            /* Copy the second part */
>> +            second_copy_bytes = cons_idx + to_read - pipe_buf->capacity;
>> +            memcpy(iovec_data + first_copy_bytes,
>> +                            pipe_buf->data,
>> +                            second_copy_bytes);
>> +    }
>> +
>> +    /* Update consumer */
>> +    pipe_buf->cons += to_read;
>> +
>> +out:
>> +    return to_read;
>> +}
>> +
>> +struct pipe_file *pipe_file_alloc(int capacity, int flags)
>> +{
>> +    struct pipe_file *pipe_file;
>> +
>> +    pipe_file = malloc(sizeof(*pipe_file));
>> +    if (!pipe_file)
>> +            return NULL;
>> +
>> +    pipe_file->buf = pipe_buf_alloc(capacity);
>> +    if (!pipe_file->buf) {
>> +            free(pipe_file);
>> +            return NULL;
>> +    }
>> +
>> +    pipe_file->w_refcount = 1;
>> +    pipe_file->r_refcount = 1;
>> +    pipe_file->flags = flags;
>> +
>> +    return pipe_file;
>> +}
>> +
>> +void pipe_file_free(struct pipe_file *pipe_file)
>> +{
>> +    pipe_buf_free(pipe_file->buf);
>> +    free(pipe_file);
>> +}
>> +
>> +static int pipe_write(struct vnode *vnode,
>> +            struct uio *buf, int ioflag __unused)
>> +{
>> +    struct pipe_file *pipe_file = vnode->v_data;
>> +    struct pipe_buf *pipe_buf = pipe_file->buf;
>> +    bool nonblocking = false; /* TODO handle nonblocking */
> In this case even though we support non-blocking we always have the
> value set to false.

Right. This pipe implementation does support non-blocking write, but I
didn't know where to take this information from. For read operations it
is set in the vfscore file flags, but for write operations I couldn't
find anything. If anyone would find out how it should be done then it
shouldn't be a problem to just send a patch.

>> +    bool data_available = true;
>> +    int uio_idx = 0;
>> +
>> +    if (!pipe_file->r_refcount) {
>> +            /* TODO before returning the error, send a SIGPIPE signal */
>> +            return -EPIPE;
>> +    }
>> +
>> +    uk_mutex_lock(&pipe_buf->wrlock);
>> +    while (data_available && uio_idx < buf->uio_iovcnt) {
>> +            struct iovec *iovec = &buf->uio_iov[uio_idx];
>> +            unsigned long off = 0;
>> +
>> +            while (off < iovec->iov_len) {
>> +                    unsigned long written_bytes;
>> +
>> +                    written_bytes = pipe_buf_write(pipe_buf, iovec, off);
>> +                    if (written_bytes == 0) {
>> +                            /* No data */
>> +                            if (nonblocking) {
>> +                                    data_available = false;
>> +                                    break;
>> +
>> +                            } else {
>> +                                    /* Wait until data available */
>> +                                    while (!pipe_buf_can_write(pipe_buf)) {
>> +                                            
>> uk_mutex_unlock(&pipe_buf->wrlock);
>> +                                            
>> uk_waitq_wait_event(&pipe_buf->wrwq,
>> +                                                    
>> pipe_buf_can_write(pipe_buf));
>> +                                            
>> uk_mutex_lock(&pipe_buf->wrlock);
>> +                                    }
>> +                            }
>> +
>> +                    } else {
>> +                            /* Update bytes written_bytes. */
>> +                            buf->uio_resid -= written_bytes;
>> +
>> +                            off += written_bytes;
>> +
>> +                            /* wake some readers */
>> +                            uk_waitq_wake_up(&pipe_buf->rdwq);
>> +                    }
>> +            }
>> +
>> +            uio_idx++;
>> +    }
>> +    uk_mutex_unlock(&pipe_buf->wrlock);
>> +
>> +    return 0;
>> +}
>> +
>> +static int pipe_read(struct vnode *vnode,
>> +            struct vfscore_file *vfscore_file,
>> +            struct uio *buf, int ioflag __unused)
>> +{
>> +    struct pipe_file *pipe_file = vnode->v_data;
>> +    struct pipe_buf *pipe_buf = pipe_file->buf;
>> +    bool nonblocking = (vfscore_file->f_flags & O_NONBLOCK);
>> +    bool data_available = true;
>> +    int uio_idx = 0;
>> +
>> +    uk_mutex_lock(&pipe_buf->rdlock);
>> +    if (nonblocking && !pipe_buf_can_read(pipe_buf)) {
>> +            uk_mutex_unlock(&pipe_buf->rdlock);
>> +            return EAGAIN;
>> +    }
>> +
>> +    while (data_available && uio_idx < buf->uio_iovcnt) {
>> +            struct iovec *iovec = &buf->uio_iov[uio_idx];
>> +            unsigned long off = 0;
>> +
>> +            while (off < iovec->iov_len) {
>> +                    unsigned long read_bytes;
>> +
>> +                    read_bytes = pipe_buf_read(pipe_buf, iovec, off);
>> +                    if (read_bytes == 0) {
>> +                            /* No data */
>> +                            if (nonblocking) {
>> +                                    data_available = false;
>> +                                    break;
>> +
>> +                            } else {
>> +                                    /* Wait until data available */
>> +                                    while (!pipe_buf_can_read(pipe_buf)) {
>> +                                            
>> uk_mutex_unlock(&pipe_buf->rdlock);
>> +                                            
>> uk_waitq_wait_event(&pipe_buf->rdwq,
>> +                                                    
>> pipe_buf_can_read(pipe_buf));
>> +                                            
>> uk_mutex_lock(&pipe_buf->rdlock);
>> +                                    }
>> +                            }
>> +
>> +                    } else {
>> +                            /* Update bytes read */
>> +                            buf->uio_resid -= read_bytes;
>> +
>> +                            off += read_bytes;
>> +
>> +                            /* wake some writers */
>> +                            uk_waitq_wake_up(&pipe_buf->wrwq);
>> +                    }
>> +            }
>> +
>> +            uio_idx++;
>> +    }
>> +    uk_mutex_unlock(&pipe_buf->rdlock);
>> +
>> +    return 0;
>> +}
>> +
>> +static int pipe_close(struct vnode *vnode,
>> +            struct vfscore_file *vfscore_file)
>> +{
>> +    struct pipe_file *pipe_file = vnode->v_data;
>> +
>> +    UK_ASSERT(vfscore_file->f_dentry->d_vnode == vnode);
>> +    UK_ASSERT(vnode->v_refcnt == 1);
>> +
>> +    if (vfscore_file->f_flags & UK_FREAD)
>> +            pipe_file->r_refcount--;
> Shouldn't we have a lock on pipe_file in order to avoid race conditions?

In deed, we could have a race with write operations, for example.
However, vfscore takes care of that (or at least that's what I
understood :-D): every time an operation is performed, the lock on the
vnode is taken, so vfscore takes care of it.

>> +
>> +    if (vfscore_file->f_flags & UK_FWRITE)
>> +            pipe_file->w_refcount--;
>> +
>> +    if (!pipe_file->r_refcount && !pipe_file->w_refcount)
>> +            pipe_file_free(pipe_file);
>> +
>> +    return 0;
>> +}
>> +
>> +static int pipe_seek(struct vnode *vnode __unused,
>> +                    struct vfscore_file *vfscore_file __unused,
>> +                    off_t off1 __unused, off_t off2 __unused)
>> +{
>> +    errno = ESPIPE;
>> +    return -1;
>> +}
>> +
>> +static int pipe_ioctl(struct vnode *vnode,
>> +            struct vfscore_file *vfscore_file __unused,
>> +            unsigned long com, void *data)
>> +{
>> +    struct pipe_file *pipe_file = vnode->v_data;
>> +    struct pipe_buf *pipe_buf = pipe_file->buf;
>> +
>> +    switch (com) {
>> +    case FIONREAD:
>> +            uk_mutex_lock(&pipe_buf->rdlock);
>> +            *((int *) data) = pipe_buf_get_available(pipe_buf);
>> +            uk_mutex_unlock(&pipe_buf->rdlock);
>> +            return 0;
>> +    default:
>> +            return -EINVAL;
>> +    }
>> +}
>> +
>> +#define pipe_open        ((vnop_open_t) vfscore_vop_einval)
>> +#define pipe_fsync       ((vnop_fsync_t) vfscore_vop_nullop)
>> +#define pipe_readdir     ((vnop_readdir_t) vfscore_vop_einval)
>> +#define pipe_lookup      ((vnop_lookup_t) vfscore_vop_einval)
>> +#define pipe_create      ((vnop_create_t) vfscore_vop_einval)
>> +#define pipe_remove      ((vnop_remove_t) vfscore_vop_einval)
>> +#define pipe_rename      ((vnop_rename_t) vfscore_vop_einval)
>> +#define pipe_mkdir       ((vnop_mkdir_t) vfscore_vop_einval)
>> +#define pipe_rmdir       ((vnop_rmdir_t) vfscore_vop_einval)
>> +#define pipe_getattr     ((vnop_getattr_t) vfscore_vop_einval)
>> +#define pipe_setattr     ((vnop_setattr_t) vfscore_vop_nullop)
>> +#define pipe_inactive    ((vnop_inactive_t) vfscore_vop_einval)
>> +#define pipe_truncate    ((vnop_truncate_t) vfscore_vop_nullop)
>> +#define pipe_link        ((vnop_link_t) vfscore_vop_eperm)
>> +#define pipe_cache       ((vnop_cache_t) NULL)
>> +#define pipe_readlink    ((vnop_readlink_t) vfscore_vop_einval)
>> +#define pipe_symlink     ((vnop_symlink_t) vfscore_vop_eperm)
>> +#define pipe_fallocate   ((vnop_fallocate_t) vfscore_vop_nullop)
>> +
>> +static struct vnops pipe_vnops = {
>> +    .vop_open      = pipe_open,
>> +    .vop_close     = pipe_close,
>> +    .vop_read      = pipe_read,
>> +    .vop_write     = pipe_write,
>> +    .vop_seek      = pipe_seek,
>> +    .vop_ioctl     = pipe_ioctl,
>> +    .vop_fsync     = pipe_fsync,
>> +    .vop_readdir   = pipe_readdir,
>> +    .vop_lookup    = pipe_lookup,
>> +    .vop_create    = pipe_create,
>> +    .vop_remove    = pipe_remove,
>> +    .vop_rename    = pipe_rename,
>> +    .vop_mkdir     = pipe_mkdir,
>> +    .vop_rmdir     = pipe_rmdir,
>> +    .vop_getattr   = pipe_getattr,
>> +    .vop_setattr   = pipe_setattr,
>> +    .vop_inactive  = pipe_inactive,
>> +    .vop_truncate  = pipe_truncate,
>> +    .vop_link      = pipe_link,
>> +    .vop_cache     = pipe_cache,
>> +    .vop_fallocate = pipe_fallocate,
>> +    .vop_readlink  = pipe_readlink,
>> +    .vop_symlink   = pipe_symlink
>> +};
>> +
>> +#define pipe_vget  ((vfsop_vget_t) vfscore_vop_nullop)
>> +
>> +static struct vfsops pipe_vfsops = {
>> +    .vfs_vget = pipe_vget,
>> +    .vfs_vnops = &pipe_vnops
>> +};
>> +
>> +static uint64_t p_inode;
>> +
>> +/*
>> + * Bogus mount point used by all sockets
>> + */
>> +static struct mount p_mount = {
>> +    .m_op = &pipe_vfsops
>> +};
>> +
>> +static int pipe_fd_alloc(struct pipe_file *pipe_file, int flags)
>> +{
>> +    int ret = 0;
>> +    int vfs_fd;
>> +    struct vfscore_file *vfs_file = NULL;
>> +    struct dentry *p_dentry;
>> +    struct vnode *p_vnode;
>> +
>> +    /* Reserve file descriptor number */
>> +    vfs_fd = vfscore_alloc_fd();
>> +    if (vfs_fd < 0) {
>> +            ret = -ENFILE;
>> +            goto ERR_EXIT;
>> +    }
>> +
>> +    /* Allocate file, dentry, and vnode */
>> +    vfs_file = calloc(1, sizeof(*vfs_file));
>> +    if (!vfs_file) {
>> +            ret = -ENOMEM;
>> +            goto ERR_MALLOC_VFS_FILE;
>> +    }
>> +
>> +    ret = vfscore_vget(&p_mount, p_inode++, &p_vnode);
>> +    UK_ASSERT(ret == 0); /* we should not find it in cache */
>> +
>> +    if (!p_vnode) {
>> +            ret = -ENOMEM;
>> +            goto ERR_ALLOC_VNODE;
>> +    }
>> +
>> +    uk_mutex_unlock(&p_vnode->v_lock);
>> +
>> +    p_dentry = dentry_alloc(NULL, p_vnode, "/");
>> +    if (!p_dentry) {
>> +            ret = -ENOMEM;
>> +            goto ERR_ALLOC_DENTRY;
>> +    }
>> +
>> +    /* Fill out necessary fields. */
>> +    vfs_file->fd = vfs_fd;
>> +    vfs_file->f_flags = flags;
>> +    vfs_file->f_count = 1;
>> +    vfs_file->f_data = pipe_file;
>> +    vfs_file->f_dentry = p_dentry;
>> +    vfs_file->f_vfs_flags = UK_VFSCORE_NOPOS;
>> +
>> +    p_vnode->v_data = pipe_file;
>> +    p_vnode->v_type = VFIFO;
>> +
>> +    /* Assign the file descriptors to the corresponding vfs_file. */
>> +    ret = vfscore_install_fd(vfs_fd, vfs_file);
>> +    if (ret)
>> +            goto ERR_VFS_INSTALL;
>> +
>> +    /* Only the dentry should hold a reference; release ours */
>> +    vrele(p_vnode);
>> +
>> +    return vfs_fd;
>> +
>> +ERR_VFS_INSTALL:
>> +    drele(p_dentry);
>> +ERR_ALLOC_DENTRY:
>> +    vrele(p_vnode);
>> +ERR_ALLOC_VNODE:
>> +    free(vfs_file);
>> +ERR_MALLOC_VFS_FILE:
>> +    vfscore_put_fd(vfs_fd);
>> +ERR_EXIT:
>> +    UK_ASSERT(ret < 0);
>> +    return ret;
>> +}
>> +
>> +int pipe(int pipefd[2])
>> +{
>> +    int ret = 0;
>> +    int r_fd, w_fd;
>> +    struct pipe_file *pipe_file;
>> +
>> +    /* Allocate pipe internal structure. */
>> +    pipe_file = pipe_file_alloc(PIPE_MAX_SIZE, 0);
>> +    if (!pipe_file) {
>> +            ret = -ENOMEM;
>> +            goto ERR_EXIT;
>> +    }
>> +
>> +    r_fd = pipe_fd_alloc(pipe_file, UK_FREAD);
>> +    if (r_fd < 0)
>> +            goto ERR_VFS_INSTALL;
>> +
>> +    w_fd = pipe_fd_alloc(pipe_file, UK_FWRITE);
>> +    if (w_fd < 0)
>> +            goto ERR_W_FD;
>> +
>> +    /* Fill pipefd fields. */
>> +    pipefd[0] = r_fd;
>> +    pipefd[1] = w_fd;
>> +
>> +    return ret;
>> +
>> +ERR_W_FD:
>> +    vfscore_put_fd(r_fd);
>> +ERR_VFS_INSTALL:
>> +    pipe_file_free(pipe_file);
>> +ERR_EXIT:
>> +    UK_ASSERT(ret < 0);
>> +    return ret;
>> +}
> 
> _______________________________________________
> Minios-devel mailing list
> Minios-devel@xxxxxxxxxxxxxxxxxxxx
> https://lists.xenproject.org/mailman/listinfo/minios-devel
> 

_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.