Commit c48722c6 authored by Al Viro's avatar Al Viro
Browse files

Merge branch '9p-iov_iter' into for-next

parents 34d0640e dcdbd7b2
......@@ -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);
buffer = kmap(page);
offset = page_offset(page);
bvec.bv_page = page;
bvec.bv_offset = 0;
bvec.bv_len = len;
iov_iter_bvec(&from, ITER_BVEC | WRITE, &bvec, 1, len);
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);
......
......@@ -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 @@ out_err:
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 @@ out_unlock:
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,8 @@ 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 = new_sync_read,
.write = new_sync_write,
.read_iter = generic_file_read_iter,
.write_iter = generic_file_write_iter,
.open = v9fs_file_open,
......@@ -856,8 +654,8 @@ 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 = new_sync_read,
.write = new_sync_write,
.read_iter = generic_file_read_iter,
.write_iter = generic_file_write_iter,
.open = v9fs_file_open,
......@@ -870,8 +668,10 @@ 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 = new_sync_read,
.write = new_sync_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 +681,10 @@ 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 = new_sync_read,
.write = new_sync_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 +695,10 @@ 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 = new_sync_read,
.write = new_sync_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 +708,10 @@ 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 = new_sync_read,
.write = new_sync_write,