NFS: O_DIRECT needs to use a completion
Now that we have aio writes, it is possible for dreq->outstanding to be zero, but for the I/O not to have completed. Convert struct nfs_direct_req to use a completion to signal when the I/O is done. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
@@ -72,7 +72,6 @@ struct nfs_direct_req {
|
|||||||
rewrite_list; /* saved nfs_write_data structs */
|
rewrite_list; /* saved nfs_write_data structs */
|
||||||
struct nfs_open_context *ctx; /* file open context info */
|
struct nfs_open_context *ctx; /* file open context info */
|
||||||
struct kiocb * iocb; /* controlling i/o request */
|
struct kiocb * iocb; /* controlling i/o request */
|
||||||
wait_queue_head_t wait; /* wait for i/o completion */
|
|
||||||
struct inode * inode; /* target file of i/o */
|
struct inode * inode; /* target file of i/o */
|
||||||
unsigned long user_addr; /* location of user's buffer */
|
unsigned long user_addr; /* location of user's buffer */
|
||||||
size_t user_count; /* total bytes to move */
|
size_t user_count; /* total bytes to move */
|
||||||
@@ -85,6 +84,7 @@ struct nfs_direct_req {
|
|||||||
int outstanding; /* i/os we're waiting for */
|
int outstanding; /* i/os we're waiting for */
|
||||||
ssize_t count, /* bytes actually processed */
|
ssize_t count, /* bytes actually processed */
|
||||||
error; /* any reported error */
|
error; /* any reported error */
|
||||||
|
struct completion completion; /* wait for i/o completion */
|
||||||
|
|
||||||
/* commit state */
|
/* commit state */
|
||||||
struct nfs_write_data * commit_data; /* special write_data for commits */
|
struct nfs_write_data * commit_data; /* special write_data for commits */
|
||||||
@@ -175,7 +175,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
kref_init(&dreq->kref);
|
kref_init(&dreq->kref);
|
||||||
init_waitqueue_head(&dreq->wait);
|
init_completion(&dreq->completion);
|
||||||
INIT_LIST_HEAD(&dreq->list);
|
INIT_LIST_HEAD(&dreq->list);
|
||||||
INIT_LIST_HEAD(&dreq->rewrite_list);
|
INIT_LIST_HEAD(&dreq->rewrite_list);
|
||||||
dreq->iocb = NULL;
|
dreq->iocb = NULL;
|
||||||
@@ -209,7 +209,7 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
|
|||||||
if (dreq->iocb)
|
if (dreq->iocb)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
result = wait_event_interruptible(dreq->wait, (dreq->outstanding == 0));
|
result = wait_for_completion_interruptible(&dreq->completion);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
result = dreq->error;
|
result = dreq->error;
|
||||||
@@ -239,8 +239,8 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
|
|||||||
if (!res)
|
if (!res)
|
||||||
res = (long) dreq->count;
|
res = (long) dreq->count;
|
||||||
aio_complete(dreq->iocb, res, 0);
|
aio_complete(dreq->iocb, res, 0);
|
||||||
} else
|
}
|
||||||
wake_up(&dreq->wait);
|
complete_all(&dreq->completion);
|
||||||
|
|
||||||
kref_put(&dreq->kref, nfs_direct_req_release);
|
kref_put(&dreq->kref, nfs_direct_req_release);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user