summaryrefslogtreecommitdiffstats
path: root/fs/nfs/read.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-11-13 22:23:44 +0100
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-12-06 16:46:26 +0100
commit8aca67f0ae2d8811165c22326825a645cc8e1b48 (patch)
tree19e82f4bc7b4f865a9dcf4744e7c224ea517ba10 /fs/nfs/read.c
parentFix a second potential rpc_wakeup race... (diff)
downloadlinux-8aca67f0ae2d8811165c22326825a645cc8e1b48.tar.xz
linux-8aca67f0ae2d8811165c22326825a645cc8e1b48.zip
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.c8
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)
return p;
}
-static void nfs_readdata_free(struct nfs_read_data *p)
+static void nfs_readdata_rcu_free(struct rcu_head *head)
{
+ struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu);
if (p && (p->pagevec != &p->page_array[0]))
kfree(p->pagevec);
mempool_free(p, nfs_rdata_mempool);
}
+static void nfs_readdata_free(struct nfs_read_data *rdata)
+{
+ call_rcu_bh(&rdata->task.u.tk_rcu, nfs_readdata_rcu_free);
+}
+
void nfs_readdata_release(void *data)
{
nfs_readdata_free(data);