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 /include | |
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 'include')
-rw-r--r-- | include/linux/nfs_fs.h | 7 | ||||
-rw-r--r-- | include/linux/sunrpc/sched.h | 2 |
2 files changed, 4 insertions, 5 deletions
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 625ffea98561..02f38189d180 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -428,11 +428,6 @@ extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned | |||
428 | extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); | 428 | extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); |
429 | extern void nfs_writedata_release(void *); | 429 | extern void nfs_writedata_release(void *); |
430 | 430 | ||
431 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | ||
432 | struct nfs_write_data *nfs_commit_alloc(void); | ||
433 | void nfs_commit_free(struct nfs_write_data *p); | ||
434 | #endif | ||
435 | |||
436 | /* | 431 | /* |
437 | * Try to write back everything synchronously (but check the | 432 | * Try to write back everything synchronously (but check the |
438 | * return value!) | 433 | * return value!) |
@@ -440,6 +435,8 @@ void nfs_commit_free(struct nfs_write_data *p); | |||
440 | extern int nfs_sync_inode_wait(struct inode *, unsigned long, unsigned int, int); | 435 | extern int nfs_sync_inode_wait(struct inode *, unsigned long, unsigned int, int); |
441 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 436 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
442 | extern int nfs_commit_inode(struct inode *, int); | 437 | extern int nfs_commit_inode(struct inode *, int); |
438 | extern struct nfs_write_data *nfs_commit_alloc(void); | ||
439 | extern void nfs_commit_free(struct nfs_write_data *wdata); | ||
443 | extern void nfs_commit_release(void *wdata); | 440 | extern void nfs_commit_release(void *wdata); |
444 | #else | 441 | #else |
445 | static inline int | 442 | static inline int |
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 9fdb8c9d09f2..14fc813ddd0c 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/timer.h> | 12 | #include <linux/timer.h> |
13 | #include <linux/sunrpc/types.h> | 13 | #include <linux/sunrpc/types.h> |
14 | #include <linux/rcupdate.h> | ||
14 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
15 | #include <linux/wait.h> | 16 | #include <linux/wait.h> |
16 | #include <linux/workqueue.h> | 17 | #include <linux/workqueue.h> |
@@ -85,6 +86,7 @@ struct rpc_task { | |||
85 | union { | 86 | union { |
86 | struct work_struct tk_work; /* Async task work queue */ | 87 | struct work_struct tk_work; /* Async task work queue */ |
87 | struct rpc_wait tk_wait; /* RPC wait */ | 88 | struct rpc_wait tk_wait; /* RPC wait */ |
89 | struct rcu_head tk_rcu; /* for task deletion */ | ||
88 | } u; | 90 | } u; |
89 | 91 | ||
90 | unsigned short tk_timeouts; /* maj timeouts */ | 92 | unsigned short tk_timeouts; /* maj timeouts */ |