diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/rfkill.h | 1 | ||||
| -rw-r--r-- | include/linux/spinlock.h | 5 | ||||
| -rw-r--r-- | include/net/sock.h | 69 |
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 | ||
| 137 | static 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 | */ | ||
| 1278 | static 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 | */ | ||
| 1298 | static 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 |
