diff options
author | Nadia Derbey <Nadia.Derbey@bull.net> | 2007-10-19 02:40:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-19 14:53:48 -0400 |
commit | 3e148c79938aa39035669c1cfa3ff60722134535 (patch) | |
tree | 0effb3edfece56ea38a9727ec8f4721d9a4c3ea8 /ipc/util.h | |
parent | f4566f04854d78acfc74b9acb029744acde9d033 (diff) |
fix idr_find() locking
This is a patch that fixes the way idr_find() used to be called in ipc_lock():
in all the paths that don't imply an update of the ipcs idr, it was called
without the idr tree being locked.
The changes are:
. in ipc_ids, the mutex has been changed into a reader/writer semaphore.
. ipc_lock() now takes the mutex as a reader during the idr_find().
. a new routine ipc_lock_down() has been defined: it doesn't take the
mutex, assuming that it is being held by the caller. This is the routine
that is now called in all the update paths.
Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net>
Acked-by: Jarek Poplawski <jarkao2@o2.pl>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc/util.h')
-rw-r--r-- | ipc/util.h | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/ipc/util.h b/ipc/util.h index 99414a36a250..bd47687077e0 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
@@ -32,7 +32,7 @@ struct ipc_ids { | |||
32 | int in_use; | 32 | int in_use; |
33 | unsigned short seq; | 33 | unsigned short seq; |
34 | unsigned short seq_max; | 34 | unsigned short seq_max; |
35 | struct mutex mutex; | 35 | struct rw_semaphore rw_mutex; |
36 | struct idr ipcs_idr; | 36 | struct idr ipcs_idr; |
37 | }; | 37 | }; |
38 | 38 | ||
@@ -81,8 +81,10 @@ void __init ipc_init_proc_interface(const char *path, const char *header, | |||
81 | 81 | ||
82 | #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) | 82 | #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) |
83 | 83 | ||
84 | /* must be called with ids->mutex acquired.*/ | 84 | /* must be called with ids->rw_mutex acquired for writing */ |
85 | int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); | 85 | int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); |
86 | |||
87 | /* must be called with ids->rw_mutex acquired for reading */ | ||
86 | int ipc_get_maxid(struct ipc_ids *); | 88 | int ipc_get_maxid(struct ipc_ids *); |
87 | 89 | ||
88 | /* must be called with both locks acquired. */ | 90 | /* must be called with both locks acquired. */ |
@@ -107,6 +109,11 @@ void* ipc_rcu_alloc(int size); | |||
107 | void ipc_rcu_getref(void *ptr); | 109 | void ipc_rcu_getref(void *ptr); |
108 | void ipc_rcu_putref(void *ptr); | 110 | void ipc_rcu_putref(void *ptr); |
109 | 111 | ||
112 | /* | ||
113 | * ipc_lock_down: called with rw_mutex held | ||
114 | * ipc_lock: called without that lock held | ||
115 | */ | ||
116 | struct kern_ipc_perm *ipc_lock_down(struct ipc_ids *, int); | ||
110 | struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int); | 117 | struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int); |
111 | 118 | ||
112 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); | 119 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); |
@@ -155,6 +162,23 @@ static inline void ipc_unlock(struct kern_ipc_perm *perm) | |||
155 | rcu_read_unlock(); | 162 | rcu_read_unlock(); |
156 | } | 163 | } |
157 | 164 | ||
165 | static inline struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, | ||
166 | int id) | ||
167 | { | ||
168 | struct kern_ipc_perm *out; | ||
169 | |||
170 | out = ipc_lock_down(ids, id); | ||
171 | if (IS_ERR(out)) | ||
172 | return out; | ||
173 | |||
174 | if (ipc_checkid(ids, out, id)) { | ||
175 | ipc_unlock(out); | ||
176 | return ERR_PTR(-EIDRM); | ||
177 | } | ||
178 | |||
179 | return out; | ||
180 | } | ||
181 | |||
158 | static inline struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, | 182 | static inline struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, |
159 | int id) | 183 | int id) |
160 | { | 184 | { |