summaryrefslogtreecommitdiffstats
path: root/fs/nfs/direct.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-13 16:46:18 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-13 16:46:18 -0700
commit16cefa8c3863721fd40445a1b34dea18cd16ccfe (patch)
treec8e58ca06e2edfd667d3e6062a642b80cc58e5e7 /fs/nfs/direct.c
parent4fbef206daead133085fe33905f5e842d38fb8da (diff)
parentd8558f99fbc5ef5d4ae76b893784005056450f82 (diff)
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (122 commits) sunrpc: drop BKL around wrap and unwrap NFSv4: Make sure unlock is really an unlock when cancelling a lock NLM: fix source address of callback to client SUNRPC client: add interface for binding to a local address SUNRPC server: record the destination address of a request SUNRPC: cleanup transport creation argument passing NFSv4: Make the NFS state model work with the nosharedcache mount option NFS: Error when mounting the same filesystem with different options NFS: Add the mount option "nosharecache" NFS: Add support for mounting NFSv4 file systems with string options NFS: Add final pieces to support in-kernel mount option parsing NFS: Introduce generic mount client API NFS: Add enums and match tables for mount option parsing NFS: Improve debugging output in NFS in-kernel mount client NFS: Clean up in-kernel NFS mount NFS: Remake nfsroot_mount as a permanent part of NFS client SUNRPC: Add a convenient default for the hostname when calling rpc_create() SUNRPC: Rename rpcb_getport to be consistent with new rpcb_getport_sync name SUNRPC: Rename rpcb_getport_external routine SUNRPC: Allow rpcbind requests to be interrupted by a signal. ...
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r--fs/nfs/direct.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 00eee87510f..a5c82b6f3b4 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -266,7 +266,7 @@ static const struct rpc_call_ops nfs_read_direct_ops = {
static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos)
{
struct nfs_open_context *ctx = dreq->ctx;
- struct inode *inode = ctx->dentry->d_inode;
+ struct inode *inode = ctx->path.dentry->d_inode;
size_t rsize = NFS_SERVER(inode)->rsize;
unsigned int pgbase;
int result;
@@ -295,9 +295,14 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
break;
}
if ((unsigned)result < data->npages) {
- nfs_direct_release_pages(data->pagevec, result);
- nfs_readdata_release(data);
- break;
+ bytes = result * PAGE_SIZE;
+ if (bytes <= pgbase) {
+ nfs_direct_release_pages(data->pagevec, result);
+ nfs_readdata_release(data);
+ break;
+ }
+ bytes -= pgbase;
+ data->npages = result;
}
get_dreq(dreq);
@@ -601,7 +606,7 @@ static const struct rpc_call_ops nfs_write_direct_ops = {
static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync)
{
struct nfs_open_context *ctx = dreq->ctx;
- struct inode *inode = ctx->dentry->d_inode;
+ struct inode *inode = ctx->path.dentry->d_inode;
size_t wsize = NFS_SERVER(inode)->wsize;
unsigned int pgbase;
int result;
@@ -630,9 +635,14 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
break;
}
if ((unsigned)result < data->npages) {
- nfs_direct_release_pages(data->pagevec, result);
- nfs_writedata_release(data);
- break;
+ bytes = result * PAGE_SIZE;
+ if (bytes <= pgbase) {
+ nfs_direct_release_pages(data->pagevec, result);
+ nfs_writedata_release(data);
+ break;
+ }
+ bytes -= pgbase;
+ data->npages = result;
}
get_dreq(dreq);
@@ -763,10 +773,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
(unsigned long) count, (long long) pos);
if (nr_segs != 1)
- return -EINVAL;
-
- if (count < 0)
goto out;
+
retval = -EFAULT;
if (!access_ok(VERIFY_WRITE, buf, count))
goto out;
@@ -814,7 +822,7 @@ out:
ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- ssize_t retval;
+ ssize_t retval = -EINVAL;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
/* XXX: temporary */
@@ -827,7 +835,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
(unsigned long) count, (long long) pos);
if (nr_segs != 1)
- return -EINVAL;
+ goto out;
retval = generic_write_checks(file, &pos, &count, 0);
if (retval)