diff options
Diffstat (limited to 'fs/9p/vfs_file.c')
-rw-r--r-- | fs/9p/vfs_file.c | 326 |
1 files changed, 58 insertions, 268 deletions
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index b40133796b87..1ef16bd8280b 100644 --- a/fs/9p/vfs_file.c +++ b/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> @@ -149,7 +151,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) { struct p9_flock flock; struct p9_fid *fid; - uint8_t status; + uint8_t status = P9_LOCK_ERROR; int res = 0; unsigned char fl_type; @@ -194,7 +196,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) for (;;) { res = p9_client_lock_dotl(fid, &flock, &status); if (res < 0) - break; + goto out_unlock; if (status != P9_LOCK_BLOCKED) break; @@ -212,14 +214,16 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) case P9_LOCK_BLOCKED: res = -EAGAIN; break; + default: + WARN_ONCE(1, "unknown lock status code: %d\n", status); + /* fallthough */ case P9_LOCK_ERROR: case P9_LOCK_GRACE: res = -ENOLCK; break; - default: - BUG(); } +out_unlock: /* * incase server returned error for lock request, revert * it locally @@ -285,6 +289,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; } @@ -364,63 +369,6 @@ out_err: } /** - * 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 * @udata: user data buffer to read data into @@ -430,69 +378,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; - - p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset); - fid = filp->private_data; + struct p9_fid *fid = iocb->ki_filp->private_data; + int ret, err; - 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); + p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", + iov_iter_count(to), iocb->ki_pos); - 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 +403,39 @@ 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) { - ssize_t retval = 0; - loff_t origin = *offset; - - - retval = generic_write_checks(filp, &origin, &count, 0); - if (retval) - goto out; + struct file *file = iocb->ki_filp; + ssize_t retval; + loff_t origin; + int err = 0; - retval = -EINVAL; - if ((ssize_t) count < 0) - goto out; - retval = 0; - if (!count) - goto out; + retval = generic_write_checks(iocb, from); + if (retval <= 0) + return retval; - 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; + origin = iocb->ki_pos; + retval = p9_client_write(file->private_data, iocb->ki_pos, 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); + iocb->ki_pos += retval; + i_size = i_size_read(inode); + if (iocb->ki_pos > i_size) { + inode_add_bytes(inode, iocb->ki_pos - i_size); + i_size_write(inode, iocb->ki_pos); + } + return retval; + } + return err; } - static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) { @@ -657,44 +562,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 +571,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); -} - -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); + return v9fs_file_read_iter(iocb, to); } - /** * v9fs_mmap_file_write - write to a file * @filp: file pointer to write @@ -791,14 +586,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 +637,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 +648,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 +660,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 +671,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 +683,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 +694,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, |