]> git.neil.brown.name Git - history.git/commitdiff
XFS: Implement readv/writev
authorChristoph Hellwig <hch@sgi.com>
Thu, 26 Sep 2002 23:27:50 +0000 (01:27 +0200)
committerChristoph Hellwig <hch@sgi.com>
Thu, 26 Sep 2002 23:27:50 +0000 (01:27 +0200)
Modid: 2.5.x-xfs:slinx:128366a

fs/xfs/linux/xfs_file.c
fs/xfs/linux/xfs_lrw.c
fs/xfs/linux/xfs_lrw.h
fs/xfs/linux/xfs_vnode.h

index 8da94cb6741ee909d07fced5b87f77f04357ea91..c292bfc9f1198410d82cda9a9554401935d587c4 100644 (file)
@@ -40,70 +40,76 @@ static struct vm_operations_struct linvfs_file_vm_ops;
 
 
 STATIC ssize_t
-linvfs_read(
-       struct file     *filp,
-       char            *buf,
-       size_t          size,
-       loff_t          *offset)
+linvfs_readv(
+       struct file             *filp,
+       const struct iovec      *iovp,
+       unsigned long           nr_segs,
+       loff_t                  *ppos)
 {
-       vnode_t         *vp;
-       int             error;
+       vnode_t                 *vp = LINVFS_GET_VP(filp->f_dentry->d_inode);
+       int                     error;
 
-       vp = LINVFS_GET_VP(filp->f_dentry->d_inode);
-       ASSERT(vp);
+       VOP_READ(vp, filp, iovp, nr_segs, ppos, NULL, error);
 
-       VOP_READ(vp, filp, buf, size, offset, NULL, error);
-
-       return(error);
+       return error;
 }
 
 
 STATIC ssize_t
-linvfs_write(
-       struct file     *file,
-       const char      *buf,
-       size_t          count,
-       loff_t          *ppos)
+linvfs_writev(
+       struct file             *filp,
+       const struct iovec      *iovp,
+       unsigned long           nr_segs,
+       loff_t                  *ppos)
 {
-       struct inode    *inode = file->f_dentry->d_inode;
-       loff_t          pos;
-       vnode_t         *vp;
-       int             err;    /* Use negative errors in this f'n */
-
-       if ((ssize_t) count < 0)
-               return -EINVAL;
-
-       if (!access_ok(VERIFY_READ, buf, count))
-               return -EFAULT;
+       struct inode            *inode = filp->f_dentry->d_inode;
+       vnode_t                 *vp = LINVFS_GET_VP(inode);
+       int                     error = filp->f_error;
 
-       pos = *ppos;
-       err = -EINVAL;
-       if (pos < 0)
-               goto out;
-
-       err = file->f_error;
-       if (err) {
-               file->f_error = 0;
-               goto out;
+       if (unlikely(error)) {
+               filp->f_error = 0;
+               return error;
        }
 
-       vp = LINVFS_GET_VP(inode);
-       ASSERT(vp);
-
-       /* We allow multiple direct writers in, there is no
+       /*
+        * We allow multiple direct writers in, there is no
         * potential call to vmtruncate in that path.
         */
-       if (!(file->f_flags & O_DIRECT))
+       if (filp->f_flags & O_DIRECT) {
+               VOP_WRITE(vp, filp, iovp, nr_segs, ppos, NULL, error);
+       } else {
                down(&inode->i_sem);
+               VOP_WRITE(vp, filp, iovp, nr_segs, ppos, NULL, error);
+               up(&inode->i_sem);
+       }
 
-       VOP_WRITE(vp, file, buf, count, &pos, NULL, err);
-       *ppos = pos;
+       return error;
+}
 
-       if (!(file->f_flags & O_DIRECT))
-               up(&inode->i_sem);
-out:
 
-       return(err);
+STATIC ssize_t
+linvfs_read(
+       struct file             *filp,
+       char                    *buf,
+       size_t                  count,
+       loff_t                  *ppos)
+{
+       struct iovec            iov = {buf, count};
+
+       return linvfs_readv(filp, &iov, 1, ppos);
+}
+
+
+STATIC ssize_t
+linvfs_write(
+       struct file             *file,
+       const char              *buf,
+       size_t                  count,
+       loff_t                  *ppos)
+{
+       struct iovec            iov = {(void *)buf, count};
+
+       return linvfs_writev(file, &iov, 1, ppos);
 }
 
 
@@ -312,6 +318,8 @@ struct file_operations linvfs_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = linvfs_read,
        .write          = linvfs_write,
+       .readv          = linvfs_readv,
+       .writev         = linvfs_writev,
        .ioctl          = linvfs_ioctl,
        .mmap           = linvfs_file_mmap,
        .open           = linvfs_open,
index abb820267d95611598e3fa0e547f1f37b1dc4e16..c7467e2acce360ee2700ddd2d1dd887f084b7704 100644 (file)
@@ -124,36 +124,64 @@ unlock:
 
 ssize_t                        /* bytes read, or (-)  error */
 xfs_read(
-       bhv_desc_t      *bdp,
-       struct file     *file,
-       char            *buf,
-       size_t          size,
-       loff_t          *offset,
-       cred_t          *credp)
+       bhv_desc_t              *bdp,
+       struct file             *filp,
+       const struct iovec      *iovp,
+       unsigned long           segs,
+       loff_t                  *offp,
+       cred_t                  *credp)
 {
-       ssize_t         ret;
-       xfs_fsize_t     n;
-       xfs_inode_t     *ip;
-       xfs_mount_t     *mp;
+       size_t                  size = 0;
+       ssize_t                 ret;
+       xfs_fsize_t             n;
+       xfs_inode_t             *ip;
+       xfs_mount_t             *mp;
+       unsigned long           seg;
+       int                     direct = filp->f_flags & O_DIRECT;
 
        ip = XFS_BHVTOI(bdp);
        mp = ip->i_mount;
 
        XFS_STATS_INC(xfsstats.xs_read_calls);
 
-       if (file->f_flags & O_DIRECT) {
-               if (((__psint_t)buf & BBMASK) ||
-                   (*offset & mp->m_blockmask) ||
+       /* START copy & waste from filemap.c */
+       for (seg = 0; seg < segs; seg++) {
+               const struct iovec *iv = &iovp[seg];
+
+               /*
+                * If any segment has a negative length, or the cumulative
+                * length ever wraps negative then return -EINVAL.
+                */
+               size += iv->iov_len;
+               if (unlikely((ssize_t)(size|iv->iov_len) < 0))
+                       return XFS_ERROR(-EINVAL);
+               if (direct) {   /* XFS specific check */
+                       if ((__psint_t)iv->iov_base & BBMASK) {
+                               if (*offp == ip->i_d.di_size)
+                                       return 0;
+                               return XFS_ERROR(-EINVAL);
+                       }
+               }
+               if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))
+                       continue;
+               if (seg == 0)
+                       return XFS_ERROR(-EFAULT);
+               segs = seg;
+               break;
+       }
+       /* END copy & waste from filemap.c */
+
+       if (direct) {
+               if ((*offp & mp->m_blockmask) ||
                    (size & mp->m_blockmask)) {
-                       if (*offset == ip->i_d.di_size) {
+                       if (*offp == ip->i_d.di_size) {
                                return (0);
                        }
                        return -XFS_ERROR(EINVAL);
                }
        }
 
-
-       n = XFS_MAX_FILE_OFFSET - *offset;
+       n = XFS_MAX_FILE_OFFSET - *offp;
        if ((n <= 0) || (size == 0))
                return 0;
 
@@ -167,26 +195,24 @@ xfs_read(
        xfs_ilock(ip, XFS_IOLOCK_SHARED);
 
        if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) &&
-           !(file->f_mode & FINVIS)) {
+           !(filp->f_mode & FINVIS)) {
                int error;
                vrwlock_t locktype = VRWLOCK_READ;
 
-               error = xfs_dm_send_data_event(DM_EVENT_READ, bdp,
-                                            *offset, size,
-                                            FILP_DELAY_FLAG(file),
-                                            &locktype);
+               error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, *offp,
+                               size, FILP_DELAY_FLAG(filp), &locktype);
                if (error) {
                        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
                        return -error;
                }
        }
 
-       ret = generic_file_read(file, buf, size, offset);
+       ret = generic_file_readv(filp, iovp, segs, offp);
        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
        XFS_STATS_ADD(xfsstats.xs_read_bytes, ret);
 
-       if (!(file->f_mode & FINVIS))
+       if (!(filp->f_mode & FINVIS))
                xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
 
        return ret;
@@ -418,32 +444,57 @@ out_lock:
 
 ssize_t                                /* bytes written, or (-) error */
 xfs_write(
-       bhv_desc_t      *bdp,
-       struct file     *file,
-       const char      *buf,
-       size_t          size,
-       loff_t          *offset,
-       cred_t          *credp)
+       bhv_desc_t              *bdp,
+       struct file             *file,
+       const struct iovec      *iovp,
+       unsigned long           segs,
+       loff_t                  *offset,
+       cred_t                  *credp)
 {
-       xfs_inode_t     *xip;
-       xfs_mount_t     *mp;
-       ssize_t         ret;
-       int             error = 0;
-       xfs_fsize_t     isize, new_size;
-       xfs_fsize_t     n, limit = XFS_MAX_FILE_OFFSET;
-       xfs_iocore_t    *io;
-       vnode_t         *vp;
-       struct iovec    iov;
-       int             iolock;
-       int             direct = file->f_flags & O_DIRECT;
-       int             eventsent = 0;
-       vrwlock_t       locktype;
+       size_t                  size = 0;
+       xfs_inode_t             *xip;
+       xfs_mount_t             *mp;
+       ssize_t                 ret;
+       int                     error = 0;
+       xfs_fsize_t             isize, new_size;
+       xfs_fsize_t             n, limit = XFS_MAX_FILE_OFFSET;
+       xfs_iocore_t            *io;
+       vnode_t                 *vp;
+       unsigned long           seg;
+       int                     iolock;
+       int                     direct = file->f_flags & O_DIRECT;
+       int                     eventsent = 0;
+       vrwlock_t               locktype;
 
        XFS_STATS_INC(xfsstats.xs_write_calls);
 
        vp = BHV_TO_VNODE(bdp);
        xip = XFS_BHVTOI(bdp);
 
+       /* START copy & waste from filemap.c */
+       for (seg = 0; seg < segs; seg++) {
+               const struct iovec *iv = &iovp[seg];
+
+               /*
+                * If any segment has a negative length, or the cumulative
+                * length ever wraps negative then return -EINVAL.
+                */
+               size += iv->iov_len;
+               if (unlikely((ssize_t)(size|iv->iov_len) < 0))
+                       return XFS_ERROR(-EINVAL);
+               if (direct) {   /* XFS specific check */
+                       if ((__psint_t)iv->iov_base & BBMASK)
+                               return XFS_ERROR(-EINVAL);
+               }
+               if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
+                       continue;
+               if (seg == 0)
+                       return XFS_ERROR(-EFAULT);
+               segs = seg;
+               break;
+       }
+       /* END copy & waste from filemap.c */
+
        if (size == 0)
                return 0;
 
@@ -457,9 +508,8 @@ xfs_write(
        }
 
        if (direct) {
-               if (((__psint_t)buf & BBMASK) ||
-                   (*offset & mp->m_blockmask) ||
-                   (size  & mp->m_blockmask)) {
+               if ((*offset & mp->m_blockmask) ||
+                   (size & mp->m_blockmask)) {
                        return XFS_ERROR(-EINVAL);
                }
                iolock = XFS_IOLOCK_SHARED;
@@ -481,6 +531,7 @@ start:
                xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
                return -EFBIG;
        }
+
        if (n < size)
                size = n;
 
@@ -572,10 +623,7 @@ retry:
                xfs_inval_cached_pages(vp, &xip->i_iocore, *offset, 1, 1);
        }
 
-       iov.iov_base = (void *)buf;
-       iov.iov_len = size;
-
-       ret = generic_file_write_nolock(file, &iov, 1, offset);
+       ret = generic_file_write_nolock(file, iovp, segs, offset);
 
        if ((ret == -ENOSPC) &&
            DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) &&
index 12bdf990ac16f9a19ad697eacf284e9de1eb38ce..0ea2cfe9a860b4758fbba19d18842071d577bcfb 100644 (file)
@@ -47,19 +47,19 @@ extern int xfs_bdstrat_cb (struct xfs_buf *);
 extern int xfs_zero_eof (vnode_t *, struct xfs_iocore *, xfs_off_t,
                                xfs_fsize_t, xfs_fsize_t, struct pm *);
 extern ssize_t xfs_read (
-       struct bhv_desc        *bdp,
-       struct file             *file,
-       char                    *buf,
-       size_t                  size,
-       loff_t                  *offset,
-       struct cred            *credp);
+       struct bhv_desc         *bdp,
+       struct file             *filp,
+       const struct iovec      *iovp,
+       unsigned long           segs,
+       loff_t                  *offp,
+       struct cred             *credp);
 
 extern ssize_t xfs_write (
        struct bhv_desc         *bdp,
-       struct file             *file,
-       const char              *buf,
-       size_t                  size,
-       loff_t                  *offset,
+       struct file             *filp,
+       const struct iovec      *iovp,
+       unsigned long           segs,
+       loff_t                  *offp,
        struct cred             *credp);
 
 extern int xfs_recover_read_only (xlog_t *);
index f09132b07438e012e0f792adf614b5bbf0bdce95..bf6025bfe0a4f039cf363fd696d590beba4245e6 100644 (file)
@@ -175,9 +175,11 @@ struct page_buf_bmap_s;
 struct attrlist_cursor_kern;
 
 typedef int    (*vop_open_t)(bhv_desc_t *, struct cred *);
-typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct file *, char *, size_t,
+typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct file *,
+                               const struct iovec *, unsigned long,
                                loff_t *, struct cred *);
-typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct file *, const char *, size_t,
+typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct file *,
+                               const struct iovec *, unsigned long,
                                loff_t *, struct cred *);
 typedef int    (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, unsigned int, unsigned long);
 typedef int    (*vop_getattr_t)(bhv_desc_t *, struct vattr *, int,
@@ -272,16 +274,16 @@ typedef struct vnodeops {
  */
 #define _VOP_(op, vp)  (*((vnodeops_t *)(vp)->v_fops)->op)
 
-#define VOP_READ(vp,file,buf,size,offset,cr,rv)                                \
+#define VOP_READ(vp,file,iov,segs,offset,cr,rv)                                \
 {                                                                      \
        VN_BHV_READ_LOCK(&(vp)->v_bh);                                  \
-       rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,buf,size,offset,cr); \
+       rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,iov,segs,offset,cr); \
        VN_BHV_READ_UNLOCK(&(vp)->v_bh);                                \
 }
-#define VOP_WRITE(vp,file,buf,size,offset,cr,rv)                       \
+#define VOP_WRITE(vp,file,iov,segs,offset,cr,rv)                       \
 {                                                                      \
        VN_BHV_READ_LOCK(&(vp)->v_bh);                                  \
-       rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,buf,size,offset,cr);\
+       rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,cr);\
        VN_BHV_READ_UNLOCK(&(vp)->v_bh);                                \
 }
 #define VOP_BMAP(vp,of,sz,rw,cr,b,n,rv)                                        \