diff options
Diffstat (limited to 'include/net/sock.h')
-rw-r--r-- | include/net/sock.h | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index 092b0551e77f..56df440a950b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/skbuff.h> /* struct sk_buff */ | 51 | #include <linux/skbuff.h> /* struct sk_buff */ |
52 | #include <linux/mm.h> | 52 | #include <linux/mm.h> |
53 | #include <linux/security.h> | 53 | #include <linux/security.h> |
54 | #include <linux/slab.h> | ||
54 | 55 | ||
55 | #include <linux/filter.h> | 56 | #include <linux/filter.h> |
56 | #include <linux/rculist_nulls.h> | 57 | #include <linux/rculist_nulls.h> |
@@ -261,7 +262,7 @@ struct sock { | |||
261 | #ifdef CONFIG_XFRM | 262 | #ifdef CONFIG_XFRM |
262 | struct xfrm_policy *sk_policy[2]; | 263 | struct xfrm_policy *sk_policy[2]; |
263 | #endif | 264 | #endif |
264 | rwlock_t sk_dst_lock; | 265 | spinlock_t sk_dst_lock; |
265 | atomic_t sk_rmem_alloc; | 266 | atomic_t sk_rmem_alloc; |
266 | atomic_t sk_wmem_alloc; | 267 | atomic_t sk_wmem_alloc; |
267 | atomic_t sk_omem_alloc; | 268 | atomic_t sk_omem_alloc; |
@@ -1191,7 +1192,8 @@ extern unsigned long sock_i_ino(struct sock *sk); | |||
1191 | static inline struct dst_entry * | 1192 | static inline struct dst_entry * |
1192 | __sk_dst_get(struct sock *sk) | 1193 | __sk_dst_get(struct sock *sk) |
1193 | { | 1194 | { |
1194 | return sk->sk_dst_cache; | 1195 | return rcu_dereference_check(sk->sk_dst_cache, rcu_read_lock_held() || |
1196 | sock_owned_by_user(sk)); | ||
1195 | } | 1197 | } |
1196 | 1198 | ||
1197 | static inline struct dst_entry * | 1199 | static inline struct dst_entry * |
@@ -1199,50 +1201,62 @@ sk_dst_get(struct sock *sk) | |||
1199 | { | 1201 | { |
1200 | struct dst_entry *dst; | 1202 | struct dst_entry *dst; |
1201 | 1203 | ||
1202 | read_lock(&sk->sk_dst_lock); | 1204 | rcu_read_lock(); |
1203 | dst = sk->sk_dst_cache; | 1205 | dst = rcu_dereference(sk->sk_dst_cache); |
1204 | if (dst) | 1206 | if (dst) |
1205 | dst_hold(dst); | 1207 | dst_hold(dst); |
1206 | read_unlock(&sk->sk_dst_lock); | 1208 | rcu_read_unlock(); |
1207 | return dst; | 1209 | return dst; |
1208 | } | 1210 | } |
1209 | 1211 | ||
1212 | extern void sk_reset_txq(struct sock *sk); | ||
1213 | |||
1214 | static inline void dst_negative_advice(struct sock *sk) | ||
1215 | { | ||
1216 | struct dst_entry *ndst, *dst = __sk_dst_get(sk); | ||
1217 | |||
1218 | if (dst && dst->ops->negative_advice) { | ||
1219 | ndst = dst->ops->negative_advice(dst); | ||
1220 | |||
1221 | if (ndst != dst) { | ||
1222 | rcu_assign_pointer(sk->sk_dst_cache, ndst); | ||
1223 | sk_reset_txq(sk); | ||
1224 | } | ||
1225 | } | ||
1226 | } | ||
1227 | |||
1210 | static inline void | 1228 | static inline void |
1211 | __sk_dst_set(struct sock *sk, struct dst_entry *dst) | 1229 | __sk_dst_set(struct sock *sk, struct dst_entry *dst) |
1212 | { | 1230 | { |
1213 | struct dst_entry *old_dst; | 1231 | struct dst_entry *old_dst; |
1214 | 1232 | ||
1215 | sk_tx_queue_clear(sk); | 1233 | sk_tx_queue_clear(sk); |
1216 | old_dst = sk->sk_dst_cache; | 1234 | old_dst = rcu_dereference_check(sk->sk_dst_cache, |
1217 | sk->sk_dst_cache = dst; | 1235 | lockdep_is_held(&sk->sk_dst_lock)); |
1236 | rcu_assign_pointer(sk->sk_dst_cache, dst); | ||
1218 | dst_release(old_dst); | 1237 | dst_release(old_dst); |
1219 | } | 1238 | } |
1220 | 1239 | ||
1221 | static inline void | 1240 | static inline void |
1222 | sk_dst_set(struct sock *sk, struct dst_entry *dst) | 1241 | sk_dst_set(struct sock *sk, struct dst_entry *dst) |
1223 | { | 1242 | { |
1224 | write_lock(&sk->sk_dst_lock); | 1243 | spin_lock(&sk->sk_dst_lock); |
1225 | __sk_dst_set(sk, dst); | 1244 | __sk_dst_set(sk, dst); |
1226 | write_unlock(&sk->sk_dst_lock); | 1245 | spin_unlock(&sk->sk_dst_lock); |
1227 | } | 1246 | } |
1228 | 1247 | ||
1229 | static inline void | 1248 | static inline void |
1230 | __sk_dst_reset(struct sock *sk) | 1249 | __sk_dst_reset(struct sock *sk) |
1231 | { | 1250 | { |
1232 | struct dst_entry *old_dst; | 1251 | __sk_dst_set(sk, NULL); |
1233 | |||
1234 | sk_tx_queue_clear(sk); | ||
1235 | old_dst = sk->sk_dst_cache; | ||
1236 | sk->sk_dst_cache = NULL; | ||
1237 | dst_release(old_dst); | ||
1238 | } | 1252 | } |
1239 | 1253 | ||
1240 | static inline void | 1254 | static inline void |
1241 | sk_dst_reset(struct sock *sk) | 1255 | sk_dst_reset(struct sock *sk) |
1242 | { | 1256 | { |
1243 | write_lock(&sk->sk_dst_lock); | 1257 | spin_lock(&sk->sk_dst_lock); |
1244 | __sk_dst_reset(sk); | 1258 | __sk_dst_reset(sk); |
1245 | write_unlock(&sk->sk_dst_lock); | 1259 | spin_unlock(&sk->sk_dst_lock); |
1246 | } | 1260 | } |
1247 | 1261 | ||
1248 | extern struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie); | 1262 | extern struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie); |