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);
}
.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,
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;
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;
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;
}
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;
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
return -EFBIG;
}
+
if (n < size)
size = n;
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) &&
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 *);
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,
*/
#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) \