Skip to content

Commit 545a682

Browse files
committed
Merge branch 'unix-Show-number-of-scm-files-in-fdinfo'
Kirill Tkhai says: ==================== unix: Show number of scm files in fdinfo v2: Pass correct argument to locked in patch [2/2]. 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 a reference counter on a resourse. $cat /proc/[pid]/fdinfo/[unix_sk_fd] | grep scm_fds scm_fds: 1 ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 6b8350a + 3c32da1 commit 545a682

File tree

4 files changed

+69
-5
lines changed

4 files changed

+69
-5
lines changed

include/linux/net.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ struct proto_ops {
171171
int (*compat_getsockopt)(struct socket *sock, int level,
172172
int optname, char __user *optval, int __user *optlen);
173173
#endif
174+
void (*show_fdinfo)(struct seq_file *m, struct socket *sock);
174175
int (*sendmsg) (struct socket *sock, struct msghdr *m,
175176
size_t total_len);
176177
/* Notes for implementing recvmsg:

include/net/af_unix.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ struct unix_skb_parms {
4141
u32 consumed;
4242
} __randomize_layout;
4343

44+
struct scm_stat {
45+
u32 nr_fds;
46+
};
47+
4448
#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
4549

4650
#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock)
@@ -65,6 +69,7 @@ struct unix_sock {
6569
#define UNIX_GC_MAYBE_CYCLE 1
6670
struct socket_wq peer_wq;
6771
wait_queue_entry_t peer_wake;
72+
struct scm_stat scm_stat;
6873
};
6974

7075
static inline struct unix_sock *unix_sk(const struct sock *sk)

net/socket.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ static ssize_t sock_sendpage(struct file *file, struct page *page,
128128
static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
129129
struct pipe_inode_info *pipe, size_t len,
130130
unsigned int flags);
131+
static void sock_show_fdinfo(struct seq_file *m, struct file *f);
131132

132133
/*
133134
* 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 = {
150151
.sendpage = sock_sendpage,
151152
.splice_write = generic_splice_sendpage,
152153
.splice_read = sock_splice_read,
154+
#ifdef CONFIG_PROC_FS
155+
.show_fdinfo = sock_show_fdinfo,
156+
#endif
153157
};
154158

155159
/*
@@ -993,6 +997,14 @@ static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from)
993997
return res;
994998
}
995999

1000+
static void sock_show_fdinfo(struct seq_file *m, struct file *f)
1001+
{
1002+
struct socket *sock = f->private_data;
1003+
1004+
if (sock->ops->show_fdinfo)
1005+
sock->ops->show_fdinfo(m, sock);
1006+
}
1007+
9961008
/*
9971009
* Atomic setting of ioctl hooks to avoid race
9981010
* with module unload.

net/unix/af_unix.c

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,16 @@ static int unix_set_peek_off(struct sock *sk, int val)
676676
return 0;
677677
}
678678

679+
static void unix_show_fdinfo(struct seq_file *m, struct socket *sock)
680+
{
681+
struct sock *sk = sock->sk;
682+
struct unix_sock *u;
683+
684+
if (sk) {
685+
u = unix_sk(sock->sk);
686+
seq_printf(m, "scm_fds: %u\n", READ_ONCE(u->scm_stat.nr_fds));
687+
}
688+
}
679689

680690
static const struct proto_ops unix_stream_ops = {
681691
.family = PF_UNIX,
@@ -701,6 +711,7 @@ static const struct proto_ops unix_stream_ops = {
701711
.sendpage = unix_stream_sendpage,
702712
.splice_read = unix_stream_splice_read,
703713
.set_peek_off = unix_set_peek_off,
714+
.show_fdinfo = unix_show_fdinfo,
704715
};
705716

706717
static const struct proto_ops unix_dgram_ops = {
@@ -726,6 +737,7 @@ static const struct proto_ops unix_dgram_ops = {
726737
.mmap = sock_no_mmap,
727738
.sendpage = sock_no_sendpage,
728739
.set_peek_off = unix_set_peek_off,
740+
.show_fdinfo = unix_show_fdinfo,
729741
};
730742

731743
static const struct proto_ops unix_seqpacket_ops = {
@@ -751,6 +763,7 @@ static const struct proto_ops unix_seqpacket_ops = {
751763
.mmap = sock_no_mmap,
752764
.sendpage = sock_no_sendpage,
753765
.set_peek_off = unix_set_peek_off,
766+
.show_fdinfo = unix_show_fdinfo,
754767
};
755768

756769
static struct proto unix_proto = {
@@ -788,6 +801,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern)
788801
mutex_init(&u->bindlock); /* single task binding lock */
789802
init_waitqueue_head(&u->peer_wait);
790803
init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
804+
memset(&u->scm_stat, 0, sizeof(struct scm_stat));
791805
unix_insert_socket(unix_sockets_unbound(sk), sk);
792806
out:
793807
if (sk == NULL)
@@ -1572,6 +1586,28 @@ static bool unix_skb_scm_eq(struct sk_buff *skb,
15721586
unix_secdata_eq(scm, skb);
15731587
}
15741588

1589+
static void scm_stat_add(struct sock *sk, struct sk_buff *skb)
1590+
{
1591+
struct scm_fp_list *fp = UNIXCB(skb).fp;
1592+
struct unix_sock *u = unix_sk(sk);
1593+
1594+
lockdep_assert_held(&sk->sk_receive_queue.lock);
1595+
1596+
if (unlikely(fp && fp->count))
1597+
u->scm_stat.nr_fds += fp->count;
1598+
}
1599+
1600+
static void scm_stat_del(struct sock *sk, struct sk_buff *skb)
1601+
{
1602+
struct scm_fp_list *fp = UNIXCB(skb).fp;
1603+
struct unix_sock *u = unix_sk(sk);
1604+
1605+
lockdep_assert_held(&sk->sk_receive_queue.lock);
1606+
1607+
if (unlikely(fp && fp->count))
1608+
u->scm_stat.nr_fds -= fp->count;
1609+
}
1610+
15751611
/*
15761612
* Send AF_UNIX data.
15771613
*/
@@ -1757,7 +1793,10 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
17571793
if (sock_flag(other, SOCK_RCVTSTAMP))
17581794
__net_timestamp(skb);
17591795
maybe_add_creds(skb, sock, other);
1760-
skb_queue_tail(&other->sk_receive_queue, skb);
1796+
spin_lock(&other->sk_receive_queue.lock);
1797+
scm_stat_add(other, skb);
1798+
__skb_queue_tail(&other->sk_receive_queue, skb);
1799+
spin_unlock(&other->sk_receive_queue.lock);
17611800
unix_state_unlock(other);
17621801
other->sk_data_ready(other);
17631802
sock_put(other);
@@ -1859,7 +1898,10 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
18591898
goto pipe_err_free;
18601899

18611900
maybe_add_creds(skb, sock, other);
1862-
skb_queue_tail(&other->sk_receive_queue, skb);
1901+
spin_lock(&other->sk_receive_queue.lock);
1902+
scm_stat_add(other, skb);
1903+
__skb_queue_tail(&other->sk_receive_queue, skb);
1904+
spin_unlock(&other->sk_receive_queue.lock);
18631905
unix_state_unlock(other);
18641906
other->sk_data_ready(other);
18651907
sent += size;
@@ -2058,8 +2100,8 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
20582100
mutex_lock(&u->iolock);
20592101

20602102
skip = sk_peek_offset(sk, flags);
2061-
skb = __skb_try_recv_datagram(sk, flags, NULL, &skip, &err,
2062-
&last);
2103+
skb = __skb_try_recv_datagram(sk, flags, scm_stat_del,
2104+
&skip, &err, &last);
20632105
if (skb)
20642106
break;
20652107

@@ -2353,8 +2395,12 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,
23532395

23542396
sk_peek_offset_bwd(sk, chunk);
23552397

2356-
if (UNIXCB(skb).fp)
2398+
if (UNIXCB(skb).fp) {
2399+
spin_lock(&sk->sk_receive_queue.lock);
2400+
scm_stat_del(sk, skb);
2401+
spin_unlock(&sk->sk_receive_queue.lock);
23572402
unix_detach_fds(&scm, skb);
2403+
}
23582404

23592405
if (unix_skb_len(skb))
23602406
break;

0 commit comments

Comments
 (0)