aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-07-09 23:18:24 -0400
committerDavid S. Miller <davem@davemloft.net>2009-07-09 23:18:24 -0400
commite5a8a896f5180f2950695d2d0b79db348d200ca4 (patch)
tree04adc57ae51a6d30a89ffae970770b81ee81fc23 /include
parentbff38771e1065c7fc3de87e47ba366151eea573c (diff)
parente594e96e8a14101a6decabf6746bd5186287debc (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Diffstat (limited to 'include')
-rw-r--r--include/linux/rfkill.h1
-rw-r--r--include/linux/spinlock.h5
-rw-r--r--include/net/sock.h69
3 files changed, 74 insertions, 1 deletions
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index e73e2429a1b1..2ce29831feb6 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -99,7 +99,6 @@ enum rfkill_user_states {
99#undef RFKILL_STATE_UNBLOCKED 99#undef RFKILL_STATE_UNBLOCKED
100#undef RFKILL_STATE_HARD_BLOCKED 100#undef RFKILL_STATE_HARD_BLOCKED
101 101
102#include <linux/types.h>
103#include <linux/kernel.h> 102#include <linux/kernel.h>
104#include <linux/list.h> 103#include <linux/list.h>
105#include <linux/mutex.h> 104#include <linux/mutex.h>
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index 252b245cfcf4..4be57ab03478 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -132,6 +132,11 @@ do { \
132#endif /*__raw_spin_is_contended*/ 132#endif /*__raw_spin_is_contended*/
133#endif 133#endif
134 134
135/* The lock does not imply full memory barrier. */
136#ifndef ARCH_HAS_SMP_MB_AFTER_LOCK
137static inline void smp_mb__after_lock(void) { smp_mb(); }
138#endif
139
135/** 140/**
136 * spin_unlock_wait - wait until the spinlock gets unlocked 141 * spin_unlock_wait - wait until the spinlock gets unlocked
137 * @lock: the spinlock in question. 142 * @lock: the spinlock in question.
diff --git a/include/net/sock.h b/include/net/sock.h
index 352f06bbd7a9..2c0da9239b95 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -54,6 +54,7 @@
54 54
55#include <linux/filter.h> 55#include <linux/filter.h>
56#include <linux/rculist_nulls.h> 56#include <linux/rculist_nulls.h>
57#include <linux/poll.h>
57 58
58#include <asm/atomic.h> 59#include <asm/atomic.h>
59#include <net/dst.h> 60#include <net/dst.h>
@@ -1241,6 +1242,74 @@ static inline int sk_has_allocations(const struct sock *sk)
1241 return sk_wmem_alloc_get(sk) || sk_rmem_alloc_get(sk); 1242 return sk_wmem_alloc_get(sk) || sk_rmem_alloc_get(sk);
1242} 1243}
1243 1244
1245/**
1246 * sk_has_sleeper - check if there are any waiting processes
1247 * @sk: socket
1248 *
1249 * Returns true if socket has waiting processes
1250 *
1251 * The purpose of the sk_has_sleeper and sock_poll_wait is to wrap the memory
1252 * barrier call. They were added due to the race found within the tcp code.
1253 *
1254 * Consider following tcp code paths:
1255 *
1256 * CPU1 CPU2
1257 *
1258 * sys_select receive packet
1259 * ... ...
1260 * __add_wait_queue update tp->rcv_nxt
1261 * ... ...
1262 * tp->rcv_nxt check sock_def_readable
1263 * ... {
1264 * schedule ...
1265 * if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
1266 * wake_up_interruptible(sk->sk_sleep)
1267 * ...
1268 * }
1269 *
1270 * The race for tcp fires when the __add_wait_queue changes done by CPU1 stay
1271 * in its cache, and so does the tp->rcv_nxt update on CPU2 side. The CPU1
1272 * could then endup calling schedule and sleep forever if there are no more
1273 * data on the socket.
1274 *
1275 * The sk_has_sleeper is always called right after a call to read_lock, so we
1276 * can use smp_mb__after_lock barrier.
1277 */
1278static inline int sk_has_sleeper(struct sock *sk)
1279{
1280 /*
1281 * We need to be sure we are in sync with the
1282 * add_wait_queue modifications to the wait queue.
1283 *
1284 * This memory barrier is paired in the sock_poll_wait.
1285 */
1286 smp_mb__after_lock();
1287 return sk->sk_sleep && waitqueue_active(sk->sk_sleep);
1288}
1289
1290/**
1291 * sock_poll_wait - place memory barrier behind the poll_wait call.
1292 * @filp: file
1293 * @wait_address: socket wait queue
1294 * @p: poll_table
1295 *
1296 * See the comments in the sk_has_sleeper function.
1297 */
1298static inline void sock_poll_wait(struct file *filp,
1299 wait_queue_head_t *wait_address, poll_table *p)
1300{
1301 if (p && wait_address) {
1302 poll_wait(filp, wait_address, p);
1303 /*
1304 * We need to be sure we are in sync with the
1305 * socket flags modification.
1306 *
1307 * This memory barrier is paired in the sk_has_sleeper.
1308 */
1309 smp_mb();
1310 }
1311}
1312
1244/* 1313/*
1245 * Queue a received datagram if it will fit. Stream and sequenced 1314 * Queue a received datagram if it will fit. Stream and sequenced
1246 * protocols can't normally use this as they need to fit buffers in 1315 * protocols can't normally use this as they need to fit buffers in