Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 23906
b: refs/heads/master
c: 63ab46a
h: refs/heads/master
v: v3
  • Loading branch information
Chuck Lever authored and Trond Myklebust committed Mar 20, 2006
1 parent dad894d commit b9d8ecc
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 21 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 93619e5989173614bef0013b0bb8a3fe3dbd5a95
refs/heads/master: 63ab46abc70b01cb0711301f5ddb08c1c0bb9b1c
46 changes: 26 additions & 20 deletions trunk/fs/nfs/direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,30 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
return (ssize_t) result;
}

/*
* We must hold a reference to all the pages in this direct read request
* until the RPCs complete. This could be long *after* we are woken up in
* nfs_direct_wait (for instance, if someone hits ^C on a slow server).
*
* In addition, synchronous I/O uses a stack-allocated iocb. Thus we
* can't trust the iocb is still valid here if this is a synchronous
* request. If the waiter is woken prematurely, the iocb is long gone.
*/
static void nfs_direct_complete(struct nfs_direct_req *dreq)
{
nfs_free_user_pages(dreq->pages, dreq->npages, 1);

if (dreq->iocb) {
long res = atomic_read(&dreq->error);
if (!res)
res = atomic_read(&dreq->count);
aio_complete(dreq->iocb, res, 0);
} else
wake_up(&dreq->wait);

kref_put(&dreq->kref, nfs_direct_req_release);
}

/*
* Note we also set the number of requests we have in the dreq when we are
* done. This prevents races with I/O completion so we will always wait
Expand Down Expand Up @@ -245,15 +269,6 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, size_t rsize)
return dreq;
}

/*
* We must hold a reference to all the pages in this direct read request
* until the RPCs complete. This could be long *after* we are woken up in
* nfs_direct_wait (for instance, if someone hits ^C on a slow server).
*
* In addition, synchronous I/O uses a stack-allocated iocb. Thus we
* can't trust the iocb is still valid here if this is a synchronous
* request. If the waiter is woken prematurely, the iocb is long gone.
*/
static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
{
struct nfs_read_data *data = calldata;
Expand All @@ -266,17 +281,8 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
else
atomic_set(&dreq->error, task->tk_status);

if (unlikely(atomic_dec_and_test(&dreq->complete))) {
nfs_free_user_pages(dreq->pages, dreq->npages, 1);
if (dreq->iocb) {
long res = atomic_read(&dreq->error);
if (!res)
res = atomic_read(&dreq->count);
aio_complete(dreq->iocb, res, 0);
} else
wake_up(&dreq->wait);
kref_put(&dreq->kref, nfs_direct_req_release);
}
if (unlikely(atomic_dec_and_test(&dreq->complete)))
nfs_direct_complete(dreq);
}

static const struct rpc_call_ops nfs_read_direct_ops = {
Expand Down

0 comments on commit b9d8ecc

Please sign in to comment.