};
 
 struct socket_wq {
+       /* Note: wait MUST be first field of socket_wq */
        wait_queue_head_t       wait;
        struct fasync_struct    *fasync_list;
        struct rcu_head         rcu;
 
        unsigned long           flags;
 
-       struct socket_wq        *wq;
+       struct socket_wq __rcu  *wq;
 
        struct file             *file;
        struct sock             *sk;
 
        int                     sk_rcvbuf;
 
        struct sk_filter __rcu  *sk_filter;
-       struct socket_wq        *sk_wq;
+       struct socket_wq __rcu  *sk_wq;
 
 #ifdef CONFIG_NET_DMA
        struct sk_buff_head     sk_async_wait_queue;
 
 static inline wait_queue_head_t *sk_sleep(struct sock *sk)
 {
-       return &sk->sk_wq->wait;
+       BUILD_BUG_ON(offsetof(struct socket_wq, wait) != 0);
+       return &rcu_dereference_raw(sk->sk_wq)->wait;
 }
 /* Detach socket from process context.
  * Announce socket dead, detach it from wait queue and inode.
 static inline void sock_graft(struct sock *sk, struct socket *parent)
 {
        write_lock_bh(&sk->sk_callback_lock);
-       rcu_assign_pointer(sk->sk_wq, parent->wq);
+       sk->sk_wq = parent->wq;
        parent->sk = sk;
        sk_set_socket(sk, parent);
        security_sock_graft(sk, parent);
 
                        wake_up_interruptible(&asoc->wait);
 
                if (sctp_writeable(sk)) {
-                       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
-                               wake_up_interruptible(sk_sleep(sk));
+                       wait_queue_head_t *wq = sk_sleep(sk);
+
+                       if (wq && waitqueue_active(wq))
+                               wake_up_interruptible(wq);
 
                        /* Note that we try to include the Async I/O support
                         * here by modeling from the current TCP/UDP code.
                         * We have not tested with it yet.
                         */
-                       if (sock->wq->fasync_list &&
-                           !(sk->sk_shutdown & SEND_SHUTDOWN))
+                       if (!(sk->sk_shutdown & SEND_SHUTDOWN))
                                sock_wake_async(sock,
                                                SOCK_WAKE_SPACE, POLL_OUT);
                }
 
 static struct inode *sock_alloc_inode(struct super_block *sb)
 {
        struct socket_alloc *ei;
+       struct socket_wq *wq;
 
        ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);
        if (!ei)
                return NULL;
-       ei->socket.wq = kmalloc(sizeof(struct socket_wq), GFP_KERNEL);
-       if (!ei->socket.wq) {
+       wq = kmalloc(sizeof(*wq), GFP_KERNEL);
+       if (!wq) {
                kmem_cache_free(sock_inode_cachep, ei);
                return NULL;
        }
-       init_waitqueue_head(&ei->socket.wq->wait);
-       ei->socket.wq->fasync_list = NULL;
+       init_waitqueue_head(&wq->wait);
+       wq->fasync_list = NULL;
+       RCU_INIT_POINTER(ei->socket.wq, wq);
 
        ei->socket.state = SS_UNCONNECTED;
        ei->socket.flags = 0;
 static void sock_destroy_inode(struct inode *inode)
 {
        struct socket_alloc *ei;
+       struct socket_wq *wq;
 
        ei = container_of(inode, struct socket_alloc, vfs_inode);
-       call_rcu(&ei->socket.wq->rcu, wq_free_rcu);
+       wq = rcu_dereference_protected(ei->socket.wq, 1);
+       call_rcu(&wq->rcu, wq_free_rcu);
        kmem_cache_free(sock_inode_cachep, ei);
 }
 
                module_put(owner);
        }
 
-       if (sock->wq->fasync_list)
+       if (rcu_dereference_protected(sock->wq, 1)->fasync_list)
                printk(KERN_ERR "sock_release: fasync list not empty!\n");
 
        percpu_sub(sockets_in_use, 1);
 {
        struct socket *sock = filp->private_data;
        struct sock *sk = sock->sk;
+       struct socket_wq *wq;
 
        if (sk == NULL)
                return -EINVAL;
 
        lock_sock(sk);
+       wq = rcu_dereference_protected(sock->wq, sock_owned_by_user(sk));
+       fasync_helper(fd, filp, on, &wq->fasync_list);
 
-       fasync_helper(fd, filp, on, &sock->wq->fasync_list);
-
-       if (!sock->wq->fasync_list)
+       if (!wq->fasync_list)
                sock_reset_flag(sk, SOCK_FASYNC);
        else
                sock_set_flag(sk, SOCK_FASYNC);
 
 static void svc_udp_data_ready(struct sock *sk, int count)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
+       wait_queue_head_t *wq = sk_sleep(sk);
 
        if (svsk) {
                dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n",
                set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
                svc_xprt_enqueue(&svsk->sk_xprt);
        }
-       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
-               wake_up_interruptible(sk_sleep(sk));
+       if (wq && waitqueue_active(wq))
+               wake_up_interruptible(wq);
 }
 
 /*
 static void svc_write_space(struct sock *sk)
 {
        struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data);
+       wait_queue_head_t *wq = sk_sleep(sk);
 
        if (svsk) {
                dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
                svc_xprt_enqueue(&svsk->sk_xprt);
        }
 
-       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk))) {
+       if (wq && waitqueue_active(wq)) {
                dprintk("RPC svc_write_space: someone sleeping on %p\n",
                       svsk);
-               wake_up_interruptible(sk_sleep(sk));
+               wake_up_interruptible(wq);
        }
 }
 
 static void svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
+       wait_queue_head_t *wq;
 
        dprintk("svc: socket %p TCP (listen) state change %d\n",
                sk, sk->sk_state);
                        printk("svc: socket %p: no user data\n", sk);
        }
 
-       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
-               wake_up_interruptible_all(sk_sleep(sk));
+       wq = sk_sleep(sk);
+       if (wq && waitqueue_active(wq))
+               wake_up_interruptible_all(wq);
 }
 
 /*
 static void svc_tcp_state_change(struct sock *sk)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
+       wait_queue_head_t *wq = sk_sleep(sk);
 
        dprintk("svc: socket %p TCP (connected) state change %d (svsk %p)\n",
                sk, sk->sk_state, sk->sk_user_data);
                set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
                svc_xprt_enqueue(&svsk->sk_xprt);
        }
-       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
-               wake_up_interruptible_all(sk_sleep(sk));
+       if (wq && waitqueue_active(wq))
+               wake_up_interruptible_all(wq);
 }
 
 static void svc_tcp_data_ready(struct sock *sk, int count)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
+       wait_queue_head_t *wq = sk_sleep(sk);
 
        dprintk("svc: socket %p TCP data ready (svsk %p)\n",
                sk, sk->sk_user_data);
                set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
                svc_xprt_enqueue(&svsk->sk_xprt);
        }
-       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
-               wake_up_interruptible(sk_sleep(sk));
+       if (wq && waitqueue_active(wq))
+               wake_up_interruptible(wq);
 }
 
 /*
 {
        struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
        struct sock *sk = svsk->sk_sk;
+       wait_queue_head_t *wq;
 
        dprintk("svc: svc_sock_detach(%p)\n", svsk);
 
        sk->sk_data_ready = svsk->sk_odata;
        sk->sk_write_space = svsk->sk_owspace;
 
-       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
-               wake_up_interruptible(sk_sleep(sk));
+       wq = sk_sleep(sk);
+       if (wq && waitqueue_active(wq))
+               wake_up_interruptible(wq);
 }
 
 /*
 
        newsk->sk_type          = sk->sk_type;
        init_peercred(newsk);
        newu = unix_sk(newsk);
-       newsk->sk_wq            = &newu->peer_wq;
+       RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq);
        otheru = unix_sk(other);
 
        /* copy address information from listening to new sock*/