summaryrefslogtreecommitdiffhomepage
path: root/net/core/sock.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/sock.c')
-rw-r--r--net/core/sock.c84
1 files changed, 50 insertions, 34 deletions
diff --git a/net/core/sock.c b/net/core/sock.c
index 5976100a9d55..b37b664b6eb9 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -520,43 +520,36 @@ int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
EXPORT_SYMBOL(__sock_queue_rcv_skb);
-int sock_queue_rcv_skb_reason(struct sock *sk, struct sk_buff *skb,
- enum skb_drop_reason *reason)
+enum skb_drop_reason
+sock_queue_rcv_skb_reason(struct sock *sk, struct sk_buff *skb)
{
enum skb_drop_reason drop_reason;
int err;
- err = sk_filter_reason(sk, skb, &drop_reason);
- if (err)
- goto out;
+ drop_reason = sk_filter_reason(sk, skb);
+ if (drop_reason)
+ return drop_reason;
err = __sock_queue_rcv_skb(sk, skb);
switch (err) {
case -ENOMEM:
- drop_reason = SKB_DROP_REASON_SOCKET_RCVBUFF;
- break;
+ return SKB_DROP_REASON_SOCKET_RCVBUFF;
case -ENOBUFS:
- drop_reason = SKB_DROP_REASON_PROTO_MEM;
- break;
- default:
- drop_reason = SKB_NOT_DROPPED_YET;
- break;
+ return SKB_DROP_REASON_PROTO_MEM;
}
-out:
- if (reason)
- *reason = drop_reason;
- return err;
+ return SKB_NOT_DROPPED_YET;
}
EXPORT_SYMBOL(sock_queue_rcv_skb_reason);
int __sk_receive_skb(struct sock *sk, struct sk_buff *skb,
const int nested, unsigned int trim_cap, bool refcounted)
{
- enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
+ enum skb_drop_reason reason;
int rc = NET_RX_SUCCESS;
int err;
- if (sk_filter_trim_cap(sk, skb, trim_cap, &reason))
+ reason = sk_filter_trim_cap(sk, skb, trim_cap);
+ if (reason)
goto discard_and_relse;
skb->dev = NULL;
@@ -973,6 +966,8 @@ EXPORT_SYMBOL(sock_set_keepalive);
static void __sock_set_rcvbuf(struct sock *sk, int val)
{
+ struct socket *sock = sk->sk_socket;
+
/* Ensure val * 2 fits into an int, to prevent max_t() from treating it
* as a negative value.
*/
@@ -990,6 +985,13 @@ static void __sock_set_rcvbuf(struct sock *sk, int val)
* we actually used in getsockopt is the most desirable behavior.
*/
WRITE_ONCE(sk->sk_rcvbuf, max_t(int, val * 2, SOCK_MIN_RCVBUF));
+
+ if (sock) {
+ const struct proto_ops *ops = READ_ONCE(sock->ops);
+
+ if (ops->set_rcvbuf)
+ ops->set_rcvbuf(sk, sk->sk_rcvbuf);
+ }
}
void sock_set_rcvbuf(struct sock *sk, int val)
@@ -2583,6 +2585,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority,
sk_set_socket(newsk, NULL);
sk_tx_queue_clear(newsk);
+ sk_rx_queue_clear(newsk);
RCU_INIT_POINTER(newsk->sk_wq, NULL);
if (newsk->sk_prot->sockets_allocated)
@@ -3175,7 +3178,7 @@ bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag)
}
EXPORT_SYMBOL(sk_page_frag_refill);
-void __lock_sock(struct sock *sk)
+static void __lock_sock(struct sock *sk)
__releases(&sk->sk_lock.slock)
__acquires(&sk->sk_lock.slock)
{
@@ -3774,14 +3777,30 @@ void sock_init_data(struct socket *sock, struct sock *sk)
}
EXPORT_SYMBOL(sock_init_data);
-void lock_sock_nested(struct sock *sk, int subclass)
+void noinline lock_sock_nested(struct sock *sk, int subclass)
{
/* The sk_lock has mutex_lock() semantics here. */
mutex_acquire(&sk->sk_lock.dep_map, subclass, 0, _RET_IP_);
might_sleep();
+#ifdef CONFIG_64BIT
+ if (sizeof(struct slock_owned) == sizeof(long)) {
+ socket_lock_t tmp = {
+ .slock = __SPIN_LOCK_UNLOCKED(tmp.slock),
+ .owned = 1,
+ };
+ socket_lock_t old = {
+ .slock = __SPIN_LOCK_UNLOCKED(old.slock),
+ .owned = 0,
+ };
+
+ if (likely(try_cmpxchg(&sk->sk_lock.combined,
+ &old.combined, tmp.combined)))
+ return;
+ }
+#endif
spin_lock_bh(&sk->sk_lock.slock);
- if (sock_owned_by_user_nocheck(sk))
+ if (unlikely(sock_owned_by_user_nocheck(sk)))
__lock_sock(sk);
sk->sk_lock.owned = 1;
spin_unlock_bh(&sk->sk_lock.slock);
@@ -3791,16 +3810,18 @@ EXPORT_SYMBOL(lock_sock_nested);
void release_sock(struct sock *sk)
{
spin_lock_bh(&sk->sk_lock.slock);
- if (sk->sk_backlog.tail)
- __release_sock(sk);
- if (sk->sk_prot->release_cb)
- INDIRECT_CALL_INET_1(sk->sk_prot->release_cb,
- tcp_release_cb, sk);
+ if (unlikely(sk->sk_backlog.tail))
+ __release_sock(sk);
+ if (sk->sk_prot->release_cb) {
+ if (!tcp_release_cb_cond(sk))
+ sk->sk_prot->release_cb(sk);
+ }
sock_release_ownership(sk);
- if (waitqueue_active(&sk->sk_lock.wq))
+ if (unlikely(waitqueue_active(&sk->sk_lock.wq)))
wake_up(&sk->sk_lock.wq);
+
spin_unlock_bh(&sk->sk_lock.slock);
}
EXPORT_SYMBOL(release_sock);
@@ -3810,7 +3831,7 @@ bool __lock_sock_fast(struct sock *sk) __acquires(&sk->sk_lock.slock)
might_sleep();
spin_lock_bh(&sk->sk_lock.slock);
- if (!sock_owned_by_user_nocheck(sk)) {
+ if (likely(!sock_owned_by_user_nocheck(sk))) {
/*
* Fast path return with bottom halves disabled and
* sock::sk_lock.slock held.
@@ -3951,13 +3972,8 @@ int sock_common_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
int flags)
{
struct sock *sk = sock->sk;
- int addr_len = 0;
- int err;
- err = sk->sk_prot->recvmsg(sk, msg, size, flags, &addr_len);
- if (err >= 0)
- msg->msg_namelen = addr_len;
- return err;
+ return sk->sk_prot->recvmsg(sk, msg, size, flags);
}
EXPORT_SYMBOL(sock_common_recvmsg);