diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-11-13 16:23:44 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-12-06 10:46:26 -0500 |
commit | 8aca67f0ae2d8811165c22326825a645cc8e1b48 (patch) | |
tree | 19e82f4bc7b4f865a9dcf4744e7c224ea517ba10 /fs/nfs/read.c | |
parent | e6b3c4db6fbcd0d33720696f37790d6b8be12313 (diff) |
SUNRPC: Fix a potential race in rpc_wake_up_task()
Use RCU to ensure that we can safely call rpc_finish_wakeup after we've
called __rpc_do_wake_up_task. If not, there is a theoretical race, in which
the rpc_task finishes executing, and gets freed first.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index c2e49c397a27..8b58bbf6e39e 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -65,13 +65,19 @@ struct nfs_read_data *nfs_readdata_alloc(size_t len) | |||
65 | return p; | 65 | return p; |
66 | } | 66 | } |
67 | 67 | ||
68 | static void nfs_readdata_free(struct nfs_read_data *p) | 68 | static void nfs_readdata_rcu_free(struct rcu_head *head) |
69 | { | 69 | { |
70 | struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu); | ||
70 | if (p && (p->pagevec != &p->page_array[0])) | 71 | if (p && (p->pagevec != &p->page_array[0])) |
71 | kfree(p->pagevec); | 72 | kfree(p->pagevec); |
72 | mempool_free(p, nfs_rdata_mempool); | 73 | mempool_free(p, nfs_rdata_mempool); |
73 | } | 74 | } |
74 | 75 | ||
76 | static void nfs_readdata_free(struct nfs_read_data *rdata) | ||
77 | { | ||
78 | call_rcu_bh(&rdata->task.u.tk_rcu, nfs_readdata_rcu_free); | ||
79 | } | ||
80 | |||
75 | void nfs_readdata_release(void *data) | 81 | void nfs_readdata_release(void *data) |
76 | { | 82 | { |
77 | nfs_readdata_free(data); | 83 | nfs_readdata_free(data); |