diff options
author | Nadia Derbey <Nadia.Derbey@bull.net> | 2007-10-18 23:40:54 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-19 11:53:48 -0700 |
commit | 3e148c79938aa39035669c1cfa3ff60722134535 (patch) | |
tree | 0effb3edfece56ea38a9727ec8f4721d9a4c3ea8 /ipc/util.h | |
parent | f4566f04854d78acfc74b9acb029744acde9d033 (diff) | |
download | lwn-3e148c79938aa39035669c1cfa3ff60722134535.tar.gz lwn-3e148c79938aa39035669c1cfa3ff60722134535.zip |
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 { int in_use; unsigned short seq; unsigned short seq_max; - struct mutex mutex; + struct rw_semaphore rw_mutex; struct idr ipcs_idr; }; @@ -81,8 +81,10 @@ void __init ipc_init_proc_interface(const char *path, const char *header, #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) -/* must be called with ids->mutex acquired.*/ +/* must be called with ids->rw_mutex acquired for writing */ int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); + +/* must be called with ids->rw_mutex acquired for reading */ int ipc_get_maxid(struct ipc_ids *); /* must be called with both locks acquired. */ @@ -107,6 +109,11 @@ void* ipc_rcu_alloc(int size); void ipc_rcu_getref(void *ptr); void ipc_rcu_putref(void *ptr); +/* + * ipc_lock_down: called with rw_mutex held + * ipc_lock: called without that lock held + */ +struct kern_ipc_perm *ipc_lock_down(struct ipc_ids *, int); struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int); 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) rcu_read_unlock(); } +static inline struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, + int id) +{ + struct kern_ipc_perm *out; + + out = ipc_lock_down(ids, id); + if (IS_ERR(out)) + return out; + + if (ipc_checkid(ids, out, id)) { + ipc_unlock(out); + return ERR_PTR(-EIDRM); + } + + return out; +} + static inline struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id) { |