Netdev Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 0/2] unix: Show number of scm files in fdinfo
@ 2019-11-07 12:14 Kirill Tkhai
  2019-11-07 12:14 ` [PATCH 1/2] net: Allow to show socket-specific information in /proc/[pid]/fdinfo/[fd] Kirill Tkhai
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Kirill Tkhai @ 2019-11-07 12:14 UTC (permalink / raw)
  To: davem, pankaj.laxminarayan.bharadiya, keescook, viro, hare, tglx,
	ktkhai, edumazet, arnd, axboe, netdev

Unix sockets like a block box. You never know what is pending there:
there may be a file descriptor holding a mount or a block device,
or there may be whole universes with namespaces, sockets with receive
queues full of sockets etc.

The patchset makes number of pending scm files be visible in fdinfo.
This may be useful to determine, that socket should be investigated
or which task should be killed to put reference counter on a resourse.

---

Kirill Tkhai (2):
      net: Allow to show socket-specific information in /proc/[pid]/fdinfo/[fd]
      unix: Show number of pending scm files of receive queue in fdinfo


 include/linux/net.h   |    1 +
 include/net/af_unix.h |    5 ++++
 net/socket.c          |   12 +++++++++++
 net/unix/af_unix.c    |   56 +++++++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 69 insertions(+), 5 deletions(-)

--
Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] net: Allow to show socket-specific information in /proc/[pid]/fdinfo/[fd]
  2019-11-07 12:14 [PATCH 0/2] unix: Show number of scm files in fdinfo Kirill Tkhai
@ 2019-11-07 12:14 ` Kirill Tkhai
  2019-11-07 12:14 ` [PATCH 2/2] unix: Show number of pending scm files of receive queue in fdinfo Kirill Tkhai
  2019-11-08 19:30 ` [PATCH 0/2] unix: Show number of scm files " David Miller
  2 siblings, 0 replies; 5+ messages in thread
From: Kirill Tkhai @ 2019-11-07 12:14 UTC (permalink / raw)
  To: davem, pankaj.laxminarayan.bharadiya, keescook, viro, hare, tglx,
	ktkhai, edumazet, arnd, axboe, netdev

This adds .show_fdinfo to socket_file_ops, so protocols will be able
to print their specific data in fdinfo.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 include/linux/net.h |    1 +
 net/socket.c        |   12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/include/linux/net.h b/include/linux/net.h
index 9cafb5f353a9..6451425e828f 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -171,6 +171,7 @@ struct proto_ops {
 	int		(*compat_getsockopt)(struct socket *sock, int level,
 				      int optname, char __user *optval, int __user *optlen);
 #endif
+	void		(*show_fdinfo)(struct seq_file *m, struct socket *sock);
 	int		(*sendmsg)   (struct socket *sock, struct msghdr *m,
 				      size_t total_len);
 	/* Notes for implementing recvmsg:
diff --git a/net/socket.c b/net/socket.c
index 54afceebd7a1..29c5ed4e7d85 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -128,6 +128,7 @@ static ssize_t sock_sendpage(struct file *file, struct page *page,
 static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
 				struct pipe_inode_info *pipe, size_t len,
 				unsigned int flags);
+static void sock_show_fdinfo(struct seq_file *m, struct file *f);
 
 /*
  *	Socket files have a set of 'special' operations as well as the generic file ones. These don't appear
@@ -150,6 +151,9 @@ static const struct file_operations socket_file_ops = {
 	.sendpage =	sock_sendpage,
 	.splice_write = generic_splice_sendpage,
 	.splice_read =	sock_splice_read,
+#ifdef CONFIG_PROC_FS
+	.show_fdinfo =	sock_show_fdinfo,
+#endif
 };
 
 /*
@@ -992,6 +996,14 @@ static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from)
 	return res;
 }
 
+static void sock_show_fdinfo(struct seq_file *m, struct file *f)
+{
+	struct socket *sock = f->private_data;
+
+	if (sock->ops->show_fdinfo)
+		sock->ops->show_fdinfo(m, sock);
+}
+
 /*
  * Atomic setting of ioctl hooks to avoid race
  * with module unload.



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/2] unix: Show number of pending scm files of receive queue in fdinfo
  2019-11-07 12:14 [PATCH 0/2] unix: Show number of scm files in fdinfo Kirill Tkhai
  2019-11-07 12:14 ` [PATCH 1/2] net: Allow to show socket-specific information in /proc/[pid]/fdinfo/[fd] Kirill Tkhai
@ 2019-11-07 12:14 ` Kirill Tkhai
  2019-11-08 19:30 ` [PATCH 0/2] unix: Show number of scm files " David Miller
  2 siblings, 0 replies; 5+ messages in thread
From: Kirill Tkhai @ 2019-11-07 12:14 UTC (permalink / raw)
  To: davem, pankaj.laxminarayan.bharadiya, keescook, viro, hare, tglx,
	ktkhai, edumazet, arnd, axboe, netdev

Unix sockets like a block box. You never know what is stored there:
there may be a file descriptor holding a mount or a block device,
or there may be whole universes with namespaces, sockets with receive
queues full of sockets etc.

The patch adds a little debug and accounts number of files (not recursive),
which is in receive queue of a unix socket. Sometimes this is useful
to determine, that socket should be investigated or which task should
be killed to put reference counter on a resourse.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 include/net/af_unix.h |    5 ++++
 net/unix/af_unix.c    |   56 +++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 3426d6dacc45..17e10fba2152 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -41,6 +41,10 @@ struct unix_skb_parms {
 	u32			consumed;
 } __randomize_layout;
 
+struct scm_stat {
+	u32 nr_fds;
+};
+
 #define UNIXCB(skb)	(*(struct unix_skb_parms *)&((skb)->cb))
 
 #define unix_state_lock(s)	spin_lock(&unix_sk(s)->lock)
@@ -65,6 +69,7 @@ struct unix_sock {
 #define UNIX_GC_MAYBE_CYCLE	1
 	struct socket_wq	peer_wq;
 	wait_queue_entry_t	peer_wake;
+	struct scm_stat		scm_stat;
 };
 
 static inline struct unix_sock *unix_sk(const struct sock *sk)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index f0a074356012..991f66057718 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -676,6 +676,16 @@ static int unix_set_peek_off(struct sock *sk, int val)
 	return 0;
 }
 
+static void unix_show_fdinfo(struct seq_file *m, struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct unix_sock *u;
+
+	if (sk) {
+		u = unix_sk(sock->sk);
+		seq_printf(m, "scm_fds: %u\n", READ_ONCE(u->scm_stat.nr_fds));
+	}
+}
 
 static const struct proto_ops unix_stream_ops = {
 	.family =	PF_UNIX,
@@ -701,6 +711,7 @@ static const struct proto_ops unix_stream_ops = {
 	.sendpage =	unix_stream_sendpage,
 	.splice_read =	unix_stream_splice_read,
 	.set_peek_off =	unix_set_peek_off,
+	.show_fdinfo=	unix_show_fdinfo,
 };
 
 static const struct proto_ops unix_dgram_ops = {
@@ -726,6 +737,7 @@ static const struct proto_ops unix_dgram_ops = {
 	.mmap =		sock_no_mmap,
 	.sendpage =	sock_no_sendpage,
 	.set_peek_off =	unix_set_peek_off,
+	.show_fdinfo =	unix_show_fdinfo,
 };
 
 static const struct proto_ops unix_seqpacket_ops = {
@@ -751,6 +763,7 @@ static const struct proto_ops unix_seqpacket_ops = {
 	.mmap =		sock_no_mmap,
 	.sendpage =	sock_no_sendpage,
 	.set_peek_off =	unix_set_peek_off,
+	.show_fdinfo =	unix_show_fdinfo,
 };
 
 static struct proto unix_proto = {
@@ -788,6 +801,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern)
 	mutex_init(&u->bindlock); /* single task binding lock */
 	init_waitqueue_head(&u->peer_wait);
 	init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
+	memset(&u->scm_stat, 0, sizeof(struct scm_stat));
 	unix_insert_socket(unix_sockets_unbound(sk), sk);
 out:
 	if (sk == NULL)
@@ -1572,6 +1586,28 @@ static bool unix_skb_scm_eq(struct sk_buff *skb,
 	       unix_secdata_eq(scm, skb);
 }
 
+static void scm_stat_add(struct sock *sk, struct sk_buff *skb)
+{
+	struct scm_fp_list *fp = UNIXCB(skb).fp;
+	struct unix_sock *u = unix_sk(sk);
+
+	lockdep_assert_held(sk->sk_receive_queue.lock);
+
+	if (unlikely(fp && fp->count))
+		u->scm_stat.nr_fds += fp->count;
+}
+
+static void scm_stat_del(struct sock *sk, struct sk_buff *skb)
+{
+	struct scm_fp_list *fp = UNIXCB(skb).fp;
+	struct unix_sock *u = unix_sk(sk);
+
+	lockdep_assert_held(sk->sk_receive_queue.lock);
+
+	if (unlikely(fp && fp->count))
+		u->scm_stat.nr_fds -= fp->count;
+}
+
 /*
  *	Send AF_UNIX data.
  */
@@ -1757,7 +1793,10 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 	if (sock_flag(other, SOCK_RCVTSTAMP))
 		__net_timestamp(skb);
 	maybe_add_creds(skb, sock, other);
-	skb_queue_tail(&other->sk_receive_queue, skb);
+	spin_lock(&other->sk_receive_queue.lock);
+	scm_stat_add(other, skb);
+	__skb_queue_tail(&other->sk_receive_queue, skb);
+	spin_unlock(&other->sk_receive_queue.lock);
 	unix_state_unlock(other);
 	other->sk_data_ready(other);
 	sock_put(other);
@@ -1859,7 +1898,10 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 			goto pipe_err_free;
 
 		maybe_add_creds(skb, sock, other);
-		skb_queue_tail(&other->sk_receive_queue, skb);
+		spin_lock(&other->sk_receive_queue.lock);
+		scm_stat_add(other, skb);
+		__skb_queue_tail(&other->sk_receive_queue, skb);
+		spin_unlock(&other->sk_receive_queue.lock);
 		unix_state_unlock(other);
 		other->sk_data_ready(other);
 		sent += size;
@@ -2058,8 +2100,8 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
 		mutex_lock(&u->iolock);
 
 		skip = sk_peek_offset(sk, flags);
-		skb = __skb_try_recv_datagram(sk, flags, NULL, &skip, &err,
-					      &last);
+		skb = __skb_try_recv_datagram(sk, flags, scm_stat_del,
+					      &skip, &err, &last);
 		if (skb)
 			break;
 
@@ -2353,8 +2395,12 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,
 
 			sk_peek_offset_bwd(sk, chunk);
 
-			if (UNIXCB(skb).fp)
+			if (UNIXCB(skb).fp) {
+				spin_lock(&sk->sk_receive_queue.lock);
+				scm_stat_del(sk, skb);
+				spin_unlock(&sk->sk_receive_queue.lock);
 				unix_detach_fds(&scm, skb);
+			}
 
 			if (unix_skb_len(skb))
 				break;



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] unix: Show number of scm files in fdinfo
  2019-11-07 12:14 [PATCH 0/2] unix: Show number of scm files in fdinfo Kirill Tkhai
  2019-11-07 12:14 ` [PATCH 1/2] net: Allow to show socket-specific information in /proc/[pid]/fdinfo/[fd] Kirill Tkhai
  2019-11-07 12:14 ` [PATCH 2/2] unix: Show number of pending scm files of receive queue in fdinfo Kirill Tkhai
@ 2019-11-08 19:30 ` " David Miller
  2019-11-08 23:15   ` Jens Axboe
  2 siblings, 1 reply; 5+ messages in thread
From: David Miller @ 2019-11-08 19:30 UTC (permalink / raw)
  To: ktkhai
  Cc: pankaj.laxminarayan.bharadiya, keescook, viro, hare, tglx,
	edumazet, arnd, axboe, netdev

From: Kirill Tkhai <ktkhai@virtuozzo.com>
Date: Thu, 07 Nov 2019 15:14:15 +0300

> Unix sockets like a block box. You never know what is pending there:
> there may be a file descriptor holding a mount or a block device,
> or there may be whole universes with namespaces, sockets with receive
> queues full of sockets etc.
> 
> The patchset makes number of pending scm files be visible in fdinfo.
> This may be useful to determine, that socket should be investigated
> or which task should be killed to put reference counter on a resourse.

This doesn't even compile:

net/unix/af_unix.c: In function ‘scm_stat_add’:
./include/linux/lockdep.h:365:52: error: invalid type argument of ‘->’ (have ‘spinlock_t’ {aka ‘struct spinlock’})
 #define lockdep_is_held(lock)  lock_is_held(&(lock)->dep_map)
                                                    ^~
./include/asm-generic/bug.h:113:25: note: in definition of macro ‘WARN_ON’
  int __ret_warn_on = !!(condition);    \
                         ^~~~~~~~~
./include/linux/lockdep.h:391:27: note: in expansion of macro ‘lockdep_is_held’
   WARN_ON(debug_locks && !lockdep_is_held(l)); \
                           ^~~~~~~~~~~~~~~
net/unix/af_unix.c:1582:2: note: in expansion of macro ‘lockdep_assert_held’
  lockdep_assert_held(sk->sk_receive_queue.lock);
  ^~~~~~~~~~~~~~~~~~~
net/unix/af_unix.c: In function ‘scm_stat_del’:
./include/linux/lockdep.h:365:52: error: invalid type argument of ‘->’ (have ‘spinlock_t’ {aka ‘struct spinlock’})
 #define lockdep_is_held(lock)  lock_is_held(&(lock)->dep_map)
                                                    ^~
./include/asm-generic/bug.h:113:25: note: in definition of macro ‘WARN_ON’
  int __ret_warn_on = !!(condition);    \
                         ^~~~~~~~~
./include/linux/lockdep.h:391:27: note: in expansion of macro ‘lockdep_is_held’
   WARN_ON(debug_locks && !lockdep_is_held(l)); \
                           ^~~~~~~~~~~~~~~
net/unix/af_unix.c:1593:2: note: in expansion of macro ‘lockdep_assert_held’
  lockdep_assert_held(sk->sk_receive_queue.lock);
  ^~~~~~~~~~~~~~~~~~~
make[2]: *** [scripts/Makefile.build:266: net/unix/af_unix.o] Error 1
make[1]: *** [scripts/Makefile.build:509: net/unix] Error 2
make[1]: *** Waiting for unfinished jobs....

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] unix: Show number of scm files in fdinfo
  2019-11-08 19:30 ` [PATCH 0/2] unix: Show number of scm files " David Miller
@ 2019-11-08 23:15   ` Jens Axboe
  0 siblings, 0 replies; 5+ messages in thread
From: Jens Axboe @ 2019-11-08 23:15 UTC (permalink / raw)
  To: David Miller, ktkhai
  Cc: pankaj.laxminarayan.bharadiya, keescook, viro, hare, tglx,
	edumazet, arnd, netdev

On 11/8/19 12:30 PM, David Miller wrote:
> From: Kirill Tkhai <ktkhai@virtuozzo.com>
> Date: Thu, 07 Nov 2019 15:14:15 +0300
> 
>> Unix sockets like a block box. You never know what is pending there:
>> there may be a file descriptor holding a mount or a block device,
>> or there may be whole universes with namespaces, sockets with receive
>> queues full of sockets etc.
>>
>> The patchset makes number of pending scm files be visible in fdinfo.
>> This may be useful to determine, that socket should be investigated
>> or which task should be killed to put reference counter on a resourse.
> 
> This doesn't even compile:
> 
> net/unix/af_unix.c: In function ‘scm_stat_add’:
> ./include/linux/lockdep.h:365:52: error: invalid type argument of ‘->’ (have ‘spinlock_t’ {aka ‘struct spinlock’})
>   #define lockdep_is_held(lock)  lock_is_held(&(lock)->dep_map)

Quick guess is a missing & on those locks...

But in any case, the feature looks really useful, also for io_uring which
puts all its registered files in the skb. I'll give it a tester here.

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, back to index

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-07 12:14 [PATCH 0/2] unix: Show number of scm files in fdinfo Kirill Tkhai
2019-11-07 12:14 ` [PATCH 1/2] net: Allow to show socket-specific information in /proc/[pid]/fdinfo/[fd] Kirill Tkhai
2019-11-07 12:14 ` [PATCH 2/2] unix: Show number of pending scm files of receive queue in fdinfo Kirill Tkhai
2019-11-08 19:30 ` [PATCH 0/2] unix: Show number of scm files " David Miller
2019-11-08 23:15   ` Jens Axboe

Netdev Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/netdev/0 netdev/git/0.git
	git clone --mirror https://lore.kernel.org/netdev/1 netdev/git/1.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 netdev netdev/ https://lore.kernel.org/netdev \
		netdev@vger.kernel.org
	public-inbox-index netdev

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.netdev


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git