diff --git a/include/net/sock.h b/include/net/sock.h index e7099d3d0416..a7a8b31e9877 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -81,8 +81,13 @@ * mini-semaphore synchronizes multiple users amongst themselves. */ typedef struct { - spinlock_t slock; - int owned; + union { + struct slock_owned { + int owned; + spinlock_t slock; + }; + long combined; + }; wait_queue_head_t wq; /* * We express the mutex-alike socket_lock semantics diff --git a/net/core/sock.c b/net/core/sock.c index 2032be9a03b5..9d841975a7a1 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -3780,6 +3780,19 @@ void noinline lock_sock_nested(struct sock *sk, int subclass) 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, old; + + tmp.slock = __SPIN_LOCK_UNLOCKED(tmp.slock); + tmp.owned = 1; + old.slock = __SPIN_LOCK_UNLOCKED(old.slock); + old.owned = 0; + if (likely(try_cmpxchg(&sk->sk_lock.combined, + &old.combined, tmp.combined))) + return; + } +#endif spin_lock_bh(&sk->sk_lock.slock); if (unlikely(sock_owned_by_user_nocheck(sk))) __lock_sock(sk);