diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:36 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:36 -0500 |
commit | a8881f5a5c723f82da84b786d3ca83a0df9e0c33 (patch) | |
tree | 50e01d4a0d3b803a5103e427e94a316d7ec92c81 | |
parent | fad61490419b3e494f300e9b2579810ef3bcda31 (diff) |
NFS: O_DIRECT async IO may lose context
The struct nfs_direct_req currently keeps a pointer to the file descriptor
without referencing it. This may cause problems if the parent process is
killed.
The nfs_open_context should normally have all the information that we're
currently using the filp for, and unlike fput(), is safe to release from
an rpciod process context.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/direct.c | 30 |
1 files changed, 12 insertions, 18 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index f0f2053c7a61..e6585b9ff45a 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -71,7 +71,7 @@ struct nfs_direct_req { | |||
71 | /* I/O parameters */ | 71 | /* I/O parameters */ |
72 | struct list_head list, /* nfs_read/write_data structs */ | 72 | struct list_head list, /* nfs_read/write_data structs */ |
73 | rewrite_list; /* saved nfs_write_data structs */ | 73 | rewrite_list; /* saved nfs_write_data structs */ |
74 | struct file * filp; /* file descriptor */ | 74 | struct nfs_open_context *ctx; /* file open context info */ |
75 | struct kiocb * iocb; /* controlling i/o request */ | 75 | struct kiocb * iocb; /* controlling i/o request */ |
76 | wait_queue_head_t wait; /* wait for i/o completion */ | 76 | wait_queue_head_t wait; /* wait for i/o completion */ |
77 | struct inode * inode; /* target file of i/o */ | 77 | struct inode * inode; /* target file of i/o */ |
@@ -176,6 +176,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | |||
176 | INIT_LIST_HEAD(&dreq->list); | 176 | INIT_LIST_HEAD(&dreq->list); |
177 | INIT_LIST_HEAD(&dreq->rewrite_list); | 177 | INIT_LIST_HEAD(&dreq->rewrite_list); |
178 | dreq->iocb = NULL; | 178 | dreq->iocb = NULL; |
179 | dreq->ctx = NULL; | ||
179 | spin_lock_init(&dreq->lock); | 180 | spin_lock_init(&dreq->lock); |
180 | dreq->outstanding = 0; | 181 | dreq->outstanding = 0; |
181 | dreq->count = 0; | 182 | dreq->count = 0; |
@@ -188,6 +189,9 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | |||
188 | static void nfs_direct_req_release(struct kref *kref) | 189 | static void nfs_direct_req_release(struct kref *kref) |
189 | { | 190 | { |
190 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); | 191 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); |
192 | |||
193 | if (dreq->ctx != NULL) | ||
194 | put_nfs_open_context(dreq->ctx); | ||
191 | kmem_cache_free(nfs_direct_cachep, dreq); | 195 | kmem_cache_free(nfs_direct_cachep, dreq); |
192 | } | 196 | } |
193 | 197 | ||
@@ -235,7 +239,6 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq) | |||
235 | } else | 239 | } else |
236 | wake_up(&dreq->wait); | 240 | wake_up(&dreq->wait); |
237 | 241 | ||
238 | iput(dreq->inode); | ||
239 | kref_put(&dreq->kref, nfs_direct_req_release); | 242 | kref_put(&dreq->kref, nfs_direct_req_release); |
240 | } | 243 | } |
241 | 244 | ||
@@ -317,10 +320,8 @@ static const struct rpc_call_ops nfs_read_direct_ops = { | |||
317 | */ | 320 | */ |
318 | static void nfs_direct_read_schedule(struct nfs_direct_req *dreq) | 321 | static void nfs_direct_read_schedule(struct nfs_direct_req *dreq) |
319 | { | 322 | { |
320 | struct file *file = dreq->filp; | 323 | struct nfs_open_context *ctx = dreq->ctx; |
321 | struct inode *inode = file->f_mapping->host; | 324 | struct inode *inode = ctx->dentry->d_inode; |
322 | struct nfs_open_context *ctx = (struct nfs_open_context *) | ||
323 | file->private_data; | ||
324 | struct list_head *list = &dreq->list; | 325 | struct list_head *list = &dreq->list; |
325 | struct page **pages = dreq->pages; | 326 | struct page **pages = dreq->pages; |
326 | size_t count = dreq->user_count; | 327 | size_t count = dreq->user_count; |
@@ -396,9 +397,8 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size | |||
396 | dreq->pos = pos; | 397 | dreq->pos = pos; |
397 | dreq->pages = pages; | 398 | dreq->pages = pages; |
398 | dreq->npages = nr_pages; | 399 | dreq->npages = nr_pages; |
399 | igrab(inode); | ||
400 | dreq->inode = inode; | 400 | dreq->inode = inode; |
401 | dreq->filp = iocb->ki_filp; | 401 | dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data); |
402 | if (!is_sync_kiocb(iocb)) | 402 | if (!is_sync_kiocb(iocb)) |
403 | dreq->iocb = iocb; | 403 | dreq->iocb = iocb; |
404 | 404 | ||
@@ -462,14 +462,11 @@ static const struct rpc_call_ops nfs_commit_direct_ops = { | |||
462 | 462 | ||
463 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | 463 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
464 | { | 464 | { |
465 | struct file *file = dreq->filp; | ||
466 | struct nfs_open_context *ctx = (struct nfs_open_context *) | ||
467 | file->private_data; | ||
468 | struct nfs_write_data *data = dreq->commit_data; | 465 | struct nfs_write_data *data = dreq->commit_data; |
469 | struct rpc_task *task = &data->task; | 466 | struct rpc_task *task = &data->task; |
470 | 467 | ||
471 | data->inode = dreq->inode; | 468 | data->inode = dreq->inode; |
472 | data->cred = ctx->cred; | 469 | data->cred = dreq->ctx->cred; |
473 | 470 | ||
474 | data->args.fh = NFS_FH(data->inode); | 471 | data->args.fh = NFS_FH(data->inode); |
475 | data->args.offset = dreq->pos; | 472 | data->args.offset = dreq->pos; |
@@ -641,10 +638,8 @@ static const struct rpc_call_ops nfs_write_direct_ops = { | |||
641 | */ | 638 | */ |
642 | static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync) | 639 | static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync) |
643 | { | 640 | { |
644 | struct file *file = dreq->filp; | 641 | struct nfs_open_context *ctx = dreq->ctx; |
645 | struct inode *inode = file->f_mapping->host; | 642 | struct inode *inode = ctx->dentry->d_inode; |
646 | struct nfs_open_context *ctx = (struct nfs_open_context *) | ||
647 | file->private_data; | ||
648 | struct list_head *list = &dreq->list; | 643 | struct list_head *list = &dreq->list; |
649 | struct page **pages = dreq->pages; | 644 | struct page **pages = dreq->pages; |
650 | size_t count = dreq->user_count; | 645 | size_t count = dreq->user_count; |
@@ -725,9 +720,8 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz | |||
725 | dreq->pos = pos; | 720 | dreq->pos = pos; |
726 | dreq->pages = pages; | 721 | dreq->pages = pages; |
727 | dreq->npages = nr_pages; | 722 | dreq->npages = nr_pages; |
728 | igrab(inode); | ||
729 | dreq->inode = inode; | 723 | dreq->inode = inode; |
730 | dreq->filp = iocb->ki_filp; | 724 | dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data); |
731 | if (!is_sync_kiocb(iocb)) | 725 | if (!is_sync_kiocb(iocb)) |
732 | dreq->iocb = iocb; | 726 | dreq->iocb = iocb; |
733 | 727 | ||