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

Re: [Minios-devel] [UNIKRAFT PATCH 6/7] lib/9pfs: Add open, close and readdir vnops



Reviewed-by: Costin Lupu <costin.lupu@xxxxxxxxx>

On 9/7/19 12:59 PM, Vlad-Andrei BĂDOIU (78692) wrote:
> From: Cristian Banu <cristb@xxxxxxxxx>
> 
> This patch adds the open, close and readdir VFS node operations.
> 
> In order to cache stat structures on sequential readdir calls,
> a buffer is placed in the f_data field of a file struct.
> 
> Signed-off-by: Cristian Banu <cristb@xxxxxxxxx>
> ---
>  lib/9pfs/9pfs_vnops.c | 178 +++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 175 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/9pfs/9pfs_vnops.c b/lib/9pfs/9pfs_vnops.c
> index 50f83148..bf008a88 100644
> --- a/lib/9pfs/9pfs_vnops.c
> +++ b/lib/9pfs/9pfs_vnops.c
> @@ -47,6 +47,26 @@
>  
>  #include "9pfs.h"
>  
> +static uint8_t uk_9pfs_open_mode_from_posix_flags(unsigned long flags)
> +{
> +     uint8_t mode = 0;
> +     uint8_t flags_rw = flags & (UK_FREAD | UK_FWRITE);
> +
> +     if (flags_rw == UK_FREAD)
> +             mode = UK_9P_OREAD;
> +     else if (flags_rw == UK_FWRITE)
> +             mode = UK_9P_OWRITE;
> +     else if (flags_rw == (UK_FREAD | UK_FWRITE))
> +             mode = UK_9P_ORDWR;
> +
> +     if (flags & O_EXCL)
> +             mode |= UK_9P_OEXCL;
> +     if (flags & O_TRUNC)
> +             mode |= UK_9P_OTRUNC;
> +
> +     return mode;
> +}
> +
>  static int uk_9pfs_posix_perm_from_mode(int mode)
>  {
>       int res;
> @@ -73,6 +93,13 @@ static uint32_t uk_9pfs_perm_from_posix_mode(mode_t mode)
>       return res;
>  }
>  
> +static int uk_9pfs_dttype_from_mode(int mode)
> +{
> +     if (mode & UK_9P_DMDIR)
> +             return DT_DIR;
> +     return DT_REG;
> +}
> +
>  static int uk_9pfs_posix_mode_from_mode(int mode)
>  {
>       int res;
> @@ -131,6 +158,75 @@ void uk_9pfs_free_vnode_data(struct vnode *vp)
>       vp->v_data = NULL;
>  }
>  
> +/*
> + * The closing variant of the function will enforce freeing the associated
> + * resources only if the vnode was removed via an unlink/rmdir operation.
> + */
> +static void uk_9pfs_free_vnode_data_closing(struct vnode *vp)
> +{
> +     struct uk_9pfs_node_data *nd = UK_9PFS_ND(vp);
> +
> +     if (!nd->removed)
> +             return;
> +
> +     uk_9pfs_free_vnode_data(vp);
> +}
> +
> +static int uk_9pfs_open(struct vfscore_file *file)
> +{
> +     struct uk_9pdev *dev = UK_9PFS_MD(file->f_dentry->d_mount)->dev;
> +     struct uk_9pfid *openedfid;
> +     struct uk_9pfs_file_data *fd;
> +     int rc;
> +
> +     /* Allocate memory for file data. */
> +     fd = calloc(1, sizeof(*fd));
> +     if (!fd)
> +             return ENOMEM;
> +
> +     /* Clone fid. */
> +     openedfid = uk_9p_walk(dev, UK_9PFS_VFID(file->f_dentry->d_vnode),
> +                     NULL);
> +     if (PTRISERR(openedfid)) {
> +             rc = PTR2ERR(openedfid);
> +             goto out;
> +     }
> +
> +     /* Open cloned fid. */
> +     rc = uk_9p_open(dev, openedfid,
> +             uk_9pfs_open_mode_from_posix_flags(file->f_flags));
> +
> +     if (rc)
> +             goto out_err;
> +
> +     fd->fid = openedfid;
> +     file->f_data = fd;
> +     UK_9PFS_ND(file->f_dentry->d_vnode)->nb_open_files++;
> +
> +     return 0;
> +
> +out_err:
> +     uk_9pfid_put(openedfid);
> +out:
> +     free(fd);
> +     return -rc;
> +}
> +
> +static int uk_9pfs_close(struct vnode *vn __unused, struct vfscore_file 
> *file)
> +{
> +     struct uk_9pfs_file_data *fd = UK_9PFS_FD(file);
> +
> +     if (fd->readdir_buf)
> +             free(fd->readdir_buf);
> +
> +     uk_9pfid_put(fd->fid);
> +     free(fd);
> +     UK_9PFS_ND(file->f_dentry->d_vnode)->nb_open_files--;
> +     uk_9pfs_free_vnode_data_closing(file->f_dentry->d_vnode);
> +
> +     return 0;
> +}
> +
>  static int uk_9pfs_lookup(struct vnode *dvp, char *name, struct vnode **vpp)
>  {
>       struct uk_9pdev *dev = UK_9PFS_MD(dvp->v_mount)->dev;
> @@ -266,7 +362,85 @@ static int uk_9pfs_rmdir(struct vnode *dvp, struct vnode 
> *vp,
>  static int uk_9pfs_readdir(struct vnode *vp, struct vfscore_file *fp,
>               struct dirent *dir)
>  {
> -     return ENOENT;
> +     struct uk_9pdev *dev = UK_9PFS_MD(vp->v_mount)->dev;
> +     struct uk_9pfs_file_data *fd = UK_9PFS_FD(fp);
> +     int rc;
> +     struct uk_9p_stat stat;
> +     struct uk_9preq fake_request;
> +
> +again:
> +     if (!fd->readdir_buf) {
> +             fd->readdir_buf = malloc(UK_9PFS_READDIR_BUFSZ);
> +             if (!fd->readdir_buf)
> +                     return ENOMEM;
> +
> +             /* Currently the readdir() buffer is empty. */
> +             fd->readdir_off = 0;
> +             fd->readdir_sz = 0;
> +     }
> +
> +     if (fd->readdir_off == fd->readdir_sz) {
> +             fd->readdir_off = 0;
> +             fd->readdir_sz = uk_9p_read(dev, fd->fid, fp->f_offset,
> +                             UK_9PFS_READDIR_BUFSZ, fd->readdir_buf);
> +             if (fd->readdir_sz < 0) {
> +                     rc = fd->readdir_sz;
> +                     goto out;
> +             }
> +
> +             /* End of directory. */
> +             if (fd->readdir_sz == 0) {
> +                     rc = -ENOENT;
> +                     goto out;
> +             }
> +
> +             /*
> +              * Update offset for the next readdir() call which requires
> +              * the next chunk of data to be transferred.
> +              */
> +             fp->f_offset += fd->readdir_sz;
> +     }
> +
> +     /*
> +      * Build a fake request to use the 9P request API to read from the
> +      * buffer the stat structure.
> +      */
> +     fake_request.recv.buf = fd->readdir_buf;
> +     fake_request.recv.size = fd->readdir_sz;
> +     fake_request.recv.offset = fd->readdir_off;
> +     fake_request.state = UK_9PREQ_RECEIVED;
> +     rc = uk_9preq_deserialize(&fake_request, "S", &stat);
> +
> +     if (rc == -ENOBUFS) {
> +             /*
> +              * Retry with a clean buffer, maybe the stat structure got
> +              * chunked and is not whole, although the RFC says this should
> +              * not happen.
> +              */
> +             fd->readdir_off = 0;
> +             fd->readdir_sz = 0;
> +             goto again;
> +     }
> +
> +     /* Update the readdir() offset to the offset after deserialization. */
> +     fd->readdir_off = fake_request.recv.offset;
> +
> +     /*
> +      * Any other error besides ENOBUFS when deserializing is considered
> +      * an IO error.
> +      */
> +     if (rc) {
> +             rc = -EIO;
> +             goto out;
> +     }
> +
> +     dir->d_type = uk_9pfs_dttype_from_mode(stat.mode);
> +     dir->d_ino = uk_9pfs_ino(&stat);
> +     strlcpy((char *) &dir->d_name, stat.name.data,
> +                     MIN(sizeof(dir->d_name), stat.name.size + 1U));
> +
> +out:
> +     return -rc;
>  }
>  
>  #define uk_9pfs_seek         ((vnop_seek_t)vfscore_vop_nullop)
> @@ -281,8 +455,6 @@ static int uk_9pfs_readdir(struct vnode *vp, struct 
> vfscore_file *fp,
>  #define uk_9pfs_symlink              ((vnop_symlink_t)vfscore_vop_eperm)
>  #define uk_9pfs_fallocate    ((vnop_fallocate_t)vfscore_vop_nullop)
>  #define uk_9pfs_rename               ((vnop_rename_t)vfscore_vop_einval)
> -#define uk_9pfs_open         ((vnop_open_t)vfscore_vop_einval)
> -#define uk_9pfs_close                ((vnop_close_t)vfscore_vop_einval)
>  #define uk_9pfs_read         ((vnop_read_t)vfscore_vop_einval)
>  #define uk_9pfs_write                ((vnop_write_t)vfscore_vop_einval)
>  
> 

_______________________________________________
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®.