diff options
author | Arnaldo Carvalho de Melo <acme@ghostprotocols.net> | 2005-08-10 07:08:09 +0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-30 02:41:49 +0400 |
commit | f3f05f7046e7c85b04af390d95a82a27160dd5d0 (patch) | |
tree | 9a4a552c030ea8b2428ceee75311d73a6b339255 /net/ipv4/inet_hashtables.c | |
parent | 6e04e02165a7209a71db553b7bc48d68421e5ebf (diff) | |
download | linux-f3f05f7046e7c85b04af390d95a82a27160dd5d0.tar.xz |
[INET]: Generalise the tcp_listen_ lock routines
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/inet_hashtables.c')
-rw-r--r-- | net/ipv4/inet_hashtables.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 33d6cbe32cdc..06cbc6f689c5 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -15,7 +15,9 @@ #include <linux/config.h> #include <linux/module.h> +#include <linux/sched.h> #include <linux/slab.h> +#include <linux/wait.h> #include <net/inet_hashtables.h> @@ -89,3 +91,33 @@ void inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk) } EXPORT_SYMBOL(inet_put_port); + +/* + * This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP. + * Look, when several writers sleep and reader wakes them up, all but one + * immediately hit write lock and grab all the cpus. Exclusive sleep solves + * this, _but_ remember, it adds useless work on UP machines (wake up each + * exclusive lock release). It should be ifdefed really. + */ +void inet_listen_wlock(struct inet_hashinfo *hashinfo) +{ + write_lock(&hashinfo->lhash_lock); + + if (atomic_read(&hashinfo->lhash_users)) { + DEFINE_WAIT(wait); + + for (;;) { + prepare_to_wait_exclusive(&hashinfo->lhash_wait, + &wait, TASK_UNINTERRUPTIBLE); + if (!atomic_read(&hashinfo->lhash_users)) + break; + write_unlock_bh(&hashinfo->lhash_lock); + schedule(); + write_lock_bh(&hashinfo->lhash_lock); + } + + finish_wait(&hashinfo->lhash_wait, &wait); + } +} + +EXPORT_SYMBOL(inet_listen_wlock); |