forked from luck/tmp_suning_uos_patched
Merge branch 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull second vfs update from Al Viro: "Now that net-next went in... Here's the next big chunk - killing ->aio_read() and ->aio_write(). There'll be one more pile today (direct_IO changes and generic_write_checks() cleanups/fixes), but I'd prefer to keep that one separate" * 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (37 commits) ->aio_read and ->aio_write removed pcm: another weird API abuse infinibad: weird APIs switched to ->write_iter() kill do_sync_read/do_sync_write fuse: use iov_iter_get_pages() for non-splice path fuse: switch to ->read_iter/->write_iter switch drivers/char/mem.c to ->read_iter/->write_iter make new_sync_{read,write}() static coredump: accept any write method switch /dev/loop to vfs_iter_write() serial2002: switch to __vfs_read/__vfs_write ashmem: use __vfs_read() export __vfs_read() autofs: switch to __vfs_write() new helper: __vfs_write() switch hugetlbfs to ->read_iter() coda: switch to ->read_iter/->write_iter ncpfs: switch to ->read_iter/->write_iter net/9p: remove (now-)unused helpers p9_client_attach(): set fid->uid correctly ...
This commit is contained in:
commit
fa927894bb
|
@ -429,8 +429,6 @@ prototypes:
|
|||
loff_t (*llseek) (struct file *, loff_t, int);
|
||||
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
|
||||
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
|
||||
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
|
||||
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
|
||||
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
|
||||
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
|
||||
int (*iterate) (struct file *, struct dir_context *);
|
||||
|
|
|
@ -471,3 +471,15 @@ in your dentry operations instead.
|
|||
[mandatory]
|
||||
f_dentry is gone; use f_path.dentry, or, better yet, see if you can avoid
|
||||
it entirely.
|
||||
--
|
||||
[mandatory]
|
||||
never call ->read() and ->write() directly; use __vfs_{read,write} or
|
||||
wrappers; instead of checking for ->write or ->read being NULL, look for
|
||||
FMODE_CAN_{WRITE,READ} in file->f_mode.
|
||||
--
|
||||
[mandatory]
|
||||
do _not_ use new_sync_{read,write} for ->read/->write; leave it NULL
|
||||
instead.
|
||||
--
|
||||
[mandatory]
|
||||
->aio_read/->aio_write are gone. Use ->read_iter/->write_iter.
|
||||
|
|
|
@ -804,8 +804,6 @@ struct file_operations {
|
|||
loff_t (*llseek) (struct file *, loff_t, int);
|
||||
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
|
||||
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
|
||||
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
|
||||
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
|
||||
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
|
||||
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
|
||||
int (*iterate) (struct file *, struct dir_context *);
|
||||
|
@ -838,14 +836,10 @@ otherwise noted.
|
|||
|
||||
read: called by read(2) and related system calls
|
||||
|
||||
aio_read: vectored, possibly asynchronous read
|
||||
|
||||
read_iter: possibly asynchronous read with iov_iter as destination
|
||||
|
||||
write: called by write(2) and related system calls
|
||||
|
||||
aio_write: vectored, possibly asynchronous write
|
||||
|
||||
write_iter: possibly asynchronous write with iov_iter as source
|
||||
|
||||
iterate: called when the VFS needs to read the directory contents
|
||||
|
|
|
@ -437,8 +437,6 @@ struct dentry *hypfs_create_str(struct dentry *dir,
|
|||
static const struct file_operations hypfs_file_ops = {
|
||||
.open = hypfs_open,
|
||||
.release = hypfs_release,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = hypfs_read_iter,
|
||||
.write_iter = hypfs_write_iter,
|
||||
.llseek = no_llseek,
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
#include <linux/sysfs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/uio.h>
|
||||
#include "loop.h"
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -229,13 +230,14 @@ lo_do_transfer(struct loop_device *lo, int cmd,
|
|||
static int __do_lo_send_write(struct file *file,
|
||||
u8 *buf, const int len, loff_t pos)
|
||||
{
|
||||
struct kvec kvec = {.iov_base = buf, .iov_len = len};
|
||||
struct iov_iter from;
|
||||
ssize_t bw;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
|
||||
iov_iter_kvec(&from, ITER_KVEC | WRITE, &kvec, 1, len);
|
||||
|
||||
file_start_write(file);
|
||||
set_fs(get_ds());
|
||||
bw = file->f_op->write(file, buf, len, &pos);
|
||||
set_fs(old_fs);
|
||||
bw = vfs_iter_write(file, &from, &pos);
|
||||
file_end_write(file);
|
||||
if (likely(bw == len))
|
||||
return 0;
|
||||
|
@ -767,7 +769,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
|
|||
goto out_putf;
|
||||
|
||||
if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) ||
|
||||
!file->f_op->write)
|
||||
!file->f_op->write_iter)
|
||||
lo_flags |= LO_FLAGS_READ_ONLY;
|
||||
|
||||
lo_blocksize = S_ISBLK(inode->i_mode) ?
|
||||
|
|
|
@ -607,16 +607,16 @@ static ssize_t write_null(struct file *file, const char __user *buf,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t aio_read_null(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos)
|
||||
static ssize_t read_iter_null(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t aio_write_null(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos)
|
||||
static ssize_t write_iter_null(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
return iov_length(iov, nr_segs);
|
||||
size_t count = iov_iter_count(from);
|
||||
iov_iter_advance(from, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,
|
||||
|
@ -718,7 +718,7 @@ static int open_port(struct inode *inode, struct file *filp)
|
|||
#define zero_lseek null_lseek
|
||||
#define full_lseek null_lseek
|
||||
#define write_zero write_null
|
||||
#define aio_write_zero aio_write_null
|
||||
#define write_iter_zero write_iter_null
|
||||
#define open_mem open_port
|
||||
#define open_kmem open_mem
|
||||
|
||||
|
@ -750,8 +750,8 @@ static const struct file_operations null_fops = {
|
|||
.llseek = null_lseek,
|
||||
.read = read_null,
|
||||
.write = write_null,
|
||||
.aio_read = aio_read_null,
|
||||
.aio_write = aio_write_null,
|
||||
.read_iter = read_iter_null,
|
||||
.write_iter = write_iter_null,
|
||||
.splice_write = splice_write_null,
|
||||
};
|
||||
|
||||
|
@ -764,10 +764,9 @@ static const struct file_operations __maybe_unused port_fops = {
|
|||
|
||||
static const struct file_operations zero_fops = {
|
||||
.llseek = zero_lseek,
|
||||
.read = new_sync_read,
|
||||
.write = write_zero,
|
||||
.read_iter = read_iter_zero,
|
||||
.aio_write = aio_write_zero,
|
||||
.write_iter = write_iter_zero,
|
||||
.mmap = mmap_zero,
|
||||
#ifndef CONFIG_MMU
|
||||
.mmap_capabilities = zero_mmap_capabilities,
|
||||
|
@ -776,7 +775,6 @@ static const struct file_operations zero_fops = {
|
|||
|
||||
static const struct file_operations full_fops = {
|
||||
.llseek = full_lseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = read_iter_zero,
|
||||
.write = write_full,
|
||||
};
|
||||
|
|
|
@ -282,9 +282,7 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd,
|
|||
#endif
|
||||
|
||||
static const struct file_operations raw_fops = {
|
||||
.read = new_sync_read,
|
||||
.read_iter = blkdev_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = blkdev_write_iter,
|
||||
.fsync = blkdev_fsync,
|
||||
.open = raw_open,
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/uio.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
#include "ipath_kernel.h"
|
||||
|
@ -52,15 +53,19 @@ static int ipath_open(struct inode *, struct file *);
|
|||
static int ipath_close(struct inode *, struct file *);
|
||||
static ssize_t ipath_write(struct file *, const char __user *, size_t,
|
||||
loff_t *);
|
||||
static ssize_t ipath_writev(struct kiocb *, const struct iovec *,
|
||||
unsigned long , loff_t);
|
||||
static ssize_t ipath_write_iter(struct kiocb *, struct iov_iter *from);
|
||||
static unsigned int ipath_poll(struct file *, struct poll_table_struct *);
|
||||
static int ipath_mmap(struct file *, struct vm_area_struct *);
|
||||
|
||||
/*
|
||||
* This is really, really weird shit - write() and writev() here
|
||||
* have completely unrelated semantics. Sucky userland ABI,
|
||||
* film at 11.
|
||||
*/
|
||||
static const struct file_operations ipath_file_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.write = ipath_write,
|
||||
.aio_write = ipath_writev,
|
||||
.write_iter = ipath_write_iter,
|
||||
.open = ipath_open,
|
||||
.release = ipath_close,
|
||||
.poll = ipath_poll,
|
||||
|
@ -2413,18 +2418,17 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ipath_writev(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long dim, loff_t off)
|
||||
static ssize_t ipath_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct file *filp = iocb->ki_filp;
|
||||
struct ipath_filedata *fp = filp->private_data;
|
||||
struct ipath_portdata *pd = port_fp(filp);
|
||||
struct ipath_user_sdma_queue *pq = fp->pq;
|
||||
|
||||
if (!dim)
|
||||
if (!iter_is_iovec(from) || !from->nr_segs)
|
||||
return -EINVAL;
|
||||
|
||||
return ipath_user_sdma_writev(pd->port_dd, pq, iov, dim);
|
||||
return ipath_user_sdma_writev(pd->port_dd, pq, from->iov, from->nr_segs);
|
||||
}
|
||||
|
||||
static struct class *ipath_class;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <asm/pgtable.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
#include "qib.h"
|
||||
#include "qib_common.h"
|
||||
|
@ -54,15 +55,19 @@
|
|||
static int qib_open(struct inode *, struct file *);
|
||||
static int qib_close(struct inode *, struct file *);
|
||||
static ssize_t qib_write(struct file *, const char __user *, size_t, loff_t *);
|
||||
static ssize_t qib_aio_write(struct kiocb *, const struct iovec *,
|
||||
unsigned long, loff_t);
|
||||
static ssize_t qib_write_iter(struct kiocb *, struct iov_iter *);
|
||||
static unsigned int qib_poll(struct file *, struct poll_table_struct *);
|
||||
static int qib_mmapf(struct file *, struct vm_area_struct *);
|
||||
|
||||
/*
|
||||
* This is really, really weird shit - write() and writev() here
|
||||
* have completely unrelated semantics. Sucky userland ABI,
|
||||
* film at 11.
|
||||
*/
|
||||
static const struct file_operations qib_file_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.write = qib_write,
|
||||
.aio_write = qib_aio_write,
|
||||
.write_iter = qib_write_iter,
|
||||
.open = qib_open,
|
||||
.release = qib_close,
|
||||
.poll = qib_poll,
|
||||
|
@ -2248,17 +2253,16 @@ static ssize_t qib_write(struct file *fp, const char __user *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t qib_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long dim, loff_t off)
|
||||
static ssize_t qib_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct qib_filedata *fp = iocb->ki_filp->private_data;
|
||||
struct qib_ctxtdata *rcd = ctxt_fp(iocb->ki_filp);
|
||||
struct qib_user_sdma_queue *pq = fp->pq;
|
||||
|
||||
if (!dim || !pq)
|
||||
if (!iter_is_iovec(from) || !from->nr_segs || !pq)
|
||||
return -EINVAL;
|
||||
|
||||
return qib_user_sdma_writev(rcd, pq, iov, dim);
|
||||
|
||||
return qib_user_sdma_writev(rcd, pq, from->iov, from->nr_segs);
|
||||
}
|
||||
|
||||
static struct class *qib_class;
|
||||
|
|
|
@ -1118,8 +1118,6 @@ static const struct file_operations macvtap_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = macvtap_open,
|
||||
.release = macvtap_release,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = macvtap_read_iter,
|
||||
.write_iter = macvtap_write_iter,
|
||||
.poll = macvtap_poll,
|
||||
|
|
|
@ -2223,8 +2223,6 @@ static void tun_chr_show_fdinfo(struct seq_file *m, struct file *f)
|
|||
static const struct file_operations tun_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = tun_chr_read_iter,
|
||||
.write_iter = tun_chr_write_iter,
|
||||
.poll = tun_chr_poll,
|
||||
|
|
|
@ -310,7 +310,7 @@ static ssize_t ashmem_read(struct file *file, char __user *buf,
|
|||
* be destroyed until all references to the file are dropped and
|
||||
* ashmem_release is called.
|
||||
*/
|
||||
ret = asma->file->f_op->read(asma->file, buf, len, pos);
|
||||
ret = __vfs_read(asma->file, buf, len, pos);
|
||||
if (ret >= 0) {
|
||||
/** Update backing file pos, since f_ops->read() doesn't */
|
||||
asma->file->f_pos = *pos;
|
||||
|
|
|
@ -108,24 +108,16 @@ static int serial2002_tty_write(struct file *f, unsigned char *buf, int count)
|
|||
{
|
||||
const char __user *p = (__force const char __user *)buf;
|
||||
int result;
|
||||
loff_t offset = 0;
|
||||
mm_segment_t oldfs;
|
||||
|
||||
oldfs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
f->f_pos = 0;
|
||||
result = f->f_op->write(f, p, count, &f->f_pos);
|
||||
result = __vfs_write(f, p, count, &offset);
|
||||
set_fs(oldfs);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int serial2002_tty_readb(struct file *f, unsigned char *buf)
|
||||
{
|
||||
char __user *p = (__force char __user *)buf;
|
||||
|
||||
f->f_pos = 0;
|
||||
return f->f_op->read(f, p, 1, &f->f_pos);
|
||||
}
|
||||
|
||||
static void serial2002_tty_read_poll_wait(struct file *f, int timeout)
|
||||
{
|
||||
struct poll_wqueues table;
|
||||
|
@ -161,13 +153,15 @@ static int serial2002_tty_read(struct file *f, int timeout)
|
|||
result = -1;
|
||||
if (!IS_ERR(f)) {
|
||||
mm_segment_t oldfs;
|
||||
char __user *p = (__force char __user *)&ch;
|
||||
loff_t offset = 0;
|
||||
|
||||
oldfs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
if (f->f_op->poll) {
|
||||
serial2002_tty_read_poll_wait(f, timeout);
|
||||
|
||||
if (serial2002_tty_readb(f, &ch) == 1)
|
||||
if (__vfs_read(f, p, 1, &offset) == 1)
|
||||
result = ch;
|
||||
} else {
|
||||
/* Device does not support poll, busy wait */
|
||||
|
@ -178,7 +172,7 @@ static int serial2002_tty_read(struct file *f, int timeout)
|
|||
if (retries >= timeout)
|
||||
break;
|
||||
|
||||
if (serial2002_tty_readb(f, &ch) == 1) {
|
||||
if (__vfs_read(f, p, 1, &offset) == 1) {
|
||||
result = ch;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -3135,9 +3135,7 @@ int ll_inode_permission(struct inode *inode, int mask)
|
|||
|
||||
/* -o localflock - only provides locally consistent flock locks */
|
||||
struct file_operations ll_file_operations = {
|
||||
.read = new_sync_read,
|
||||
.read_iter = ll_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = ll_file_write_iter,
|
||||
.unlocked_ioctl = ll_file_ioctl,
|
||||
.open = ll_file_open,
|
||||
|
@ -3150,9 +3148,7 @@ struct file_operations ll_file_operations = {
|
|||
};
|
||||
|
||||
struct file_operations ll_file_operations_flock = {
|
||||
.read = new_sync_read,
|
||||
.read_iter = ll_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = ll_file_write_iter,
|
||||
.unlocked_ioctl = ll_file_ioctl,
|
||||
.open = ll_file_open,
|
||||
|
@ -3168,9 +3164,7 @@ struct file_operations ll_file_operations_flock = {
|
|||
|
||||
/* These are for -o noflock - to return ENOSYS on flock calls */
|
||||
struct file_operations ll_file_operations_noflock = {
|
||||
.read = new_sync_read,
|
||||
.read_iter = ll_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = ll_file_write_iter,
|
||||
.unlocked_ioctl = ll_file_ioctl,
|
||||
.open = ll_file_open,
|
||||
|
|
|
@ -938,10 +938,8 @@ struct ll_cl_context {
|
|||
};
|
||||
|
||||
struct vvp_thread_info {
|
||||
struct iovec vti_local_iov;
|
||||
struct vvp_io_args vti_args;
|
||||
struct ra_io_arg vti_ria;
|
||||
struct kiocb vti_kiocb;
|
||||
struct ll_cl_context vti_io_ctx;
|
||||
};
|
||||
|
||||
|
|
|
@ -1061,8 +1061,6 @@ static const struct file_operations ffs_epfile_operations = {
|
|||
.llseek = no_llseek,
|
||||
|
||||
.open = ffs_epfile_open,
|
||||
.write = new_sync_write,
|
||||
.read = new_sync_read,
|
||||
.write_iter = ffs_epfile_write_iter,
|
||||
.read_iter = ffs_epfile_read_iter,
|
||||
.release = ffs_epfile_release,
|
||||
|
|
|
@ -699,8 +699,6 @@ static const struct file_operations ep_io_operations = {
|
|||
.open = ep_open,
|
||||
.release = ep_release,
|
||||
.llseek = no_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.unlocked_ioctl = ep_ioctl,
|
||||
.read_iter = ep_read_iter,
|
||||
.write_iter = ep_write_iter,
|
||||
|
|
|
@ -68,14 +68,10 @@ int v9fs_file_open(struct inode *inode, struct file *file);
|
|||
void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
|
||||
int v9fs_uflags2omode(int uflags, int extended);
|
||||
|
||||
ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
|
||||
ssize_t v9fs_fid_readn(struct p9_fid *, char *, char __user *, u32, u64);
|
||||
void v9fs_blank_wstat(struct p9_wstat *wstat);
|
||||
int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *);
|
||||
int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
|
||||
int datasync);
|
||||
ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *,
|
||||
const char __user *, size_t, loff_t *, int);
|
||||
int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode);
|
||||
int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode);
|
||||
static inline void v9fs_invalidate_inode_attr(struct inode *inode)
|
||||
|
|
|
@ -51,12 +51,11 @@
|
|||
*/
|
||||
static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
|
||||
{
|
||||
int retval;
|
||||
loff_t offset;
|
||||
char *buffer;
|
||||
struct inode *inode;
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct bio_vec bvec = {.bv_page = page, .bv_len = PAGE_SIZE};
|
||||
struct iov_iter to;
|
||||
int retval, err;
|
||||
|
||||
inode = page->mapping->host;
|
||||
p9_debug(P9_DEBUG_VFS, "\n");
|
||||
|
||||
BUG_ON(!PageLocked(page));
|
||||
|
@ -65,16 +64,16 @@ static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
|
|||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
buffer = kmap(page);
|
||||
offset = page_offset(page);
|
||||
iov_iter_bvec(&to, ITER_BVEC | READ, &bvec, 1, PAGE_SIZE);
|
||||
|
||||
retval = v9fs_fid_readn(fid, buffer, NULL, PAGE_CACHE_SIZE, offset);
|
||||
if (retval < 0) {
|
||||
retval = p9_client_read(fid, page_offset(page), &to, &err);
|
||||
if (err) {
|
||||
v9fs_uncache_page(inode, page);
|
||||
retval = err;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memset(buffer + retval, 0, PAGE_CACHE_SIZE - retval);
|
||||
zero_user(page, retval, PAGE_SIZE - retval);
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
|
||||
|
@ -82,7 +81,6 @@ static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
|
|||
retval = 0;
|
||||
|
||||
done:
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
return retval;
|
||||
}
|
||||
|
@ -161,41 +159,32 @@ static void v9fs_invalidate_page(struct page *page, unsigned int offset,
|
|||
|
||||
static int v9fs_vfs_writepage_locked(struct page *page)
|
||||
{
|
||||
char *buffer;
|
||||
int retval, len;
|
||||
loff_t offset, size;
|
||||
mm_segment_t old_fs;
|
||||
struct v9fs_inode *v9inode;
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct v9fs_inode *v9inode = V9FS_I(inode);
|
||||
loff_t size = i_size_read(inode);
|
||||
struct iov_iter from;
|
||||
struct bio_vec bvec;
|
||||
int err, len;
|
||||
|
||||
v9inode = V9FS_I(inode);
|
||||
size = i_size_read(inode);
|
||||
if (page->index == size >> PAGE_CACHE_SHIFT)
|
||||
len = size & ~PAGE_CACHE_MASK;
|
||||
else
|
||||
len = PAGE_CACHE_SIZE;
|
||||
|
||||
set_page_writeback(page);
|
||||
bvec.bv_page = page;
|
||||
bvec.bv_offset = 0;
|
||||
bvec.bv_len = len;
|
||||
iov_iter_bvec(&from, ITER_BVEC | WRITE, &bvec, 1, len);
|
||||
|
||||
buffer = kmap(page);
|
||||
offset = page_offset(page);
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
/* We should have writeback_fid always set */
|
||||
BUG_ON(!v9inode->writeback_fid);
|
||||
|
||||
retval = v9fs_file_write_internal(inode,
|
||||
v9inode->writeback_fid,
|
||||
(__force const char __user *)buffer,
|
||||
len, &offset, 0);
|
||||
if (retval > 0)
|
||||
retval = 0;
|
||||
set_page_writeback(page);
|
||||
|
||||
p9_client_write(v9inode->writeback_fid, page_offset(page), &from, &err);
|
||||
|
||||
set_fs(old_fs);
|
||||
kunmap(page);
|
||||
end_page_writeback(page);
|
||||
return retval;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
|
@ -261,16 +250,21 @@ static int v9fs_launder_page(struct page *page)
|
|||
static ssize_t
|
||||
v9fs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos)
|
||||
{
|
||||
/*
|
||||
* FIXME
|
||||
* Now that we do caching with cache mode enabled, We need
|
||||
* to support direct IO
|
||||
*/
|
||||
p9_debug(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%pD) off/no(%lld/%lu) EINVAL\n",
|
||||
iocb->ki_filp,
|
||||
(long long)pos, iter->nr_segs);
|
||||
|
||||
return -EINVAL;
|
||||
struct file *file = iocb->ki_filp;
|
||||
ssize_t n;
|
||||
int err = 0;
|
||||
if (rw & WRITE) {
|
||||
n = p9_client_write(file->private_data, pos, iter, &err);
|
||||
if (n) {
|
||||
struct inode *inode = file_inode(file);
|
||||
loff_t i_size = i_size_read(inode);
|
||||
if (pos + n > i_size)
|
||||
inode_add_bytes(inode, pos + n - i_size);
|
||||
}
|
||||
} else {
|
||||
n = p9_client_read(file->private_data, pos, iter, &err);
|
||||
}
|
||||
return n ? n : err;
|
||||
}
|
||||
|
||||
static int v9fs_write_begin(struct file *filp, struct address_space *mapping,
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/inet.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uio.h>
|
||||
#include <net/9p/9p.h>
|
||||
#include <net/9p/client.h>
|
||||
|
||||
|
@ -115,6 +116,7 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
|
|||
int buflen;
|
||||
int reclen = 0;
|
||||
struct p9_rdir *rdir;
|
||||
struct kvec kvec;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
|
||||
fid = file->private_data;
|
||||
|
@ -124,16 +126,21 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
|
|||
rdir = v9fs_alloc_rdir_buf(file, buflen);
|
||||
if (!rdir)
|
||||
return -ENOMEM;
|
||||
kvec.iov_base = rdir->buf;
|
||||
kvec.iov_len = buflen;
|
||||
|
||||
while (1) {
|
||||
if (rdir->tail == rdir->head) {
|
||||
err = v9fs_file_readn(file, rdir->buf, NULL,
|
||||
buflen, ctx->pos);
|
||||
if (err <= 0)
|
||||
struct iov_iter to;
|
||||
int n;
|
||||
iov_iter_kvec(&to, READ | ITER_KVEC, &kvec, 1, buflen);
|
||||
n = p9_client_read(file->private_data, ctx->pos, &to,
|
||||
&err);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
rdir->head = 0;
|
||||
rdir->tail = err;
|
||||
rdir->tail = n;
|
||||
}
|
||||
while (rdir->head < rdir->tail) {
|
||||
p9stat_init(&st);
|
||||
|
|
314
fs/9p/vfs_file.c
314
fs/9p/vfs_file.c
|
@ -36,6 +36,8 @@
|
|||
#include <linux/utsname.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/9p/9p.h>
|
||||
#include <net/9p/client.h>
|
||||
|
||||
|
@ -285,6 +287,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
|
|||
fl->fl_end = glock.start + glock.length - 1;
|
||||
fl->fl_pid = glock.proc_id;
|
||||
}
|
||||
kfree(glock.client_id);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -363,63 +366,6 @@ static int v9fs_file_flock_dotl(struct file *filp, int cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_fid_readn - read from a fid
|
||||
* @fid: fid to read
|
||||
* @data: data buffer to read data into
|
||||
* @udata: user data buffer to read data into
|
||||
* @count: size of buffer
|
||||
* @offset: offset at which to read data
|
||||
*
|
||||
*/
|
||||
ssize_t
|
||||
v9fs_fid_readn(struct p9_fid *fid, char *data, char __user *udata, u32 count,
|
||||
u64 offset)
|
||||
{
|
||||
int n, total, size;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, "fid %d offset %llu count %d\n",
|
||||
fid->fid, (long long unsigned)offset, count);
|
||||
n = 0;
|
||||
total = 0;
|
||||
size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
|
||||
do {
|
||||
n = p9_client_read(fid, data, udata, offset, count);
|
||||
if (n <= 0)
|
||||
break;
|
||||
|
||||
if (data)
|
||||
data += n;
|
||||
if (udata)
|
||||
udata += n;
|
||||
|
||||
offset += n;
|
||||
count -= n;
|
||||
total += n;
|
||||
} while (count > 0 && n == size);
|
||||
|
||||
if (n < 0)
|
||||
total = n;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_file_readn - read from a file
|
||||
* @filp: file pointer to read
|
||||
* @data: data buffer to read data into
|
||||
* @udata: user data buffer to read data into
|
||||
* @count: size of buffer
|
||||
* @offset: offset at which to read data
|
||||
*
|
||||
*/
|
||||
ssize_t
|
||||
v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
|
||||
u64 offset)
|
||||
{
|
||||
return v9fs_fid_readn(filp->private_data, data, udata, count, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_file_read - read from a file
|
||||
* @filp: file pointer to read
|
||||
|
@ -430,69 +376,22 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
|
|||
*/
|
||||
|
||||
static ssize_t
|
||||
v9fs_file_read(struct file *filp, char __user *udata, size_t count,
|
||||
loff_t * offset)
|
||||
v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
int ret;
|
||||
struct p9_fid *fid;
|
||||
size_t size;
|
||||
struct p9_fid *fid = iocb->ki_filp->private_data;
|
||||
int ret, err;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
|
||||
fid = filp->private_data;
|
||||
p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n",
|
||||
iov_iter_count(to), iocb->ki_pos);
|
||||
|
||||
size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
|
||||
if (count > size)
|
||||
ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
|
||||
else
|
||||
ret = p9_client_read(fid, NULL, udata, *offset, count);
|
||||
|
||||
if (ret > 0)
|
||||
*offset += ret;
|
||||
ret = p9_client_read(fid, iocb->ki_pos, to, &err);
|
||||
if (!ret)
|
||||
return err;
|
||||
|
||||
iocb->ki_pos += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid,
|
||||
const char __user *data, size_t count,
|
||||
loff_t *offset, int invalidate)
|
||||
{
|
||||
int n;
|
||||
loff_t i_size;
|
||||
size_t total = 0;
|
||||
loff_t origin = *offset;
|
||||
unsigned long pg_start, pg_end;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, "data %p count %d offset %x\n",
|
||||
data, (int)count, (int)*offset);
|
||||
|
||||
do {
|
||||
n = p9_client_write(fid, NULL, data+total, origin+total, count);
|
||||
if (n <= 0)
|
||||
break;
|
||||
count -= n;
|
||||
total += n;
|
||||
} while (count > 0);
|
||||
|
||||
if (invalidate && (total > 0)) {
|
||||
pg_start = origin >> PAGE_CACHE_SHIFT;
|
||||
pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
|
||||
if (inode->i_mapping && inode->i_mapping->nrpages)
|
||||
invalidate_inode_pages2_range(inode->i_mapping,
|
||||
pg_start, pg_end);
|
||||
*offset += total;
|
||||
i_size = i_size_read(inode);
|
||||
if (*offset > i_size) {
|
||||
inode_add_bytes(inode, *offset - i_size);
|
||||
i_size_write(inode, *offset);
|
||||
}
|
||||
}
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_file_write - write to a file
|
||||
* @filp: file pointer to write
|
||||
|
@ -502,35 +401,45 @@ v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid,
|
|||
*
|
||||
*/
|
||||
static ssize_t
|
||||
v9fs_file_write(struct file *filp, const char __user * data,
|
||||
size_t count, loff_t *offset)
|
||||
v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
ssize_t retval = 0;
|
||||
loff_t origin = *offset;
|
||||
loff_t origin = iocb->ki_pos;
|
||||
size_t count = iov_iter_count(from);
|
||||
int err = 0;
|
||||
|
||||
|
||||
retval = generic_write_checks(filp, &origin, &count, 0);
|
||||
retval = generic_write_checks(file, &origin, &count, 0);
|
||||
if (retval)
|
||||
goto out;
|
||||
return retval;
|
||||
|
||||
iov_iter_truncate(from, count);
|
||||
|
||||
retval = -EINVAL;
|
||||
if ((ssize_t) count < 0)
|
||||
goto out;
|
||||
retval = 0;
|
||||
if (!count)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
retval = v9fs_file_write_internal(file_inode(filp),
|
||||
filp->private_data,
|
||||
data, count, &origin, 1);
|
||||
/* update offset on successful write */
|
||||
if (retval > 0)
|
||||
*offset = origin;
|
||||
out:
|
||||
return retval;
|
||||
retval = p9_client_write(file->private_data, origin, from, &err);
|
||||
if (retval > 0) {
|
||||
struct inode *inode = file_inode(file);
|
||||
loff_t i_size;
|
||||
unsigned long pg_start, pg_end;
|
||||
pg_start = origin >> PAGE_CACHE_SHIFT;
|
||||
pg_end = (origin + retval - 1) >> PAGE_CACHE_SHIFT;
|
||||
if (inode->i_mapping && inode->i_mapping->nrpages)
|
||||
invalidate_inode_pages2_range(inode->i_mapping,
|
||||
pg_start, pg_end);
|
||||
origin += retval;
|
||||
i_size = i_size_read(inode);
|
||||
iocb->ki_pos = origin;
|
||||
if (origin > i_size) {
|
||||
inode_add_bytes(inode, origin - i_size);
|
||||
i_size_write(inode, origin);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end,
|
||||
int datasync)
|
||||
{
|
||||
|
@ -657,44 +566,6 @@ v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
return VM_FAULT_NOPAGE;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
v9fs_direct_read(struct file *filp, char __user *udata, size_t count,
|
||||
loff_t *offsetp)
|
||||
{
|
||||
loff_t size, offset;
|
||||
struct inode *inode;
|
||||
struct address_space *mapping;
|
||||
|
||||
offset = *offsetp;
|
||||
mapping = filp->f_mapping;
|
||||
inode = mapping->host;
|
||||
if (!count)
|
||||
return 0;
|
||||
size = i_size_read(inode);
|
||||
if (offset < size)
|
||||
filemap_write_and_wait_range(mapping, offset,
|
||||
offset + count - 1);
|
||||
|
||||
return v9fs_file_read(filp, udata, count, offsetp);
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_cached_file_read - read from a file
|
||||
* @filp: file pointer to read
|
||||
* @data: user data buffer to read data into
|
||||
* @count: size of buffer
|
||||
* @offset: offset at which to read data
|
||||
*
|
||||
*/
|
||||
static ssize_t
|
||||
v9fs_cached_file_read(struct file *filp, char __user *data, size_t count,
|
||||
loff_t *offset)
|
||||
{
|
||||
if (filp->f_flags & O_DIRECT)
|
||||
return v9fs_direct_read(filp, data, count, offset);
|
||||
return new_sync_read(filp, data, count, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_mmap_file_read - read from a file
|
||||
* @filp: file pointer to read
|
||||
|
@ -704,84 +575,12 @@ v9fs_cached_file_read(struct file *filp, char __user *data, size_t count,
|
|||
*
|
||||
*/
|
||||
static ssize_t
|
||||
v9fs_mmap_file_read(struct file *filp, char __user *data, size_t count,
|
||||
loff_t *offset)
|
||||
v9fs_mmap_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
/* TODO: Check if there are dirty pages */
|
||||
return v9fs_file_read(filp, data, count, offset);
|
||||
return v9fs_file_read_iter(iocb, to);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
v9fs_direct_write(struct file *filp, const char __user * data,
|
||||
size_t count, loff_t *offsetp)
|
||||
{
|
||||
loff_t offset;
|
||||
ssize_t retval;
|
||||
struct inode *inode;
|
||||
struct address_space *mapping;
|
||||
|
||||
offset = *offsetp;
|
||||
mapping = filp->f_mapping;
|
||||
inode = mapping->host;
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
retval = filemap_write_and_wait_range(mapping, offset,
|
||||
offset + count - 1);
|
||||
if (retval)
|
||||
goto err_out;
|
||||
/*
|
||||
* After a write we want buffered reads to be sure to go to disk to get
|
||||
* the new data. We invalidate clean cached page from the region we're
|
||||
* about to write. We do this *before* the write so that if we fail
|
||||
* here we fall back to buffered write
|
||||
*/
|
||||
if (mapping->nrpages) {
|
||||
pgoff_t pg_start = offset >> PAGE_CACHE_SHIFT;
|
||||
pgoff_t pg_end = (offset + count - 1) >> PAGE_CACHE_SHIFT;
|
||||
|
||||
retval = invalidate_inode_pages2_range(mapping,
|
||||
pg_start, pg_end);
|
||||
/*
|
||||
* If a page can not be invalidated, fall back
|
||||
* to buffered write.
|
||||
*/
|
||||
if (retval) {
|
||||
if (retval == -EBUSY)
|
||||
goto buff_write;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
retval = v9fs_file_write(filp, data, count, offsetp);
|
||||
err_out:
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return retval;
|
||||
|
||||
buff_write:
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return new_sync_write(filp, data, count, offsetp);
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_cached_file_write - write to a file
|
||||
* @filp: file pointer to write
|
||||
* @data: data buffer to write data from
|
||||
* @count: size of buffer
|
||||
* @offset: offset at which to write data
|
||||
*
|
||||
*/
|
||||
static ssize_t
|
||||
v9fs_cached_file_write(struct file *filp, const char __user * data,
|
||||
size_t count, loff_t *offset)
|
||||
{
|
||||
|
||||
if (filp->f_flags & O_DIRECT)
|
||||
return v9fs_direct_write(filp, data, count, offset);
|
||||
return new_sync_write(filp, data, count, offset);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* v9fs_mmap_file_write - write to a file
|
||||
* @filp: file pointer to write
|
||||
|
@ -791,14 +590,13 @@ v9fs_cached_file_write(struct file *filp, const char __user * data,
|
|||
*
|
||||
*/
|
||||
static ssize_t
|
||||
v9fs_mmap_file_write(struct file *filp, const char __user *data,
|
||||
size_t count, loff_t *offset)
|
||||
v9fs_mmap_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
/*
|
||||
* TODO: invalidate mmaps on filp's inode between
|
||||
* offset and offset+count
|
||||
*/
|
||||
return v9fs_file_write(filp, data, count, offset);
|
||||
return v9fs_file_write_iter(iocb, from);
|
||||
}
|
||||
|
||||
static void v9fs_mmap_vm_close(struct vm_area_struct *vma)
|
||||
|
@ -843,8 +641,6 @@ static const struct vm_operations_struct v9fs_mmap_file_vm_ops = {
|
|||
|
||||
const struct file_operations v9fs_cached_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = v9fs_cached_file_read,
|
||||
.write = v9fs_cached_file_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.open = v9fs_file_open,
|
||||
|
@ -856,8 +652,6 @@ const struct file_operations v9fs_cached_file_operations = {
|
|||
|
||||
const struct file_operations v9fs_cached_file_operations_dotl = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = v9fs_cached_file_read,
|
||||
.write = v9fs_cached_file_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.open = v9fs_file_open,
|
||||
|
@ -870,8 +664,8 @@ const struct file_operations v9fs_cached_file_operations_dotl = {
|
|||
|
||||
const struct file_operations v9fs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = v9fs_file_read,
|
||||
.write = v9fs_file_write,
|
||||
.read_iter = v9fs_file_read_iter,
|
||||
.write_iter = v9fs_file_write_iter,
|
||||
.open = v9fs_file_open,
|
||||
.release = v9fs_dir_release,
|
||||
.lock = v9fs_file_lock,
|
||||
|
@ -881,8 +675,8 @@ const struct file_operations v9fs_file_operations = {
|
|||
|
||||
const struct file_operations v9fs_file_operations_dotl = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = v9fs_file_read,
|
||||
.write = v9fs_file_write,
|
||||
.read_iter = v9fs_file_read_iter,
|
||||
.write_iter = v9fs_file_write_iter,
|
||||
.open = v9fs_file_open,
|
||||
.release = v9fs_dir_release,
|
||||
.lock = v9fs_file_lock_dotl,
|
||||
|
@ -893,8 +687,8 @@ const struct file_operations v9fs_file_operations_dotl = {
|
|||
|
||||
const struct file_operations v9fs_mmap_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = v9fs_mmap_file_read,
|
||||
.write = v9fs_mmap_file_write,
|
||||
.read_iter = v9fs_mmap_file_read_iter,
|
||||
.write_iter = v9fs_mmap_file_write_iter,
|
||||
.open = v9fs_file_open,
|
||||
.release = v9fs_dir_release,
|
||||
.lock = v9fs_file_lock,
|
||||
|
@ -904,8 +698,8 @@ const struct file_operations v9fs_mmap_file_operations = {
|
|||
|
||||
const struct file_operations v9fs_mmap_file_operations_dotl = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = v9fs_mmap_file_read,
|
||||
.write = v9fs_mmap_file_write,
|
||||
.read_iter = v9fs_mmap_file_read_iter,
|
||||
.write_iter = v9fs_mmap_file_write_iter,
|
||||
.open = v9fs_file_open,
|
||||
.release = v9fs_dir_release,
|
||||
.lock = v9fs_file_lock_dotl,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uio.h>
|
||||
#include <net/9p/9p.h>
|
||||
#include <net/9p/client.h>
|
||||
|
||||
|
@ -25,50 +26,34 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
|
|||
void *buffer, size_t buffer_size)
|
||||
{
|
||||
ssize_t retval;
|
||||
int msize, read_count;
|
||||
u64 offset = 0, attr_size;
|
||||
u64 attr_size;
|
||||
struct p9_fid *attr_fid;
|
||||
struct kvec kvec = {.iov_base = buffer, .iov_len = buffer_size};
|
||||
struct iov_iter to;
|
||||
int err;
|
||||
|
||||
iov_iter_kvec(&to, READ | ITER_KVEC, &kvec, 1, buffer_size);
|
||||
|
||||
attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
|
||||
if (IS_ERR(attr_fid)) {
|
||||
retval = PTR_ERR(attr_fid);
|
||||
p9_debug(P9_DEBUG_VFS, "p9_client_attrwalk failed %zd\n",
|
||||
retval);
|
||||
attr_fid = NULL;
|
||||
goto error;
|
||||
}
|
||||
if (!buffer_size) {
|
||||
/* request to get the attr_size */
|
||||
retval = attr_size;
|
||||
goto error;
|
||||
return retval;
|
||||
}
|
||||
if (attr_size > buffer_size) {
|
||||
retval = -ERANGE;
|
||||
goto error;
|
||||
}
|
||||
msize = attr_fid->clnt->msize;
|
||||
while (attr_size) {
|
||||
if (attr_size > (msize - P9_IOHDRSZ))
|
||||
read_count = msize - P9_IOHDRSZ;
|
||||
if (!buffer_size) /* request to get the attr_size */
|
||||
retval = attr_size;
|
||||
else
|
||||
read_count = attr_size;
|
||||
read_count = p9_client_read(attr_fid, ((char *)buffer)+offset,
|
||||
NULL, offset, read_count);
|
||||
if (read_count < 0) {
|
||||
/* error in xattr read */
|
||||
retval = read_count;
|
||||
goto error;
|
||||
}
|
||||
offset += read_count;
|
||||
attr_size -= read_count;
|
||||
retval = -ERANGE;
|
||||
} else {
|
||||
iov_iter_truncate(&to, attr_size);
|
||||
retval = p9_client_read(attr_fid, 0, &to, &err);
|
||||
if (err)
|
||||
retval = err;
|
||||
}
|
||||
/* Total read xattr bytes */
|
||||
retval = offset;
|
||||
error:
|
||||
if (attr_fid)
|
||||
p9_client_clunk(attr_fid);
|
||||
p9_client_clunk(attr_fid);
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -120,8 +105,11 @@ int v9fs_xattr_set(struct dentry *dentry, const char *name,
|
|||
int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
|
||||
const void *value, size_t value_len, int flags)
|
||||
{
|
||||
u64 offset = 0;
|
||||
int retval, msize, write_count;
|
||||
struct kvec kvec = {.iov_base = (void *)value, .iov_len = value_len};
|
||||
struct iov_iter from;
|
||||
int retval;
|
||||
|
||||
iov_iter_kvec(&from, WRITE | ITER_KVEC, &kvec, 1, value_len);
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n",
|
||||
name, value_len, flags);
|
||||
|
@ -135,29 +123,11 @@ int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
|
|||
* On success fid points to xattr
|
||||
*/
|
||||
retval = p9_client_xattrcreate(fid, name, value_len, flags);
|
||||
if (retval < 0) {
|
||||
if (retval < 0)
|
||||
p9_debug(P9_DEBUG_VFS, "p9_client_xattrcreate failed %d\n",
|
||||
retval);
|
||||
goto err;
|
||||
}
|
||||
msize = fid->clnt->msize;
|
||||
while (value_len) {
|
||||
if (value_len > (msize - P9_IOHDRSZ))
|
||||
write_count = msize - P9_IOHDRSZ;
|
||||
else
|
||||
write_count = value_len;
|
||||
write_count = p9_client_write(fid, ((char *)value)+offset,
|
||||
NULL, offset, write_count);
|
||||
if (write_count < 0) {
|
||||
/* error in xattr write */
|
||||
retval = write_count;
|
||||
goto err;
|
||||
}
|
||||
offset += write_count;
|
||||
value_len -= write_count;
|
||||
}
|
||||
retval = 0;
|
||||
err:
|
||||
else
|
||||
p9_client_write(fid, 0, &from, &retval);
|
||||
p9_client_clunk(fid);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -23,11 +23,9 @@
|
|||
|
||||
const struct file_operations adfs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
.fsync = generic_file_fsync,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.splice_read = generic_file_splice_read,
|
||||
};
|
||||
|
|
|
@ -969,9 +969,7 @@ int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
|
|||
}
|
||||
const struct file_operations affs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
.open = affs_file_open,
|
||||
|
|
|
@ -31,8 +31,6 @@ const struct file_operations afs_file_operations = {
|
|||
.open = afs_open,
|
||||
.release = afs_release,
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = afs_file_write,
|
||||
.mmap = generic_file_readonly_mmap,
|
||||
|
|
23
fs/aio.c
23
fs/aio.c
|
@ -692,8 +692,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
|
|||
nr_events *= 2;
|
||||
|
||||
/* Prevent overflows */
|
||||
if ((nr_events > (0x10000000U / sizeof(struct io_event))) ||
|
||||
(nr_events > (0x10000000U / sizeof(struct kiocb)))) {
|
||||
if (nr_events > (0x10000000U / sizeof(struct io_event))) {
|
||||
pr_debug("ENOMEM: nr_events too high\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
@ -1356,8 +1355,6 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *,
|
||||
unsigned long, loff_t);
|
||||
typedef ssize_t (rw_iter_op)(struct kiocb *, struct iov_iter *);
|
||||
|
||||
static int aio_setup_vectored_rw(int rw, char __user *buf, size_t len,
|
||||
|
@ -1386,7 +1383,6 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
|
|||
ssize_t ret;
|
||||
int rw;
|
||||
fmode_t mode;
|
||||
aio_rw_op *rw_op;
|
||||
rw_iter_op *iter_op;
|
||||
struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
|
||||
struct iov_iter iter;
|
||||
|
@ -1396,7 +1392,6 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
|
|||
case IOCB_CMD_PREADV:
|
||||
mode = FMODE_READ;
|
||||
rw = READ;
|
||||
rw_op = file->f_op->aio_read;
|
||||
iter_op = file->f_op->read_iter;
|
||||
goto rw_common;
|
||||
|
||||
|
@ -1404,14 +1399,13 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
|
|||
case IOCB_CMD_PWRITEV:
|
||||
mode = FMODE_WRITE;
|
||||
rw = WRITE;
|
||||
rw_op = file->f_op->aio_write;
|
||||
iter_op = file->f_op->write_iter;
|
||||
goto rw_common;
|
||||
rw_common:
|
||||
if (unlikely(!(file->f_mode & mode)))
|
||||
return -EBADF;
|
||||
|
||||
if (!rw_op && !iter_op)
|
||||
if (!iter_op)
|
||||
return -EINVAL;
|
||||
|
||||
if (opcode == IOCB_CMD_PREADV || opcode == IOCB_CMD_PWRITEV)
|
||||
|
@ -1431,21 +1425,10 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
|
|||
|
||||
len = ret;
|
||||
|
||||
/* XXX: move/kill - rw_verify_area()? */
|
||||
/* This matches the pread()/pwrite() logic */
|
||||
if (req->ki_pos < 0) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rw == WRITE)
|
||||
file_start_write(file);
|
||||
|
||||
if (iter_op) {
|
||||
ret = iter_op(req, &iter);
|
||||
} else {
|
||||
ret = rw_op(req, iter.iov, iter.nr_segs, req->ki_pos);
|
||||
}
|
||||
ret = iter_op(req, &iter);
|
||||
|
||||
if (rw == WRITE)
|
||||
file_end_write(file);
|
||||
|
|
|
@ -213,7 +213,7 @@ void autofs4_clean_ino(struct autofs_info *);
|
|||
|
||||
static inline int autofs_prepare_pipe(struct file *pipe)
|
||||
{
|
||||
if (!pipe->f_op->write)
|
||||
if (!(pipe->f_mode & FMODE_CAN_WRITE))
|
||||
return -EINVAL;
|
||||
if (!S_ISFIFO(file_inode(pipe)->i_mode))
|
||||
return -EINVAL;
|
||||
|
|
|
@ -70,7 +70,7 @@ static int autofs4_write(struct autofs_sb_info *sbi,
|
|||
|
||||
mutex_lock(&sbi->pipe_mutex);
|
||||
while (bytes &&
|
||||
(wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) {
|
||||
(wr = __vfs_write(file,data,bytes,&file->f_pos)) > 0) {
|
||||
data += wr;
|
||||
bytes -= wr;
|
||||
}
|
||||
|
|
|
@ -23,9 +23,7 @@
|
|||
|
||||
const struct file_operations bfs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
|
|
|
@ -1659,8 +1659,6 @@ const struct file_operations def_blk_fops = {
|
|||
.open = blkdev_open,
|
||||
.release = blkdev_close,
|
||||
.llseek = block_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = blkdev_read_iter,
|
||||
.write_iter = blkdev_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
|
|
|
@ -2806,8 +2806,6 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence)
|
|||
|
||||
const struct file_operations btrfs_file_operations = {
|
||||
.llseek = btrfs_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.write_iter = btrfs_file_write_iter,
|
||||
|
|
|
@ -1331,8 +1331,6 @@ const struct file_operations ceph_file_fops = {
|
|||
.open = ceph_open,
|
||||
.release = ceph_release,
|
||||
.llseek = ceph_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = ceph_read_iter,
|
||||
.write_iter = ceph_write_iter,
|
||||
.mmap = ceph_mmap,
|
||||
|
|
|
@ -906,8 +906,6 @@ const struct inode_operations cifs_symlink_inode_ops = {
|
|||
};
|
||||
|
||||
const struct file_operations cifs_file_ops = {
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = cifs_loose_read_iter,
|
||||
.write_iter = cifs_file_write_iter,
|
||||
.open = cifs_open,
|
||||
|
@ -926,8 +924,6 @@ const struct file_operations cifs_file_ops = {
|
|||
};
|
||||
|
||||
const struct file_operations cifs_file_strict_ops = {
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = cifs_strict_readv,
|
||||
.write_iter = cifs_strict_writev,
|
||||
.open = cifs_open,
|
||||
|
@ -947,8 +943,6 @@ const struct file_operations cifs_file_strict_ops = {
|
|||
|
||||
const struct file_operations cifs_file_direct_ops = {
|
||||
/* BB reevaluate whether they can be done with directio, no cache */
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = cifs_user_readv,
|
||||
.write_iter = cifs_user_writev,
|
||||
.open = cifs_open,
|
||||
|
@ -967,8 +961,6 @@ const struct file_operations cifs_file_direct_ops = {
|
|||
};
|
||||
|
||||
const struct file_operations cifs_file_nobrl_ops = {
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = cifs_loose_read_iter,
|
||||
.write_iter = cifs_file_write_iter,
|
||||
.open = cifs_open,
|
||||
|
@ -986,8 +978,6 @@ const struct file_operations cifs_file_nobrl_ops = {
|
|||
};
|
||||
|
||||
const struct file_operations cifs_file_strict_nobrl_ops = {
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = cifs_strict_readv,
|
||||
.write_iter = cifs_strict_writev,
|
||||
.open = cifs_open,
|
||||
|
@ -1006,8 +996,6 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
|
|||
|
||||
const struct file_operations cifs_file_direct_nobrl_ops = {
|
||||
/* BB reevaluate whether they can be done with directio, no cache */
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = cifs_user_readv,
|
||||
.write_iter = cifs_user_writev,
|
||||
.open = cifs_open,
|
||||
|
|
|
@ -27,19 +27,14 @@
|
|||
#include "coda_int.h"
|
||||
|
||||
static ssize_t
|
||||
coda_file_read(struct file *coda_file, char __user *buf, size_t count, loff_t *ppos)
|
||||
coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct coda_file_info *cfi;
|
||||
struct file *host_file;
|
||||
struct file *coda_file = iocb->ki_filp;
|
||||
struct coda_file_info *cfi = CODA_FTOC(coda_file);
|
||||
|
||||
cfi = CODA_FTOC(coda_file);
|
||||
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
|
||||
host_file = cfi->cfi_container;
|
||||
|
||||
if (!host_file->f_op->read)
|
||||
return -EINVAL;
|
||||
|
||||
return host_file->f_op->read(host_file, buf, count, ppos);
|
||||
return vfs_iter_read(cfi->cfi_container, to, &iocb->ki_pos);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
@ -64,32 +59,25 @@ coda_file_splice_read(struct file *coda_file, loff_t *ppos,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
coda_file_write(struct file *coda_file, const char __user *buf, size_t count, loff_t *ppos)
|
||||
coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct inode *host_inode, *coda_inode = file_inode(coda_file);
|
||||
struct coda_file_info *cfi;
|
||||
struct file *coda_file = iocb->ki_filp;
|
||||
struct inode *coda_inode = file_inode(coda_file);
|
||||
struct coda_file_info *cfi = CODA_FTOC(coda_file);
|
||||
struct file *host_file;
|
||||
ssize_t ret;
|
||||
|
||||
cfi = CODA_FTOC(coda_file);
|
||||
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
|
||||
|
||||
host_file = cfi->cfi_container;
|
||||
|
||||
if (!host_file->f_op->write)
|
||||
return -EINVAL;
|
||||
|
||||
host_inode = file_inode(host_file);
|
||||
file_start_write(host_file);
|
||||
mutex_lock(&coda_inode->i_mutex);
|
||||
|
||||
ret = host_file->f_op->write(host_file, buf, count, ppos);
|
||||
|
||||
coda_inode->i_size = host_inode->i_size;
|
||||
ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos);
|
||||
coda_inode->i_size = file_inode(host_file)->i_size;
|
||||
coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
|
||||
coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME_SEC;
|
||||
mutex_unlock(&coda_inode->i_mutex);
|
||||
file_end_write(host_file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -231,8 +219,8 @@ int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync)
|
|||
|
||||
const struct file_operations coda_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = coda_file_read,
|
||||
.write = coda_file_write,
|
||||
.read_iter = coda_file_read_iter,
|
||||
.write_iter = coda_file_write_iter,
|
||||
.mmap = coda_file_mmap,
|
||||
.open = coda_open,
|
||||
.release = coda_release,
|
||||
|
|
|
@ -657,7 +657,7 @@ void do_coredump(const siginfo_t *siginfo)
|
|||
*/
|
||||
if (!uid_eq(inode->i_uid, current_fsuid()))
|
||||
goto close_fail;
|
||||
if (!cprm.file->f_op->write)
|
||||
if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
|
||||
goto close_fail;
|
||||
if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file))
|
||||
goto close_fail;
|
||||
|
|
|
@ -358,9 +358,7 @@ const struct file_operations ecryptfs_dir_fops = {
|
|||
|
||||
const struct file_operations ecryptfs_main_fops = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = ecryptfs_read_update_atime,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.iterate = ecryptfs_readdir,
|
||||
.unlocked_ioctl = ecryptfs_unlocked_ioctl,
|
||||
|
|
|
@ -67,8 +67,6 @@ static int exofs_flush(struct file *file, fl_owner_t id)
|
|||
|
||||
const struct file_operations exofs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
|
|
|
@ -92,8 +92,6 @@ int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
|||
*/
|
||||
const struct file_operations ext2_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.unlocked_ioctl = ext2_ioctl,
|
||||
|
@ -111,8 +109,6 @@ const struct file_operations ext2_file_operations = {
|
|||
#ifdef CONFIG_FS_DAX
|
||||
const struct file_operations ext2_dax_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.unlocked_ioctl = ext2_ioctl,
|
||||
|
|
|
@ -50,8 +50,6 @@ static int ext3_release_file (struct inode * inode, struct file * filp)
|
|||
|
||||
const struct file_operations ext3_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.unlocked_ioctl = ext3_ioctl,
|
||||
|
|
|
@ -607,8 +607,6 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence)
|
|||
|
||||
const struct file_operations ext4_file_operations = {
|
||||
.llseek = ext4_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = ext4_file_write_iter,
|
||||
.unlocked_ioctl = ext4_ioctl,
|
||||
|
@ -627,8 +625,6 @@ const struct file_operations ext4_file_operations = {
|
|||
#ifdef CONFIG_FS_DAX
|
||||
const struct file_operations ext4_dax_file_operations = {
|
||||
.llseek = ext4_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = ext4_file_write_iter,
|
||||
.unlocked_ioctl = ext4_ioctl,
|
||||
|
|
|
@ -1104,8 +1104,6 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
|
||||
const struct file_operations f2fs_file_operations = {
|
||||
.llseek = f2fs_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.open = generic_file_open,
|
||||
|
|
|
@ -170,8 +170,6 @@ int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
|
|||
|
||||
const struct file_operations fat_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
|
|
|
@ -168,10 +168,10 @@ struct file *alloc_file(struct path *path, fmode_t mode,
|
|||
file->f_inode = path->dentry->d_inode;
|
||||
file->f_mapping = path->dentry->d_inode->i_mapping;
|
||||
if ((mode & FMODE_READ) &&
|
||||
likely(fop->read || fop->aio_read || fop->read_iter))
|
||||
likely(fop->read || fop->read_iter))
|
||||
mode |= FMODE_CAN_READ;
|
||||
if ((mode & FMODE_WRITE) &&
|
||||
likely(fop->write || fop->aio_write || fop->write_iter))
|
||||
likely(fop->write || fop->write_iter))
|
||||
mode |= FMODE_CAN_WRITE;
|
||||
file->f_mode = mode;
|
||||
file->f_op = fop;
|
||||
|
|
|
@ -88,32 +88,23 @@ static struct list_head *cuse_conntbl_head(dev_t devt)
|
|||
* FUSE file.
|
||||
*/
|
||||
|
||||
static ssize_t cuse_read(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
static ssize_t cuse_read_iter(struct kiocb *kiocb, struct iov_iter *to)
|
||||
{
|
||||
struct fuse_io_priv io = { .async = 0, .file = kiocb->ki_filp };
|
||||
loff_t pos = 0;
|
||||
struct iovec iov = { .iov_base = buf, .iov_len = count };
|
||||
struct fuse_io_priv io = { .async = 0, .file = file };
|
||||
struct iov_iter ii;
|
||||
iov_iter_init(&ii, READ, &iov, 1, count);
|
||||
|
||||
return fuse_direct_io(&io, &ii, &pos, FUSE_DIO_CUSE);
|
||||
return fuse_direct_io(&io, to, &pos, FUSE_DIO_CUSE);
|
||||
}
|
||||
|
||||
static ssize_t cuse_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
static ssize_t cuse_write_iter(struct kiocb *kiocb, struct iov_iter *from)
|
||||
{
|
||||
struct fuse_io_priv io = { .async = 0, .file = kiocb->ki_filp };
|
||||
loff_t pos = 0;
|
||||
struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count };
|
||||
struct fuse_io_priv io = { .async = 0, .file = file };
|
||||
struct iov_iter ii;
|
||||
iov_iter_init(&ii, WRITE, &iov, 1, count);
|
||||
|
||||
/*
|
||||
* No locking or generic_write_checks(), the server is
|
||||
* responsible for locking and sanity checks.
|
||||
*/
|
||||
return fuse_direct_io(&io, &ii, &pos,
|
||||
return fuse_direct_io(&io, from, &pos,
|
||||
FUSE_DIO_WRITE | FUSE_DIO_CUSE);
|
||||
}
|
||||
|
||||
|
@ -186,8 +177,8 @@ static long cuse_file_compat_ioctl(struct file *file, unsigned int cmd,
|
|||
|
||||
static const struct file_operations cuse_frontend_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = cuse_read,
|
||||
.write = cuse_write,
|
||||
.read_iter = cuse_read_iter,
|
||||
.write_iter = cuse_write_iter,
|
||||
.open = cuse_open,
|
||||
.release = cuse_release,
|
||||
.unlocked_ioctl = cuse_file_ioctl,
|
||||
|
|
|
@ -710,28 +710,26 @@ struct fuse_copy_state {
|
|||
struct fuse_conn *fc;
|
||||
int write;
|
||||
struct fuse_req *req;
|
||||
const struct iovec *iov;
|
||||
struct iov_iter *iter;
|
||||
struct pipe_buffer *pipebufs;
|
||||
struct pipe_buffer *currbuf;
|
||||
struct pipe_inode_info *pipe;
|
||||
unsigned long nr_segs;
|
||||
unsigned long seglen;
|
||||
unsigned long addr;
|
||||
struct page *pg;
|
||||
unsigned len;
|
||||
unsigned offset;
|
||||
unsigned move_pages:1;
|
||||
};
|
||||
|
||||
static void fuse_copy_init(struct fuse_copy_state *cs, struct fuse_conn *fc,
|
||||
static void fuse_copy_init(struct fuse_copy_state *cs,
|
||||
struct fuse_conn *fc,
|
||||
int write,
|
||||
const struct iovec *iov, unsigned long nr_segs)
|
||||
struct iov_iter *iter)
|
||||
{
|
||||
memset(cs, 0, sizeof(*cs));
|
||||
cs->fc = fc;
|
||||
cs->write = write;
|
||||
cs->iov = iov;
|
||||
cs->nr_segs = nr_segs;
|
||||
cs->iter = iter;
|
||||
}
|
||||
|
||||
/* Unmap and put previous page of userspace buffer */
|
||||
|
@ -799,22 +797,16 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
|
|||
cs->nr_segs++;
|
||||
}
|
||||
} else {
|
||||
if (!cs->seglen) {
|
||||
BUG_ON(!cs->nr_segs);
|
||||
cs->seglen = cs->iov[0].iov_len;
|
||||
cs->addr = (unsigned long) cs->iov[0].iov_base;
|
||||
cs->iov++;
|
||||
cs->nr_segs--;
|
||||
}
|
||||
err = get_user_pages_fast(cs->addr, 1, cs->write, &page);
|
||||
size_t off;
|
||||
err = iov_iter_get_pages(cs->iter, &page, PAGE_SIZE, 1, &off);
|
||||
if (err < 0)
|
||||
return err;
|
||||
BUG_ON(err != 1);
|
||||
BUG_ON(!err);
|
||||
cs->len = err;
|
||||
cs->offset = off;
|
||||
cs->pg = page;
|
||||
cs->offset = cs->addr % PAGE_SIZE;
|
||||
cs->len = min(PAGE_SIZE - cs->offset, cs->seglen);
|
||||
cs->seglen -= cs->len;
|
||||
cs->addr += cs->len;
|
||||
cs->offset = off;
|
||||
iov_iter_advance(cs->iter, err);
|
||||
}
|
||||
|
||||
return lock_request(cs->fc, cs->req);
|
||||
|
@ -1363,8 +1355,7 @@ static int fuse_dev_open(struct inode *inode, struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos)
|
||||
static ssize_t fuse_dev_read(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct fuse_copy_state cs;
|
||||
struct file *file = iocb->ki_filp;
|
||||
|
@ -1372,9 +1363,12 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
|
|||
if (!fc)
|
||||
return -EPERM;
|
||||
|
||||
fuse_copy_init(&cs, fc, 1, iov, nr_segs);
|
||||
if (!iter_is_iovec(to))
|
||||
return -EINVAL;
|
||||
|
||||
return fuse_dev_do_read(fc, file, &cs, iov_length(iov, nr_segs));
|
||||
fuse_copy_init(&cs, fc, 1, to);
|
||||
|
||||
return fuse_dev_do_read(fc, file, &cs, iov_iter_count(to));
|
||||
}
|
||||
|
||||
static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
|
||||
|
@ -1394,7 +1388,7 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
|
|||
if (!bufs)
|
||||
return -ENOMEM;
|
||||
|
||||
fuse_copy_init(&cs, fc, 1, NULL, 0);
|
||||
fuse_copy_init(&cs, fc, 1, NULL);
|
||||
cs.pipebufs = bufs;
|
||||
cs.pipe = pipe;
|
||||
ret = fuse_dev_do_read(fc, in, &cs, len);
|
||||
|
@ -1970,17 +1964,19 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc,
|
|||
return err;
|
||||
}
|
||||
|
||||
static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos)
|
||||
static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct fuse_copy_state cs;
|
||||
struct fuse_conn *fc = fuse_get_conn(iocb->ki_filp);
|
||||
if (!fc)
|
||||
return -EPERM;
|
||||
|
||||
fuse_copy_init(&cs, fc, 0, iov, nr_segs);
|
||||
if (!iter_is_iovec(from))
|
||||
return -EINVAL;
|
||||
|
||||
return fuse_dev_do_write(fc, &cs, iov_length(iov, nr_segs));
|
||||
fuse_copy_init(&cs, fc, 0, from);
|
||||
|
||||
return fuse_dev_do_write(fc, &cs, iov_iter_count(from));
|
||||
}
|
||||
|
||||
static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
|
||||
|
@ -2043,8 +2039,9 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
|
|||
}
|
||||
pipe_unlock(pipe);
|
||||
|
||||
fuse_copy_init(&cs, fc, 0, NULL, nbuf);
|
||||
fuse_copy_init(&cs, fc, 0, NULL);
|
||||
cs.pipebufs = bufs;
|
||||
cs.nr_segs = nbuf;
|
||||
cs.pipe = pipe;
|
||||
|
||||
if (flags & SPLICE_F_MOVE)
|
||||
|
@ -2232,11 +2229,9 @@ const struct file_operations fuse_dev_operations = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = fuse_dev_open,
|
||||
.llseek = no_llseek,
|
||||
.read = do_sync_read,
|
||||
.aio_read = fuse_dev_read,
|
||||
.read_iter = fuse_dev_read,
|
||||
.splice_read = fuse_dev_splice_read,
|
||||
.write = do_sync_write,
|
||||
.aio_write = fuse_dev_write,
|
||||
.write_iter = fuse_dev_write,
|
||||
.splice_write = fuse_dev_splice_write,
|
||||
.poll = fuse_dev_poll,
|
||||
.release = fuse_dev_release,
|
||||
|
|
|
@ -1401,55 +1401,33 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io,
|
|||
return res;
|
||||
}
|
||||
|
||||
static ssize_t fuse_direct_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct fuse_io_priv io = { .async = 0, .file = file };
|
||||
struct iovec iov = { .iov_base = buf, .iov_len = count };
|
||||
struct iov_iter ii;
|
||||
iov_iter_init(&ii, READ, &iov, 1, count);
|
||||
return __fuse_direct_read(&io, &ii, ppos);
|
||||
struct fuse_io_priv io = { .async = 0, .file = iocb->ki_filp };
|
||||
return __fuse_direct_read(&io, to, &iocb->ki_pos);
|
||||
}
|
||||
|
||||
static ssize_t __fuse_direct_write(struct fuse_io_priv *io,
|
||||
struct iov_iter *iter,
|
||||
loff_t *ppos)
|
||||
static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct file *file = io->file;
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
size_t count = iov_iter_count(iter);
|
||||
ssize_t res;
|
||||
|
||||
|
||||
res = generic_write_checks(file, ppos, &count, 0);
|
||||
if (!res) {
|
||||
iov_iter_truncate(iter, count);
|
||||
res = fuse_direct_io(io, iter, ppos, FUSE_DIO_WRITE);
|
||||
}
|
||||
|
||||
fuse_invalidate_attr(inode);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count };
|
||||
struct inode *inode = file_inode(file);
|
||||
ssize_t res;
|
||||
struct fuse_io_priv io = { .async = 0, .file = file };
|
||||
struct iov_iter ii;
|
||||
iov_iter_init(&ii, WRITE, &iov, 1, count);
|
||||
size_t count = iov_iter_count(from);
|
||||
ssize_t res;
|
||||
|
||||
if (is_bad_inode(inode))
|
||||
return -EIO;
|
||||
|
||||
/* Don't allow parallel writes to the same file */
|
||||
mutex_lock(&inode->i_mutex);
|
||||
res = __fuse_direct_write(&io, &ii, ppos);
|
||||
res = generic_write_checks(file, &iocb->ki_pos, &count, 0);
|
||||
if (!res) {
|
||||
iov_iter_truncate(from, count);
|
||||
res = fuse_direct_io(&io, from, &iocb->ki_pos, FUSE_DIO_WRITE);
|
||||
}
|
||||
fuse_invalidate_attr(inode);
|
||||
if (res > 0)
|
||||
fuse_write_update_size(inode, *ppos);
|
||||
fuse_write_update_size(inode, iocb->ki_pos);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
return res;
|
||||
|
@ -2862,10 +2840,17 @@ fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter,
|
|||
if (io->async && is_sync_kiocb(iocb))
|
||||
io->done = &wait;
|
||||
|
||||
if (rw == WRITE)
|
||||
ret = __fuse_direct_write(io, iter, &pos);
|
||||
else
|
||||
if (rw == WRITE) {
|
||||
ret = generic_write_checks(file, &pos, &count, 0);
|
||||
if (!ret) {
|
||||
iov_iter_truncate(iter, count);
|
||||
ret = fuse_direct_io(io, iter, &pos, FUSE_DIO_WRITE);
|
||||
}
|
||||
|
||||
fuse_invalidate_attr(inode);
|
||||
} else {
|
||||
ret = __fuse_direct_read(io, iter, &pos);
|
||||
}
|
||||
|
||||
if (io->async) {
|
||||
fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
|
||||
|
@ -2968,9 +2953,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
|
|||
|
||||
static const struct file_operations fuse_file_operations = {
|
||||
.llseek = fuse_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = fuse_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = fuse_file_write_iter,
|
||||
.mmap = fuse_file_mmap,
|
||||
.open = fuse_open,
|
||||
|
@ -2988,8 +2971,8 @@ static const struct file_operations fuse_file_operations = {
|
|||
|
||||
static const struct file_operations fuse_direct_io_file_operations = {
|
||||
.llseek = fuse_file_llseek,
|
||||
.read = fuse_direct_read,
|
||||
.write = fuse_direct_write,
|
||||
.read_iter = fuse_direct_read_iter,
|
||||
.write_iter = fuse_direct_write_iter,
|
||||
.mmap = fuse_direct_mmap,
|
||||
.open = fuse_open,
|
||||
.flush = fuse_flush,
|
||||
|
|
|
@ -1105,9 +1105,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
|
|||
|
||||
const struct file_operations gfs2_file_fops = {
|
||||
.llseek = gfs2_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = gfs2_file_write_iter,
|
||||
.unlocked_ioctl = gfs2_ioctl,
|
||||
.mmap = gfs2_mmap,
|
||||
|
@ -1137,9 +1135,7 @@ const struct file_operations gfs2_dir_fops = {
|
|||
|
||||
const struct file_operations gfs2_file_fops_nolock = {
|
||||
.llseek = gfs2_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = gfs2_file_write_iter,
|
||||
.unlocked_ioctl = gfs2_ioctl,
|
||||
.mmap = gfs2_mmap,
|
||||
|
|
|
@ -674,9 +674,7 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end,
|
|||
|
||||
static const struct file_operations hfs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
|
|
|
@ -341,9 +341,7 @@ static const struct inode_operations hfsplus_file_inode_operations = {
|
|||
|
||||
static const struct file_operations hfsplus_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
|
|
|
@ -378,11 +378,9 @@ static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
|
|||
|
||||
static const struct file_operations hostfs_file_fops = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.write = new_sync_write,
|
||||
.mmap = generic_file_mmap,
|
||||
.open = hostfs_file_open,
|
||||
.release = hostfs_file_release,
|
||||
|
|
|
@ -197,9 +197,7 @@ const struct address_space_operations hpfs_aops = {
|
|||
const struct file_operations hpfs_file_ops =
|
||||
{
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
.release = hpfs_file_release,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/security.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/migrate.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
@ -179,42 +180,33 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
static size_t
|
||||
hugetlbfs_read_actor(struct page *page, unsigned long offset,
|
||||
char __user *buf, unsigned long count,
|
||||
unsigned long size)
|
||||
struct iov_iter *to, unsigned long size)
|
||||
{
|
||||
char *kaddr;
|
||||
unsigned long left, copied = 0;
|
||||
size_t copied = 0;
|
||||
int i, chunksize;
|
||||
|
||||
if (size > count)
|
||||
size = count;
|
||||
|
||||
/* Find which 4k chunk and offset with in that chunk */
|
||||
i = offset >> PAGE_CACHE_SHIFT;
|
||||
offset = offset & ~PAGE_CACHE_MASK;
|
||||
|
||||
while (size) {
|
||||
size_t n;
|
||||
chunksize = PAGE_CACHE_SIZE;
|
||||
if (offset)
|
||||
chunksize -= offset;
|
||||
if (chunksize > size)
|
||||
chunksize = size;
|
||||
kaddr = kmap(&page[i]);
|
||||
left = __copy_to_user(buf, kaddr + offset, chunksize);
|
||||
kunmap(&page[i]);
|
||||
if (left) {
|
||||
copied += (chunksize - left);
|
||||
break;
|
||||
}
|
||||
n = copy_page_to_iter(&page[i], offset, chunksize, to);
|
||||
copied += n;
|
||||
if (n != chunksize)
|
||||
return copied;
|
||||
offset = 0;
|
||||
size -= chunksize;
|
||||
buf += chunksize;
|
||||
copied += chunksize;
|
||||
i++;
|
||||
}
|
||||
return copied ? copied : -EFAULT;
|
||||
return copied;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -222,39 +214,34 @@ hugetlbfs_read_actor(struct page *page, unsigned long offset,
|
|||
* data. Its *very* similar to do_generic_mapping_read(), we can't use that
|
||||
* since it has PAGE_CACHE_SIZE assumptions.
|
||||
*/
|
||||
static ssize_t hugetlbfs_read(struct file *filp, char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
static ssize_t hugetlbfs_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct hstate *h = hstate_file(filp);
|
||||
struct address_space *mapping = filp->f_mapping;
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct hstate *h = hstate_file(file);
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
struct inode *inode = mapping->host;
|
||||
unsigned long index = *ppos >> huge_page_shift(h);
|
||||
unsigned long offset = *ppos & ~huge_page_mask(h);
|
||||
unsigned long index = iocb->ki_pos >> huge_page_shift(h);
|
||||
unsigned long offset = iocb->ki_pos & ~huge_page_mask(h);
|
||||
unsigned long end_index;
|
||||
loff_t isize;
|
||||
ssize_t retval = 0;
|
||||
|
||||
/* validate length */
|
||||
if (len == 0)
|
||||
goto out;
|
||||
|
||||
for (;;) {
|
||||
while (iov_iter_count(to)) {
|
||||
struct page *page;
|
||||
unsigned long nr, ret;
|
||||
int ra;
|
||||
size_t nr, copied;
|
||||
|
||||
/* nr is the maximum number of bytes to copy from this page */
|
||||
nr = huge_page_size(h);
|
||||
isize = i_size_read(inode);
|
||||
if (!isize)
|
||||
goto out;
|
||||
break;
|
||||
end_index = (isize - 1) >> huge_page_shift(h);
|
||||
if (index >= end_index) {
|
||||
if (index > end_index)
|
||||
goto out;
|
||||
if (index > end_index)
|
||||
break;
|
||||
if (index == end_index) {
|
||||
nr = ((isize - 1) & ~huge_page_mask(h)) + 1;
|
||||
if (nr <= offset)
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
nr = nr - offset;
|
||||
|
||||
|
@ -265,39 +252,27 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf,
|
|||
* We have a HOLE, zero out the user-buffer for the
|
||||
* length of the hole or request.
|
||||
*/
|
||||
ret = len < nr ? len : nr;
|
||||
if (clear_user(buf, ret))
|
||||
ra = -EFAULT;
|
||||
else
|
||||
ra = 0;
|
||||
copied = iov_iter_zero(nr, to);
|
||||
} else {
|
||||
unlock_page(page);
|
||||
|
||||
/*
|
||||
* We have the page, copy it to user space buffer.
|
||||
*/
|
||||
ra = hugetlbfs_read_actor(page, offset, buf, len, nr);
|
||||
ret = ra;
|
||||
copied = hugetlbfs_read_actor(page, offset, to, nr);
|
||||
page_cache_release(page);
|
||||
}
|
||||
if (ra < 0) {
|
||||
if (retval == 0)
|
||||
retval = ra;
|
||||
goto out;
|
||||
offset += copied;
|
||||
retval += copied;
|
||||
if (copied != nr && iov_iter_count(to)) {
|
||||
if (!retval)
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
offset += ret;
|
||||
retval += ret;
|
||||
len -= ret;
|
||||
index += offset >> huge_page_shift(h);
|
||||
offset &= ~huge_page_mask(h);
|
||||
|
||||
/* short read or no more work */
|
||||
if ((ret != nr) || (len == 0))
|
||||
break;
|
||||
}
|
||||
out:
|
||||
*ppos = ((loff_t)index << huge_page_shift(h)) + offset;
|
||||
iocb->ki_pos = ((loff_t)index << huge_page_shift(h)) + offset;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -721,7 +696,7 @@ static void init_once(void *foo)
|
|||
}
|
||||
|
||||
const struct file_operations hugetlbfs_file_operations = {
|
||||
.read = hugetlbfs_read,
|
||||
.read_iter = hugetlbfs_read_iter,
|
||||
.mmap = hugetlbfs_file_mmap,
|
||||
.fsync = noop_fsync,
|
||||
.get_unmapped_area = hugetlb_get_unmapped_area,
|
||||
|
|
|
@ -51,9 +51,7 @@ const struct file_operations jffs2_file_operations =
|
|||
{
|
||||
.llseek = generic_file_llseek,
|
||||
.open = generic_file_open,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.unlocked_ioctl=jffs2_ioctl,
|
||||
.mmap = generic_file_readonly_mmap,
|
||||
|
|
|
@ -151,8 +151,6 @@ const struct inode_operations jfs_file_inode_operations = {
|
|||
const struct file_operations jfs_file_operations = {
|
||||
.open = jfs_open,
|
||||
.llseek = generic_file_llseek,
|
||||
.write = new_sync_write,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
|
|
|
@ -271,8 +271,6 @@ const struct file_operations logfs_reg_fops = {
|
|||
.llseek = generic_file_llseek,
|
||||
.mmap = generic_file_readonly_mmap,
|
||||
.open = generic_file_open,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
};
|
||||
|
||||
const struct address_space_operations logfs_reg_aops = {
|
||||
|
|
|
@ -14,9 +14,7 @@
|
|||
*/
|
||||
const struct file_operations minix_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
.fsync = generic_file_fsync,
|
||||
|
|
|
@ -98,30 +98,24 @@ int ncp_make_open(struct inode *inode, int right)
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
||||
ncp_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
size_t already_read = 0;
|
||||
off_t pos;
|
||||
off_t pos = iocb->ki_pos;
|
||||
size_t bufsize;
|
||||
int error;
|
||||
void* freepage;
|
||||
void *freepage;
|
||||
size_t freelen;
|
||||
|
||||
ncp_dbg(1, "enter %pD2\n", file);
|
||||
|
||||
pos = *ppos;
|
||||
|
||||
if ((ssize_t) count < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!count)
|
||||
if (!iov_iter_count(to))
|
||||
return 0;
|
||||
if (pos > inode->i_sb->s_maxbytes)
|
||||
return 0;
|
||||
if (pos + count > inode->i_sb->s_maxbytes) {
|
||||
count = inode->i_sb->s_maxbytes - pos;
|
||||
}
|
||||
iov_iter_truncate(to, inode->i_sb->s_maxbytes - pos);
|
||||
|
||||
error = ncp_make_open(inode, O_RDONLY);
|
||||
if (error) {
|
||||
|
@ -138,31 +132,29 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
|||
goto outrel;
|
||||
error = 0;
|
||||
/* First read in as much as possible for each bufsize. */
|
||||
while (already_read < count) {
|
||||
while (iov_iter_count(to)) {
|
||||
int read_this_time;
|
||||
size_t to_read = min_t(unsigned int,
|
||||
size_t to_read = min_t(size_t,
|
||||
bufsize - (pos % bufsize),
|
||||
count - already_read);
|
||||
iov_iter_count(to));
|
||||
|
||||
error = ncp_read_bounce(NCP_SERVER(inode),
|
||||
NCP_FINFO(inode)->file_handle,
|
||||
pos, to_read, buf, &read_this_time,
|
||||
pos, to_read, to, &read_this_time,
|
||||
freepage, freelen);
|
||||
if (error) {
|
||||
error = -EIO; /* NW errno -> Linux errno */
|
||||
break;
|
||||
}
|
||||
pos += read_this_time;
|
||||
buf += read_this_time;
|
||||
already_read += read_this_time;
|
||||
|
||||
if (read_this_time != to_read) {
|
||||
if (read_this_time != to_read)
|
||||
break;
|
||||
}
|
||||
}
|
||||
vfree(freepage);
|
||||
|
||||
*ppos = pos;
|
||||
iocb->ki_pos = pos;
|
||||
|
||||
file_accessed(file);
|
||||
|
||||
|
@ -173,42 +165,26 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
|
||||
ncp_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
size_t already_written = 0;
|
||||
off_t pos;
|
||||
loff_t pos = iocb->ki_pos;
|
||||
size_t count = iov_iter_count(from);
|
||||
size_t bufsize;
|
||||
int errno;
|
||||
void* bouncebuffer;
|
||||
void *bouncebuffer;
|
||||
|
||||
ncp_dbg(1, "enter %pD2\n", file);
|
||||
if ((ssize_t) count < 0)
|
||||
return -EINVAL;
|
||||
pos = *ppos;
|
||||
if (file->f_flags & O_APPEND) {
|
||||
pos = i_size_read(inode);
|
||||
}
|
||||
|
||||
if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
|
||||
if (pos >= MAX_NON_LFS) {
|
||||
return -EFBIG;
|
||||
}
|
||||
if (count > MAX_NON_LFS - (u32)pos) {
|
||||
count = MAX_NON_LFS - (u32)pos;
|
||||
}
|
||||
}
|
||||
if (pos >= inode->i_sb->s_maxbytes) {
|
||||
if (count || pos > inode->i_sb->s_maxbytes) {
|
||||
return -EFBIG;
|
||||
}
|
||||
}
|
||||
if (pos + count > inode->i_sb->s_maxbytes) {
|
||||
count = inode->i_sb->s_maxbytes - pos;
|
||||
}
|
||||
errno = generic_write_checks(file, &pos, &count, 0);
|
||||
if (errno)
|
||||
return errno;
|
||||
iov_iter_truncate(from, count);
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
errno = ncp_make_open(inode, O_WRONLY);
|
||||
if (errno) {
|
||||
ncp_dbg(1, "open failed, error=%d\n", errno);
|
||||
|
@ -216,8 +192,6 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
|
|||
}
|
||||
bufsize = NCP_SERVER(inode)->buffer_size;
|
||||
|
||||
already_written = 0;
|
||||
|
||||
errno = file_update_time(file);
|
||||
if (errno)
|
||||
goto outrel;
|
||||
|
@ -227,13 +201,13 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
|
|||
errno = -EIO; /* -ENOMEM */
|
||||
goto outrel;
|
||||
}
|
||||
while (already_written < count) {
|
||||
while (iov_iter_count(from)) {
|
||||
int written_this_time;
|
||||
size_t to_write = min_t(unsigned int,
|
||||
bufsize - (pos % bufsize),
|
||||
count - already_written);
|
||||
size_t to_write = min_t(size_t,
|
||||
bufsize - ((off_t)pos % bufsize),
|
||||
iov_iter_count(from));
|
||||
|
||||
if (copy_from_user(bouncebuffer, buf, to_write)) {
|
||||
if (copy_from_iter(bouncebuffer, to_write, from) != to_write) {
|
||||
errno = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
@ -244,16 +218,14 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
|
|||
break;
|
||||
}
|
||||
pos += written_this_time;
|
||||
buf += written_this_time;
|
||||
already_written += written_this_time;
|
||||
|
||||
if (written_this_time != to_write) {
|
||||
if (written_this_time != to_write)
|
||||
break;
|
||||
}
|
||||
}
|
||||
vfree(bouncebuffer);
|
||||
|
||||
*ppos = pos;
|
||||
iocb->ki_pos = pos;
|
||||
|
||||
if (pos > i_size_read(inode)) {
|
||||
mutex_lock(&inode->i_mutex);
|
||||
|
@ -277,8 +249,8 @@ static int ncp_release(struct inode *inode, struct file *file) {
|
|||
const struct file_operations ncp_file_operations =
|
||||
{
|
||||
.llseek = generic_file_llseek,
|
||||
.read = ncp_file_read,
|
||||
.write = ncp_file_write,
|
||||
.read_iter = ncp_file_read_iter,
|
||||
.write_iter = ncp_file_write_iter,
|
||||
.unlocked_ioctl = ncp_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ncp_compat_ioctl,
|
||||
|
|
|
@ -1001,8 +1001,8 @@ ncp_read_kernel(struct ncp_server *server, const char *file_id,
|
|||
*/
|
||||
int
|
||||
ncp_read_bounce(struct ncp_server *server, const char *file_id,
|
||||
__u32 offset, __u16 to_read, char __user *target, int *bytes_read,
|
||||
void* bounce, __u32 bufsize)
|
||||
__u32 offset, __u16 to_read, struct iov_iter *to,
|
||||
int *bytes_read, void *bounce, __u32 bufsize)
|
||||
{
|
||||
int result;
|
||||
|
||||
|
@ -1025,7 +1025,7 @@ ncp_read_bounce(struct ncp_server *server, const char *file_id,
|
|||
(offset & 1);
|
||||
*bytes_read = len;
|
||||
result = 0;
|
||||
if (copy_to_user(target, source, len))
|
||||
if (copy_to_iter(source, len, to) != len)
|
||||
result = -EFAULT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ static inline int ncp_read_bounce_size(__u32 size) {
|
|||
return sizeof(struct ncp_reply_header) + 2 + 2 + size + 8;
|
||||
};
|
||||
int ncp_read_bounce(struct ncp_server *, const char *, __u32, __u16,
|
||||
char __user *, int *, void* bounce, __u32 bouncelen);
|
||||
struct iov_iter *, int *, void *bounce, __u32 bouncelen);
|
||||
int ncp_read_kernel(struct ncp_server *, const char *, __u32, __u16,
|
||||
char *, int *);
|
||||
int ncp_write_kernel(struct ncp_server *, const char *, __u32, __u16,
|
||||
|
|
|
@ -926,8 +926,6 @@ EXPORT_SYMBOL_GPL(nfs_flock);
|
|||
|
||||
const struct file_operations nfs_file_operations = {
|
||||
.llseek = nfs_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = nfs_file_read,
|
||||
.write_iter = nfs_file_write,
|
||||
.mmap = nfs_file_mmap,
|
||||
|
|
|
@ -170,8 +170,6 @@ const struct file_operations nfs4_file_operations = {
|
|||
#else
|
||||
.llseek = nfs_file_llseek,
|
||||
#endif
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = nfs_file_read,
|
||||
.write_iter = nfs_file_write,
|
||||
.mmap = nfs_file_mmap,
|
||||
|
|
|
@ -143,8 +143,6 @@ static int nilfs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
*/
|
||||
const struct file_operations nilfs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.unlocked_ioctl = nilfs_ioctl,
|
||||
|
|
|
@ -2048,10 +2048,8 @@ static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end,
|
|||
|
||||
const struct file_operations ntfs_file_ops = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
#ifdef NTFS_RW
|
||||
.write = new_sync_write,
|
||||
.write_iter = ntfs_file_write_iter,
|
||||
.fsync = ntfs_file_fsync,
|
||||
#endif /* NTFS_RW */
|
||||
|
|
|
@ -2681,8 +2681,6 @@ const struct inode_operations ocfs2_special_file_iops = {
|
|||
*/
|
||||
const struct file_operations ocfs2_fops = {
|
||||
.llseek = ocfs2_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.mmap = ocfs2_mmap,
|
||||
.fsync = ocfs2_sync_file,
|
||||
.release = ocfs2_file_release,
|
||||
|
@ -2729,8 +2727,6 @@ const struct file_operations ocfs2_dops = {
|
|||
*/
|
||||
const struct file_operations ocfs2_fops_no_plocks = {
|
||||
.llseek = ocfs2_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.mmap = ocfs2_mmap,
|
||||
.fsync = ocfs2_sync_file,
|
||||
.release = ocfs2_file_release,
|
||||
|
|
|
@ -337,8 +337,6 @@ static sector_t omfs_bmap(struct address_space *mapping, sector_t block)
|
|||
|
||||
const struct file_operations omfs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
|
|
|
@ -734,10 +734,10 @@ static int do_dentry_open(struct file *f,
|
|||
if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
||||
i_readcount_inc(inode);
|
||||
if ((f->f_mode & FMODE_READ) &&
|
||||
likely(f->f_op->read || f->f_op->aio_read || f->f_op->read_iter))
|
||||
likely(f->f_op->read || f->f_op->read_iter))
|
||||
f->f_mode |= FMODE_CAN_READ;
|
||||
if ((f->f_mode & FMODE_WRITE) &&
|
||||
likely(f->f_op->write || f->f_op->aio_write || f->f_op->write_iter))
|
||||
likely(f->f_op->write || f->f_op->write_iter))
|
||||
f->f_mode |= FMODE_CAN_WRITE;
|
||||
|
||||
f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
|
||||
|
|
|
@ -946,9 +946,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
|
|||
const struct file_operations pipefifo_fops = {
|
||||
.open = fifo_open,
|
||||
.llseek = no_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = pipe_read,
|
||||
.write = new_sync_write,
|
||||
.write_iter = pipe_write,
|
||||
.poll = pipe_poll,
|
||||
.unlocked_ioctl = pipe_ioctl,
|
||||
|
|
|
@ -31,9 +31,7 @@
|
|||
#include "internal.h"
|
||||
|
||||
const struct file_operations ramfs_file_operations = {
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
.fsync = noop_fsync,
|
||||
|
|
|
@ -44,9 +44,7 @@ const struct file_operations ramfs_file_operations = {
|
|||
.mmap_capabilities = ramfs_mmap_capabilities,
|
||||
.mmap = ramfs_nommu_mmap,
|
||||
.get_unmapped_area = ramfs_nommu_get_unmapped_area,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.fsync = noop_fsync,
|
||||
.splice_read = generic_file_splice_read,
|
||||
|
|
109
fs/read_write.c
109
fs/read_write.c
|
@ -22,13 +22,10 @@
|
|||
#include <asm/unistd.h>
|
||||
|
||||
typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
|
||||
typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *,
|
||||
unsigned long, loff_t);
|
||||
typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *);
|
||||
|
||||
const struct file_operations generic_ro_fops = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.mmap = generic_file_readonly_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
|
@ -411,24 +408,7 @@ int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t
|
|||
return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;
|
||||
}
|
||||
|
||||
ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
|
||||
{
|
||||
struct iovec iov = { .iov_base = buf, .iov_len = len };
|
||||
struct kiocb kiocb;
|
||||
ssize_t ret;
|
||||
|
||||
init_sync_kiocb(&kiocb, filp);
|
||||
kiocb.ki_pos = *ppos;
|
||||
|
||||
ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
|
||||
BUG_ON(ret == -EIOCBQUEUED);
|
||||
*ppos = kiocb.ki_pos;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(do_sync_read);
|
||||
|
||||
ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
|
||||
static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
|
||||
{
|
||||
struct iovec iov = { .iov_base = buf, .iov_len = len };
|
||||
struct kiocb kiocb;
|
||||
|
@ -445,24 +425,17 @@ ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *p
|
|||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(new_sync_read);
|
||||
|
||||
ssize_t __vfs_read(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *pos)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
if (file->f_op->read)
|
||||
ret = file->f_op->read(file, buf, count, pos);
|
||||
else if (file->f_op->aio_read)
|
||||
ret = do_sync_read(file, buf, count, pos);
|
||||
return file->f_op->read(file, buf, count, pos);
|
||||
else if (file->f_op->read_iter)
|
||||
ret = new_sync_read(file, buf, count, pos);
|
||||
return new_sync_read(file, buf, count, pos);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(__vfs_read);
|
||||
|
||||
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
|
@ -491,24 +464,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
|
|||
|
||||
EXPORT_SYMBOL(vfs_read);
|
||||
|
||||
ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
|
||||
{
|
||||
struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
|
||||
struct kiocb kiocb;
|
||||
ssize_t ret;
|
||||
|
||||
init_sync_kiocb(&kiocb, filp);
|
||||
kiocb.ki_pos = *ppos;
|
||||
|
||||
ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
|
||||
BUG_ON(ret == -EIOCBQUEUED);
|
||||
*ppos = kiocb.ki_pos;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(do_sync_write);
|
||||
|
||||
ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
|
||||
static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
|
||||
{
|
||||
struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
|
||||
struct kiocb kiocb;
|
||||
|
@ -525,7 +481,17 @@ ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, lo
|
|||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(new_sync_write);
|
||||
ssize_t __vfs_write(struct file *file, const char __user *p, size_t count,
|
||||
loff_t *pos)
|
||||
{
|
||||
if (file->f_op->write)
|
||||
return file->f_op->write(file, p, count, pos);
|
||||
else if (file->f_op->write_iter)
|
||||
return new_sync_write(file, p, count, pos);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(__vfs_write);
|
||||
|
||||
ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
|
@ -541,12 +507,7 @@ ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t
|
|||
p = (__force const char __user *)buf;
|
||||
if (count > MAX_RW_COUNT)
|
||||
count = MAX_RW_COUNT;
|
||||
if (file->f_op->write)
|
||||
ret = file->f_op->write(file, p, count, pos);
|
||||
else if (file->f_op->aio_write)
|
||||
ret = do_sync_write(file, p, count, pos);
|
||||
else
|
||||
ret = new_sync_write(file, p, count, pos);
|
||||
ret = __vfs_write(file, p, count, pos);
|
||||
set_fs(old_fs);
|
||||
if (ret > 0) {
|
||||
fsnotify_modify(file);
|
||||
|
@ -573,12 +534,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
|
|||
if (ret >= 0) {
|
||||
count = ret;
|
||||
file_start_write(file);
|
||||
if (file->f_op->write)
|
||||
ret = file->f_op->write(file, buf, count, pos);
|
||||
else if (file->f_op->aio_write)
|
||||
ret = do_sync_write(file, buf, count, pos);
|
||||
else
|
||||
ret = new_sync_write(file, buf, count, pos);
|
||||
ret = __vfs_write(file, buf, count, pos);
|
||||
if (ret > 0) {
|
||||
fsnotify_modify(file);
|
||||
add_wchar(current, ret);
|
||||
|
@ -710,21 +666,6 @@ static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t do_sync_readv_writev(struct file *filp, struct iov_iter *iter,
|
||||
loff_t *ppos, iov_fn_t fn)
|
||||
{
|
||||
struct kiocb kiocb;
|
||||
ssize_t ret;
|
||||
|
||||
init_sync_kiocb(&kiocb, filp);
|
||||
kiocb.ki_pos = *ppos;
|
||||
|
||||
ret = fn(&kiocb, iter->iov, iter->nr_segs, kiocb.ki_pos);
|
||||
BUG_ON(ret == -EIOCBQUEUED);
|
||||
*ppos = kiocb.ki_pos;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Do it by hand, with file-ops */
|
||||
static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter,
|
||||
loff_t *ppos, io_fn_t fn)
|
||||
|
@ -839,7 +780,6 @@ static ssize_t do_readv_writev(int type, struct file *file,
|
|||
struct iov_iter iter;
|
||||
ssize_t ret;
|
||||
io_fn_t fn;
|
||||
iov_fn_t fnv;
|
||||
iter_fn_t iter_fn;
|
||||
|
||||
ret = import_iovec(type, uvector, nr_segs,
|
||||
|
@ -854,22 +794,17 @@ static ssize_t do_readv_writev(int type, struct file *file,
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
fnv = NULL;
|
||||
if (type == READ) {
|
||||
fn = file->f_op->read;
|
||||
fnv = file->f_op->aio_read;
|
||||
iter_fn = file->f_op->read_iter;
|
||||
} else {
|
||||
fn = (io_fn_t)file->f_op->write;
|
||||
fnv = file->f_op->aio_write;
|
||||
iter_fn = file->f_op->write_iter;
|
||||
file_start_write(file);
|
||||
}
|
||||
|
||||
if (iter_fn)
|
||||
ret = do_iter_readv_writev(file, &iter, pos, iter_fn);
|
||||
else if (fnv)
|
||||
ret = do_sync_readv_writev(file, &iter, pos, fnv);
|
||||
else
|
||||
ret = do_loop_readv_writev(file, &iter, pos, fn);
|
||||
|
||||
|
@ -1019,7 +954,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
|
|||
struct iov_iter iter;
|
||||
ssize_t ret;
|
||||
io_fn_t fn;
|
||||
iov_fn_t fnv;
|
||||
iter_fn_t iter_fn;
|
||||
|
||||
ret = compat_import_iovec(type, uvector, nr_segs,
|
||||
|
@ -1034,22 +968,17 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
fnv = NULL;
|
||||
if (type == READ) {
|
||||
fn = file->f_op->read;
|
||||
fnv = file->f_op->aio_read;
|
||||
iter_fn = file->f_op->read_iter;
|
||||
} else {
|
||||
fn = (io_fn_t)file->f_op->write;
|
||||
fnv = file->f_op->aio_write;
|
||||
iter_fn = file->f_op->write_iter;
|
||||
file_start_write(file);
|
||||
}
|
||||
|
||||
if (iter_fn)
|
||||
ret = do_iter_readv_writev(file, &iter, pos, iter_fn);
|
||||
else if (fnv)
|
||||
ret = do_sync_readv_writev(file, &iter, pos, fnv);
|
||||
else
|
||||
ret = do_loop_readv_writev(file, &iter, pos, fn);
|
||||
|
||||
|
|
|
@ -243,8 +243,6 @@ int reiserfs_commit_page(struct inode *inode, struct page *page,
|
|||
}
|
||||
|
||||
const struct file_operations reiserfs_file_operations = {
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.unlocked_ioctl = reiserfs_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = reiserfs_compat_ioctl,
|
||||
|
|
|
@ -81,7 +81,6 @@ static unsigned romfs_mmap_capabilities(struct file *file)
|
|||
|
||||
const struct file_operations romfs_ro_fops = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.mmap = romfs_mmap,
|
||||
|
|
|
@ -21,9 +21,7 @@
|
|||
*/
|
||||
const struct file_operations sysv_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
.fsync = generic_file_fsync,
|
||||
|
|
|
@ -1580,8 +1580,6 @@ const struct inode_operations ubifs_symlink_inode_operations = {
|
|||
|
||||
const struct file_operations ubifs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = ubifs_write_iter,
|
||||
.mmap = ubifs_file_mmap,
|
||||
|
|
|
@ -240,12 +240,10 @@ static int udf_release_file(struct inode *inode, struct file *filp)
|
|||
}
|
||||
|
||||
const struct file_operations udf_file_operations = {
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.unlocked_ioctl = udf_ioctl,
|
||||
.open = generic_file_open,
|
||||
.mmap = generic_file_mmap,
|
||||
.write = new_sync_write,
|
||||
.write_iter = udf_file_write_iter,
|
||||
.release = udf_release_file,
|
||||
.fsync = generic_file_fsync,
|
||||
|
|
|
@ -35,9 +35,7 @@
|
|||
|
||||
const struct file_operations ufs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write = new_sync_write,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
.open = generic_file_open,
|
||||
|
|
|
@ -1386,8 +1386,6 @@ xfs_file_llseek(
|
|||
|
||||
const struct file_operations xfs_file_operations = {
|
||||
.llseek = xfs_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = xfs_file_read_iter,
|
||||
.write_iter = xfs_file_write_iter,
|
||||
.splice_read = xfs_file_splice_read,
|
||||
|
|
|
@ -1562,8 +1562,6 @@ struct file_operations {
|
|||
loff_t (*llseek) (struct file *, loff_t, int);
|
||||
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
|
||||
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
|
||||
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
|
||||
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
|
||||
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
|
||||
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
|
||||
int (*iterate) (struct file *, struct dir_context *);
|
||||
|
@ -1639,6 +1637,7 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
|
|||
struct iovec **ret_pointer);
|
||||
|
||||
extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *);
|
||||
extern ssize_t __vfs_write(struct file *, const char __user *, size_t, loff_t *);
|
||||
extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
|
||||
extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
|
||||
extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
|
||||
|
@ -2573,10 +2572,6 @@ extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *);
|
|||
extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *);
|
||||
extern ssize_t generic_file_direct_write(struct kiocb *, struct iov_iter *, loff_t);
|
||||
extern ssize_t generic_perform_write(struct file *, struct iov_iter *, loff_t);
|
||||
extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
|
||||
extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
|
||||
extern ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
|
||||
extern ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
|
||||
|
||||
ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos);
|
||||
ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos);
|
||||
|
|
|
@ -211,6 +211,8 @@ struct p9_dirent {
|
|||
char d_name[256];
|
||||
};
|
||||
|
||||
struct iov_iter;
|
||||
|
||||
int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb);
|
||||
int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid,
|
||||
const char *name);
|
||||
|
@ -236,10 +238,8 @@ int p9_client_clunk(struct p9_fid *fid);
|
|||
int p9_client_fsync(struct p9_fid *fid, int datasync);
|
||||
int p9_client_remove(struct p9_fid *fid);
|
||||
int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags);
|
||||
int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
|
||||
u64 offset, u32 count);
|
||||
int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
|
||||
u64 offset, u32 count);
|
||||
int p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err);
|
||||
int p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err);
|
||||
int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset);
|
||||
int p9dirent_read(struct p9_client *clnt, char *buf, int len,
|
||||
struct p9_dirent *dirent);
|
||||
|
|
|
@ -61,7 +61,7 @@ struct p9_trans_module {
|
|||
int (*cancel) (struct p9_client *, struct p9_req_t *req);
|
||||
int (*cancelled)(struct p9_client *, struct p9_req_t *req);
|
||||
int (*zc_request)(struct p9_client *, struct p9_req_t *,
|
||||
char *, char *, int , int, int, int);
|
||||
struct iov_iter *, struct iov_iter *, int , int, int);
|
||||
};
|
||||
|
||||
void v9fs_register_trans(struct p9_trans_module *m);
|
||||
|
|
|
@ -213,7 +213,7 @@ static int acct_on(struct filename *pathname)
|
|||
return -EACCES;
|
||||
}
|
||||
|
||||
if (!file->f_op->write) {
|
||||
if (!(file->f_mode & FMODE_CAN_WRITE)) {
|
||||
kfree(acct);
|
||||
filp_close(file, NULL);
|
||||
return -EIO;
|
||||
|
|
|
@ -1016,7 +1016,7 @@ static int validate_mmap_request(struct file *file,
|
|||
* device */
|
||||
if (!file->f_op->get_unmapped_area)
|
||||
capabilities &= ~NOMMU_MAP_DIRECT;
|
||||
if (!file->f_op->read)
|
||||
if (!(file->f_mode & FMODE_CAN_READ))
|
||||
capabilities &= ~NOMMU_MAP_COPY;
|
||||
|
||||
/* The file shall have been opened with read permission. */
|
||||
|
@ -1240,7 +1240,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
|
|||
|
||||
old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
ret = vma->vm_file->f_op->read(vma->vm_file, base, len, &fpos);
|
||||
ret = __vfs_read(vma->vm_file, base, len, &fpos);
|
||||
set_fs(old_fs);
|
||||
|
||||
if (ret < 0)
|
||||
|
|
|
@ -3118,8 +3118,6 @@ static const struct file_operations shmem_file_operations = {
|
|||
.mmap = shmem_mmap,
|
||||
#ifdef CONFIG_TMPFS
|
||||
.llseek = shmem_file_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = shmem_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.fsync = noop_fsync,
|
||||
|
|
260
net/9p/client.c
260
net/9p/client.c
|
@ -34,6 +34,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/uio.h>
|
||||
#include <net/9p/9p.h>
|
||||
#include <linux/parser.h>
|
||||
#include <net/9p/client.h>
|
||||
|
@ -555,7 +556,7 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
|
|||
*/
|
||||
|
||||
static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
|
||||
char *uidata, int in_hdrlen, int kern_buf)
|
||||
struct iov_iter *uidata, int in_hdrlen)
|
||||
{
|
||||
int err;
|
||||
int ecode;
|
||||
|
@ -591,16 +592,11 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
|
|||
ename = &req->rc->sdata[req->rc->offset];
|
||||
if (len > inline_len) {
|
||||
/* We have error in external buffer */
|
||||
if (kern_buf) {
|
||||
memcpy(ename + inline_len, uidata,
|
||||
len - inline_len);
|
||||
} else {
|
||||
err = copy_from_user(ename + inline_len,
|
||||
uidata, len - inline_len);
|
||||
if (err) {
|
||||
err = -EFAULT;
|
||||
goto out_err;
|
||||
}
|
||||
err = copy_from_iter(ename + inline_len,
|
||||
len - inline_len, uidata);
|
||||
if (err != len - inline_len) {
|
||||
err = -EFAULT;
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
ename = NULL;
|
||||
|
@ -806,8 +802,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
|
|||
* p9_client_zc_rpc - issue a request and wait for a response
|
||||
* @c: client session
|
||||
* @type: type of request
|
||||
* @uidata: user bffer that should be ued for zero copy read
|
||||
* @uodata: user buffer that shoud be user for zero copy write
|
||||
* @uidata: destination for zero copy read
|
||||
* @uodata: source for zero copy write
|
||||
* @inlen: read buffer size
|
||||
* @olen: write buffer size
|
||||
* @hdrlen: reader header size, This is the size of response protocol data
|
||||
|
@ -816,9 +812,10 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
|
|||
* Returns request structure (which client must free using p9_free_req)
|
||||
*/
|
||||
static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
|
||||
char *uidata, char *uodata,
|
||||
struct iov_iter *uidata,
|
||||
struct iov_iter *uodata,
|
||||
int inlen, int olen, int in_hdrlen,
|
||||
int kern_buf, const char *fmt, ...)
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int sigpending, err;
|
||||
|
@ -841,12 +838,8 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
|
|||
} else
|
||||
sigpending = 0;
|
||||
|
||||
/* If we are called with KERNEL_DS force kern_buf */
|
||||
if (segment_eq(get_fs(), KERNEL_DS))
|
||||
kern_buf = 1;
|
||||
|
||||
err = c->trans_mod->zc_request(c, req, uidata, uodata,
|
||||
inlen, olen, in_hdrlen, kern_buf);
|
||||
inlen, olen, in_hdrlen);
|
||||
if (err < 0) {
|
||||
if (err == -EIO)
|
||||
c->status = Disconnected;
|
||||
|
@ -876,7 +869,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
|
|||
if (err < 0)
|
||||
goto reterr;
|
||||
|
||||
err = p9_check_zc_errors(c, req, uidata, in_hdrlen, kern_buf);
|
||||
err = p9_check_zc_errors(c, req, uidata, in_hdrlen);
|
||||
trace_9p_client_res(c, type, req->rc->tag, err);
|
||||
if (!err)
|
||||
return req;
|
||||
|
@ -1123,6 +1116,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
|
|||
fid = NULL;
|
||||
goto error;
|
||||
}
|
||||
fid->uid = n_uname;
|
||||
|
||||
req = p9_client_rpc(clnt, P9_TATTACH, "ddss?u", fid->fid,
|
||||
afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
|
||||
|
@ -1541,142 +1535,128 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
|
|||
EXPORT_SYMBOL(p9_client_unlinkat);
|
||||
|
||||
int
|
||||
p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
|
||||
u32 count)
|
||||
p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
|
||||
{
|
||||
char *dataptr;
|
||||
int kernel_buf = 0;
|
||||
struct p9_client *clnt = fid->clnt;
|
||||
struct p9_req_t *req;
|
||||
struct p9_client *clnt;
|
||||
int err, rsize, non_zc = 0;
|
||||
|
||||
int total = 0;
|
||||
|
||||
p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n",
|
||||
fid->fid, (unsigned long long) offset, count);
|
||||
err = 0;
|
||||
clnt = fid->clnt;
|
||||
fid->fid, (unsigned long long) offset, (int)iov_iter_count(to));
|
||||
|
||||
rsize = fid->iounit;
|
||||
if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
|
||||
rsize = clnt->msize - P9_IOHDRSZ;
|
||||
while (iov_iter_count(to)) {
|
||||
int count = iov_iter_count(to);
|
||||
int rsize, non_zc = 0;
|
||||
char *dataptr;
|
||||
|
||||
rsize = fid->iounit;
|
||||
if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
|
||||
rsize = clnt->msize - P9_IOHDRSZ;
|
||||
|
||||
if (count < rsize)
|
||||
rsize = count;
|
||||
if (count < rsize)
|
||||
rsize = count;
|
||||
|
||||
/* Don't bother zerocopy for small IO (< 1024) */
|
||||
if (clnt->trans_mod->zc_request && rsize > 1024) {
|
||||
char *indata;
|
||||
if (data) {
|
||||
kernel_buf = 1;
|
||||
indata = data;
|
||||
} else
|
||||
indata = (__force char *)udata;
|
||||
/*
|
||||
* response header len is 11
|
||||
* PDU Header(7) + IO Size (4)
|
||||
*/
|
||||
req = p9_client_zc_rpc(clnt, P9_TREAD, indata, NULL, rsize, 0,
|
||||
11, kernel_buf, "dqd", fid->fid,
|
||||
offset, rsize);
|
||||
} else {
|
||||
non_zc = 1;
|
||||
req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset,
|
||||
rsize);
|
||||
}
|
||||
if (IS_ERR(req)) {
|
||||
err = PTR_ERR(req);
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
|
||||
if (err) {
|
||||
trace_9p_protocol_dump(clnt, req->rc);
|
||||
goto free_and_error;
|
||||
}
|
||||
|
||||
p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
|
||||
|
||||
if (non_zc) {
|
||||
if (data) {
|
||||
memmove(data, dataptr, count);
|
||||
/* Don't bother zerocopy for small IO (< 1024) */
|
||||
if (clnt->trans_mod->zc_request && rsize > 1024) {
|
||||
/*
|
||||
* response header len is 11
|
||||
* PDU Header(7) + IO Size (4)
|
||||
*/
|
||||
req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize,
|
||||
0, 11, "dqd", fid->fid,
|
||||
offset, rsize);
|
||||
} else {
|
||||
err = copy_to_user(udata, dataptr, count);
|
||||
if (err) {
|
||||
err = -EFAULT;
|
||||
goto free_and_error;
|
||||
}
|
||||
non_zc = 1;
|
||||
req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset,
|
||||
rsize);
|
||||
}
|
||||
if (IS_ERR(req)) {
|
||||
*err = PTR_ERR(req);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p9_free_req(clnt, req);
|
||||
return count;
|
||||
|
||||
free_and_error:
|
||||
p9_free_req(clnt, req);
|
||||
error:
|
||||
return err;
|
||||
*err = p9pdu_readf(req->rc, clnt->proto_version,
|
||||
"D", &count, &dataptr);
|
||||
if (*err) {
|
||||
trace_9p_protocol_dump(clnt, req->rc);
|
||||
p9_free_req(clnt, req);
|
||||
break;
|
||||
}
|
||||
|
||||
p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
|
||||
if (!count) {
|
||||
p9_free_req(clnt, req);
|
||||
break;
|
||||
}
|
||||
|
||||
if (non_zc) {
|
||||
int n = copy_to_iter(dataptr, count, to);
|
||||
total += n;
|
||||
offset += n;
|
||||
if (n != count) {
|
||||
*err = -EFAULT;
|
||||
p9_free_req(clnt, req);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
iov_iter_advance(to, count);
|
||||
total += count;
|
||||
offset += count;
|
||||
}
|
||||
p9_free_req(clnt, req);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
EXPORT_SYMBOL(p9_client_read);
|
||||
|
||||
int
|
||||
p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
|
||||
u64 offset, u32 count)
|
||||
p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
|
||||
{
|
||||
int err, rsize;
|
||||
int kernel_buf = 0;
|
||||
struct p9_client *clnt;
|
||||
struct p9_client *clnt = fid->clnt;
|
||||
struct p9_req_t *req;
|
||||
int total = 0;
|
||||
|
||||
p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n",
|
||||
fid->fid, (unsigned long long) offset, count);
|
||||
err = 0;
|
||||
clnt = fid->clnt;
|
||||
p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %zd\n",
|
||||
fid->fid, (unsigned long long) offset,
|
||||
iov_iter_count(from));
|
||||
|
||||
rsize = fid->iounit;
|
||||
if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
|
||||
rsize = clnt->msize - P9_IOHDRSZ;
|
||||
while (iov_iter_count(from)) {
|
||||
int count = iov_iter_count(from);
|
||||
int rsize = fid->iounit;
|
||||
if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
|
||||
rsize = clnt->msize - P9_IOHDRSZ;
|
||||
|
||||
if (count < rsize)
|
||||
rsize = count;
|
||||
if (count < rsize)
|
||||
rsize = count;
|
||||
|
||||
/* Don't bother zerocopy for small IO (< 1024) */
|
||||
if (clnt->trans_mod->zc_request && rsize > 1024) {
|
||||
char *odata;
|
||||
if (data) {
|
||||
kernel_buf = 1;
|
||||
odata = data;
|
||||
} else
|
||||
odata = (char *)udata;
|
||||
req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, odata, 0, rsize,
|
||||
P9_ZC_HDR_SZ, kernel_buf, "dqd",
|
||||
fid->fid, offset, rsize);
|
||||
} else {
|
||||
if (data)
|
||||
req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid,
|
||||
offset, rsize, data);
|
||||
else
|
||||
req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid,
|
||||
offset, rsize, udata);
|
||||
/* Don't bother zerocopy for small IO (< 1024) */
|
||||
if (clnt->trans_mod->zc_request && rsize > 1024) {
|
||||
req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, from, 0,
|
||||
rsize, P9_ZC_HDR_SZ, "dqd",
|
||||
fid->fid, offset, rsize);
|
||||
} else {
|
||||
req = p9_client_rpc(clnt, P9_TWRITE, "dqV", fid->fid,
|
||||
offset, rsize, from);
|
||||
}
|
||||
if (IS_ERR(req)) {
|
||||
*err = PTR_ERR(req);
|
||||
break;
|
||||
}
|
||||
|
||||
*err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
|
||||
if (*err) {
|
||||
trace_9p_protocol_dump(clnt, req->rc);
|
||||
p9_free_req(clnt, req);
|
||||
}
|
||||
|
||||
p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
|
||||
|
||||
p9_free_req(clnt, req);
|
||||
iov_iter_advance(from, count);
|
||||
total += count;
|
||||
offset += count;
|
||||
}
|
||||
if (IS_ERR(req)) {
|
||||
err = PTR_ERR(req);
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
|
||||
if (err) {
|
||||
trace_9p_protocol_dump(clnt, req->rc);
|
||||
goto free_and_error;
|
||||
}
|
||||
|
||||
p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
|
||||
|
||||
p9_free_req(clnt, req);
|
||||
return count;
|
||||
|
||||
free_and_error:
|
||||
p9_free_req(clnt, req);
|
||||
error:
|
||||
return err;
|
||||
return total;
|
||||
}
|
||||
EXPORT_SYMBOL(p9_client_write);
|
||||
|
||||
|
@ -2068,6 +2048,10 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
|
|||
struct p9_client *clnt;
|
||||
struct p9_req_t *req;
|
||||
char *dataptr;
|
||||
struct kvec kv = {.iov_base = data, .iov_len = count};
|
||||
struct iov_iter to;
|
||||
|
||||
iov_iter_kvec(&to, READ | ITER_KVEC, &kv, 1, count);
|
||||
|
||||
p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
|
||||
fid->fid, (unsigned long long) offset, count);
|
||||
|
@ -2088,8 +2072,8 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
|
|||
* response header len is 11
|
||||
* PDU Header(7) + IO Size (4)
|
||||
*/
|
||||
req = p9_client_zc_rpc(clnt, P9_TREADDIR, data, NULL, rsize, 0,
|
||||
11, 1, "dqd", fid->fid, offset, rsize);
|
||||
req = p9_client_zc_rpc(clnt, P9_TREADDIR, &to, NULL, rsize, 0,
|
||||
11, "dqd", fid->fid, offset, rsize);
|
||||
} else {
|
||||
non_zc = 1;
|
||||
req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid,
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uio.h>
|
||||
#include <net/9p/9p.h>
|
||||
#include <net/9p/client.h>
|
||||
#include "protocol.h"
|
||||
|
@ -69,10 +70,11 @@ static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
|
|||
}
|
||||
|
||||
static size_t
|
||||
pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
|
||||
pdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size)
|
||||
{
|
||||
size_t len = min(pdu->capacity - pdu->size, size);
|
||||
if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
|
||||
struct iov_iter i = *from;
|
||||
if (copy_from_iter(&pdu->sdata[pdu->size], len, &i) != len)
|
||||
len = 0;
|
||||
|
||||
pdu->size += len;
|
||||
|
@ -437,23 +439,13 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
|
|||
stbuf->extension, stbuf->n_uid,
|
||||
stbuf->n_gid, stbuf->n_muid);
|
||||
} break;
|
||||
case 'D':{
|
||||
uint32_t count = va_arg(ap, uint32_t);
|
||||
const void *data = va_arg(ap, const void *);
|
||||
|
||||
errcode = p9pdu_writef(pdu, proto_version, "d",
|
||||
count);
|
||||
if (!errcode && pdu_write(pdu, data, count))
|
||||
errcode = -EFAULT;
|
||||
}
|
||||
break;
|
||||
case 'U':{
|
||||
case 'V':{
|
||||
int32_t count = va_arg(ap, int32_t);
|
||||
const char __user *udata =
|
||||
va_arg(ap, const void __user *);
|
||||
struct iov_iter *from =
|
||||
va_arg(ap, struct iov_iter *);
|
||||
errcode = p9pdu_writef(pdu, proto_version, "d",
|
||||
count);
|
||||
if (!errcode && pdu_write_u(pdu, udata, count))
|
||||
if (!errcode && pdu_write_u(pdu, from, count))
|
||||
errcode = -EFAULT;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -12,12 +12,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/9p/9p.h>
|
||||
#include <net/9p/client.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include "trans_common.h"
|
||||
|
||||
/**
|
||||
* p9_release_req_pages - Release pages after the transaction.
|
||||
|
@ -31,39 +27,3 @@ void p9_release_pages(struct page **pages, int nr_pages)
|
|||
put_page(pages[i]);
|
||||
}
|
||||
EXPORT_SYMBOL(p9_release_pages);
|
||||
|
||||
/**
|
||||
* p9_nr_pages - Return number of pages needed to accommodate the payload.
|
||||
*/
|
||||
int p9_nr_pages(char *data, int len)
|
||||
{
|
||||
unsigned long start_page, end_page;
|
||||
start_page = (unsigned long)data >> PAGE_SHIFT;
|
||||
end_page = ((unsigned long)data + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
return end_page - start_page;
|
||||
}
|
||||
EXPORT_SYMBOL(p9_nr_pages);
|
||||
|
||||
/**
|
||||
* payload_gup - Translates user buffer into kernel pages and
|
||||
* pins them either for read/write through get_user_pages_fast().
|
||||
* @req: Request to be sent to server.
|
||||
* @pdata_off: data offset into the first page after translation (gup).
|
||||
* @pdata_len: Total length of the IO. gup may not return requested # of pages.
|
||||
* @nr_pages: number of pages to accommodate the payload
|
||||
* @rw: Indicates if the pages are for read or write.
|
||||
*/
|
||||
|
||||
int p9_payload_gup(char *data, int *nr_pages, struct page **pages, int write)
|
||||
{
|
||||
int nr_mapped_pages;
|
||||
|
||||
nr_mapped_pages = get_user_pages_fast((unsigned long)data,
|
||||
*nr_pages, write, pages);
|
||||
if (nr_mapped_pages <= 0)
|
||||
return nr_mapped_pages;
|
||||
|
||||
*nr_pages = nr_mapped_pages;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(p9_payload_gup);
|
||||
|
|
|
@ -13,5 +13,3 @@
|
|||
*/
|
||||
|
||||
void p9_release_pages(struct page **, int);
|
||||
int p9_payload_gup(char *, int *, struct page **, int);
|
||||
int p9_nr_pages(char *, int);
|
||||
|
|
|
@ -217,15 +217,15 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
|
|||
* @start: which segment of the sg_list to start at
|
||||
* @pdata: a list of pages to add into sg.
|
||||
* @nr_pages: number of pages to pack into the scatter/gather list
|
||||
* @data: data to pack into scatter/gather list
|
||||
* @offs: amount of data in the beginning of first page _not_ to pack
|
||||
* @count: amount of data to pack into the scatter/gather list
|
||||
*/
|
||||
static int
|
||||
pack_sg_list_p(struct scatterlist *sg, int start, int limit,
|
||||
struct page **pdata, int nr_pages, char *data, int count)
|
||||
struct page **pdata, int nr_pages, size_t offs, int count)
|
||||
{
|
||||
int i = 0, s;
|
||||
int data_off;
|
||||
int data_off = offs;
|
||||
int index = start;
|
||||
|
||||
BUG_ON(nr_pages > (limit - start));
|
||||
|
@ -233,16 +233,14 @@ pack_sg_list_p(struct scatterlist *sg, int start, int limit,
|
|||
* if the first page doesn't start at
|
||||
* page boundary find the offset
|
||||
*/
|
||||
data_off = offset_in_page(data);
|
||||
while (nr_pages) {
|
||||
s = rest_of_page(data);
|
||||
s = PAGE_SIZE - data_off;
|
||||
if (s > count)
|
||||
s = count;
|
||||
/* Make sure we don't terminate early. */
|
||||
sg_unmark_end(&sg[index]);
|
||||
sg_set_page(&sg[index++], pdata[i++], s, data_off);
|
||||
data_off = 0;
|
||||
data += s;
|
||||
count -= s;
|
||||
nr_pages--;
|
||||
}
|
||||
|
@ -314,11 +312,20 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
|
|||
}
|
||||
|
||||
static int p9_get_mapped_pages(struct virtio_chan *chan,
|
||||
struct page **pages, char *data,
|
||||
int nr_pages, int write, int kern_buf)
|
||||
struct page ***pages,
|
||||
struct iov_iter *data,
|
||||
int count,
|
||||
size_t *offs,
|
||||
int *need_drop)
|
||||
{
|
||||
int nr_pages;
|
||||
int err;
|
||||
if (!kern_buf) {
|
||||
|
||||
if (!iov_iter_count(data))
|
||||
return 0;
|
||||
|
||||
if (!(data->type & ITER_KVEC)) {
|
||||
int n;
|
||||
/*
|
||||
* We allow only p9_max_pages pinned. We wait for the
|
||||
* Other zc request to finish here
|
||||
|
@ -329,26 +336,49 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
|
|||
if (err == -ERESTARTSYS)
|
||||
return err;
|
||||
}
|
||||
err = p9_payload_gup(data, &nr_pages, pages, write);
|
||||
if (err < 0)
|
||||
return err;
|
||||
n = iov_iter_get_pages_alloc(data, pages, count, offs);
|
||||
if (n < 0)
|
||||
return n;
|
||||
*need_drop = 1;
|
||||
nr_pages = DIV_ROUND_UP(n + *offs, PAGE_SIZE);
|
||||
atomic_add(nr_pages, &vp_pinned);
|
||||
return n;
|
||||
} else {
|
||||
/* kernel buffer, no need to pin pages */
|
||||
int s, index = 0;
|
||||
int count = nr_pages;
|
||||
while (nr_pages) {
|
||||
s = rest_of_page(data);
|
||||
if (is_vmalloc_addr(data))
|
||||
pages[index++] = vmalloc_to_page(data);
|
||||
else
|
||||
pages[index++] = kmap_to_page(data);
|
||||
data += s;
|
||||
nr_pages--;
|
||||
int index;
|
||||
size_t len;
|
||||
void *p;
|
||||
|
||||
/* we'd already checked that it's non-empty */
|
||||
while (1) {
|
||||
len = iov_iter_single_seg_count(data);
|
||||
if (likely(len)) {
|
||||
p = data->kvec->iov_base + data->iov_offset;
|
||||
break;
|
||||
}
|
||||
iov_iter_advance(data, 0);
|
||||
}
|
||||
nr_pages = count;
|
||||
if (len > count)
|
||||
len = count;
|
||||
|
||||
nr_pages = DIV_ROUND_UP((unsigned long)p + len, PAGE_SIZE) -
|
||||
(unsigned long)p / PAGE_SIZE;
|
||||
|
||||
*pages = kmalloc(sizeof(struct page *) * nr_pages, GFP_NOFS);
|
||||
if (!*pages)
|
||||
return -ENOMEM;
|
||||
|
||||
*need_drop = 0;
|
||||
p -= (*offs = (unsigned long)p % PAGE_SIZE);
|
||||
for (index = 0; index < nr_pages; index++) {
|
||||
if (is_vmalloc_addr(p))
|
||||
(*pages)[index] = vmalloc_to_page(p);
|
||||
else
|
||||
(*pages)[index] = kmap_to_page(p);
|
||||
p += PAGE_SIZE;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
return nr_pages;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -364,8 +394,8 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
|
|||
*/
|
||||
static int
|
||||
p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
|
||||
char *uidata, char *uodata, int inlen,
|
||||
int outlen, int in_hdr_len, int kern_buf)
|
||||
struct iov_iter *uidata, struct iov_iter *uodata,
|
||||
int inlen, int outlen, int in_hdr_len)
|
||||
{
|
||||
int in, out, err, out_sgs, in_sgs;
|
||||
unsigned long flags;
|
||||
|
@ -373,41 +403,32 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
|
|||
struct page **in_pages = NULL, **out_pages = NULL;
|
||||
struct virtio_chan *chan = client->trans;
|
||||
struct scatterlist *sgs[4];
|
||||
size_t offs;
|
||||
int need_drop = 0;
|
||||
|
||||
p9_debug(P9_DEBUG_TRANS, "virtio request\n");
|
||||
|
||||
if (uodata) {
|
||||
out_nr_pages = p9_nr_pages(uodata, outlen);
|
||||
out_pages = kmalloc(sizeof(struct page *) * out_nr_pages,
|
||||
GFP_NOFS);
|
||||
if (!out_pages) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
int n = p9_get_mapped_pages(chan, &out_pages, uodata,
|
||||
outlen, &offs, &need_drop);
|
||||
if (n < 0)
|
||||
return n;
|
||||
out_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE);
|
||||
if (n != outlen) {
|
||||
__le32 v = cpu_to_le32(n);
|
||||
memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4);
|
||||
outlen = n;
|
||||
}
|
||||
out_nr_pages = p9_get_mapped_pages(chan, out_pages, uodata,
|
||||
out_nr_pages, 0, kern_buf);
|
||||
if (out_nr_pages < 0) {
|
||||
err = out_nr_pages;
|
||||
kfree(out_pages);
|
||||
out_pages = NULL;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
if (uidata) {
|
||||
in_nr_pages = p9_nr_pages(uidata, inlen);
|
||||
in_pages = kmalloc(sizeof(struct page *) * in_nr_pages,
|
||||
GFP_NOFS);
|
||||
if (!in_pages) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
in_nr_pages = p9_get_mapped_pages(chan, in_pages, uidata,
|
||||
in_nr_pages, 1, kern_buf);
|
||||
if (in_nr_pages < 0) {
|
||||
err = in_nr_pages;
|
||||
kfree(in_pages);
|
||||
in_pages = NULL;
|
||||
goto err_out;
|
||||
} else if (uidata) {
|
||||
int n = p9_get_mapped_pages(chan, &in_pages, uidata,
|
||||
inlen, &offs, &need_drop);
|
||||
if (n < 0)
|
||||
return n;
|
||||
in_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE);
|
||||
if (n != inlen) {
|
||||
__le32 v = cpu_to_le32(n);
|
||||
memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4);
|
||||
inlen = n;
|
||||
}
|
||||
}
|
||||
req->status = REQ_STATUS_SENT;
|
||||
|
@ -426,7 +447,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
|
|||
if (out_pages) {
|
||||
sgs[out_sgs++] = chan->sg + out;
|
||||
out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM,
|
||||
out_pages, out_nr_pages, uodata, outlen);
|
||||
out_pages, out_nr_pages, offs, outlen);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -444,7 +465,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
|
|||
if (in_pages) {
|
||||
sgs[out_sgs + in_sgs++] = chan->sg + out + in;
|
||||
in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM,
|
||||
in_pages, in_nr_pages, uidata, inlen);
|
||||
in_pages, in_nr_pages, offs, inlen);
|
||||
}
|
||||
|
||||
BUG_ON(out_sgs + in_sgs > ARRAY_SIZE(sgs));
|
||||
|
@ -478,7 +499,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
|
|||
* Non kernel buffers are pinned, unpin them
|
||||
*/
|
||||
err_out:
|
||||
if (!kern_buf) {
|
||||
if (need_drop) {
|
||||
if (in_pages) {
|
||||
p9_release_pages(in_pages, in_nr_pages);
|
||||
atomic_sub(in_nr_pages, &vp_pinned);
|
||||
|
|
|
@ -140,8 +140,6 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
|
|||
static const struct file_operations socket_file_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.read = new_sync_read,
|
||||
.write = new_sync_write,
|
||||
.read_iter = sock_read_iter,
|
||||
.write_iter = sock_write_iter,
|
||||
.poll = sock_poll,
|
||||
|
|
|
@ -3033,9 +3033,7 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
|
|||
return result;
|
||||
}
|
||||
|
||||
static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos)
|
||||
|
||||
static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct snd_pcm_file *pcm_file;
|
||||
struct snd_pcm_substream *substream;
|
||||
|
@ -3052,16 +3050,18 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
|
|||
runtime = substream->runtime;
|
||||
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
|
||||
return -EBADFD;
|
||||
if (nr_segs > 1024 || nr_segs != runtime->channels)
|
||||
if (!iter_is_iovec(to))
|
||||
return -EINVAL;
|
||||
if (!frame_aligned(runtime, iov->iov_len))
|
||||
if (to->nr_segs > 1024 || to->nr_segs != runtime->channels)
|
||||
return -EINVAL;
|
||||
frames = bytes_to_samples(runtime, iov->iov_len);
|
||||
bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
|
||||
if (!frame_aligned(runtime, to->iov->iov_len))
|
||||
return -EINVAL;
|
||||
frames = bytes_to_samples(runtime, to->iov->iov_len);
|
||||
bufs = kmalloc(sizeof(void *) * to->nr_segs, GFP_KERNEL);
|
||||
if (bufs == NULL)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < nr_segs; ++i)
|
||||
bufs[i] = iov[i].iov_base;
|
||||
for (i = 0; i < to->nr_segs; ++i)
|
||||
bufs[i] = to->iov[i].iov_base;
|
||||
result = snd_pcm_lib_readv(substream, bufs, frames);
|
||||
if (result > 0)
|
||||
result = frames_to_bytes(runtime, result);
|
||||
|
@ -3069,8 +3069,7 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
|
|||
return result;
|
||||
}
|
||||
|
||||
static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos)
|
||||
static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct snd_pcm_file *pcm_file;
|
||||
struct snd_pcm_substream *substream;
|
||||
|
@ -3087,15 +3086,17 @@ static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
|||
runtime = substream->runtime;
|
||||
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
|
||||
return -EBADFD;
|
||||
if (nr_segs > 128 || nr_segs != runtime->channels ||
|
||||
!frame_aligned(runtime, iov->iov_len))
|
||||
if (!iter_is_iovec(from))
|
||||
return -EINVAL;
|
||||
frames = bytes_to_samples(runtime, iov->iov_len);
|
||||
bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
|
||||
if (from->nr_segs > 128 || from->nr_segs != runtime->channels ||
|
||||
!frame_aligned(runtime, from->iov->iov_len))
|
||||
return -EINVAL;
|
||||
frames = bytes_to_samples(runtime, from->iov->iov_len);
|
||||
bufs = kmalloc(sizeof(void *) * from->nr_segs, GFP_KERNEL);
|
||||
if (bufs == NULL)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < nr_segs; ++i)
|
||||
bufs[i] = iov[i].iov_base;
|
||||
for (i = 0; i < from->nr_segs; ++i)
|
||||
bufs[i] = from->iov[i].iov_base;
|
||||
result = snd_pcm_lib_writev(substream, bufs, frames);
|
||||
if (result > 0)
|
||||
result = frames_to_bytes(runtime, result);
|
||||
|
@ -3633,7 +3634,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
|
|||
{
|
||||
.owner = THIS_MODULE,
|
||||
.write = snd_pcm_write,
|
||||
.aio_write = snd_pcm_aio_write,
|
||||
.write_iter = snd_pcm_writev,
|
||||
.open = snd_pcm_playback_open,
|
||||
.release = snd_pcm_release,
|
||||
.llseek = no_llseek,
|
||||
|
@ -3647,7 +3648,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
|
|||
{
|
||||
.owner = THIS_MODULE,
|
||||
.read = snd_pcm_read,
|
||||
.aio_read = snd_pcm_aio_read,
|
||||
.read_iter = snd_pcm_readv,
|
||||
.open = snd_pcm_capture_open,
|
||||
.release = snd_pcm_release,
|
||||
.llseek = no_llseek,
|
||||
|
|
Loading…
Reference in New Issue
Block a user