From patchwork Thu Dec 15 12:46:14 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Emelyanov X-Patchwork-Id: 131594 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 5660E1007D6 for ; Thu, 15 Dec 2011 23:46:27 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758823Ab1LOMqW (ORCPT ); Thu, 15 Dec 2011 07:46:22 -0500 Received: from mailhub.sw.ru ([195.214.232.25]:18223 "EHLO relay.sw.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756117Ab1LOMqW (ORCPT ); Thu, 15 Dec 2011 07:46:22 -0500 Received: from [10.30.19.237] ([10.30.19.237]) (authenticated bits=0) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id pBFCkELJ025522 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 15 Dec 2011 15:46:16 +0300 (MSK) Message-ID: <4EE9EC16.7070701@parallels.com> Date: Thu, 15 Dec 2011 16:46:14 +0400 From: Pavel Emelyanov User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc15 Thunderbird/3.1.10 MIME-Version: 1.0 To: David Miller , Linux Netdev List Subject: [PATCH 11/13] unix_diag: Pending connections IDs NLA References: <4EE9EB2A.4040909@parallels.com> In-Reply-To: <4EE9EB2A.4040909@parallels.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org When establishing a unix connection on stream sockets the server end receives an skb with socket in its receive queue. Report who is waiting for these ends to be accepted for listening sockets via NLA. There's a lokcing issue with this -- the unix sk state lock is required to access the peer, and it is taken under the listening sk's queue lock. Strictly speaking the queue lock should be taken inside the state lock, but since in this case these two sockets are different it shouldn't lead to deadlock. Signed-off-by: Pavel Emelyanov --- include/linux/unix_diag.h | 2 ++ net/unix/diag.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 0 deletions(-) diff --git a/include/linux/unix_diag.h b/include/linux/unix_diag.h index 2d74a86..03ffb7d 100644 --- a/include/linux/unix_diag.h +++ b/include/linux/unix_diag.h @@ -14,6 +14,7 @@ struct unix_diag_req { #define UDIAG_SHOW_NAME 0x00000001 /* show name (not path) */ #define UDIAG_SHOW_VFS 0x00000002 /* show VFS inode info */ #define UDIAG_SHOW_PEER 0x00000004 /* show peer socket info */ +#define UDIAG_SHOW_ICONS 0x00000008 /* show pending connections */ struct unix_diag_msg { __u8 udiag_family; @@ -29,6 +30,7 @@ enum { UNIX_DIAG_NAME, UNIX_DIAG_VFS, UNIX_DIAG_PEER, + UNIX_DIAG_ICONS, UNIX_DIAG_MAX, }; diff --git a/net/unix/diag.c b/net/unix/diag.c index 0e0fda7..9d9e808 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -63,6 +63,41 @@ rtattr_failure: return -EMSGSIZE; } +static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb) +{ + struct sk_buff *skb; + u32 *buf; + int i; + + if (sk->sk_state == TCP_LISTEN) { + spin_lock(&sk->sk_receive_queue.lock); + buf = UNIX_DIAG_PUT(nlskb, UNIX_DIAG_ICONS, sk->sk_receive_queue.qlen); + i = 0; + skb_queue_walk(&sk->sk_receive_queue, skb) { + struct sock *req, *peer; + + req = skb->sk; + /* + * The state lock is outer for the same sk's + * queue lock. With the other's queue locked it's + * OK to lock the state. + */ + unix_state_lock_nested(req); + peer = unix_sk(req)->peer; + if (peer) + buf[i++] = sock_i_ino(peer); + unix_state_unlock(req); + } + spin_unlock(&sk->sk_receive_queue.lock); + } + + return 0; + +rtattr_failure: + spin_unlock(&sk->sk_receive_queue.lock); + return -EMSGSIZE; +} + static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req, u32 pid, u32 seq, u32 flags, int sk_ino) { @@ -93,6 +128,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r sk_diag_dump_peer(sk, skb)) goto nlmsg_failure; + if ((req->udiag_show & UDIAG_SHOW_ICONS) && + sk_diag_dump_icons(sk, skb)) + goto nlmsg_failure; + nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len;