From 502cc4207c2a50f3e10ca0c41c1e42217a1956fa Mon Sep 17 00:00:00 2001 From: msaitoh Date: Fri, 20 Jul 2018 08:26:25 +0000 Subject: [PATCH] Add "show socket" command written by Hiroki SUENAGA. It prints usage of system's socket buffers. --- share/man/man4/ddb.4 | 23 ++++- sys/ddb/db_command.c | 18 +++- sys/kern/uipc_socket2.c | 199 +++++++++++++++++++++++++++++++++++++++- sys/sys/socketvar.h | 6 +- 4 files changed, 239 insertions(+), 7 deletions(-) diff --git a/share/man/man4/ddb.4 b/share/man/man4/ddb.4 index dc3abb577142..c9458653c725 100644 --- a/share/man/man4/ddb.4 +++ b/share/man/man4/ddb.4 @@ -1,4 +1,4 @@ -.\" $NetBSD: ddb.4,v 1.179 2018/07/17 05:52:07 msaitoh Exp $ +.\" $NetBSD: ddb.4,v 1.180 2018/07/20 08:26:25 msaitoh Exp $ .\" .\" Copyright (c) 1997 - 2009 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -56,7 +56,7 @@ .\" any improvements or extensions that they make and grant Carnegie Mellon .\" the rights to redistribute these changes. .\" -.Dd July 17, 2018 +.Dd July 20, 2018 .Dt DDB 4 .Os .Sh NAME @@ -750,6 +750,25 @@ of LWPs will be shown. If the run queue has LWPs, but the sched_whichqs bit is not set for that queue, the queue index will be prefixed with a .Sq \&! . +.It Ic show socket Ns Oo Cm /ampv Oc +Print usage of system's socket buffers. +By default, empty socket isn't printed. +.Bl -tag -width 4n -compact +.It Cm /a +Print all processes which use the socket. +.It Cm /m +Print mbuf chain in the socket buffer. +.It Cm /p +By default, a process which use the socket is printed (only one socket). +If +.Cm /p +is specified, the process isn't printed. +.It Cm /v +Verbose mode. +If +.Cm /v +is specified, all sockets are printed. +.El .It Ic show uvmexp Print a selection of UVM counters and statistics. .It Ic show kernhist Oo Ar addr Oc diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c index 4444d46b8308..c49a66317d3c 100644 --- a/sys/ddb/db_command.c +++ b/sys/ddb/db_command.c @@ -1,4 +1,4 @@ -/* $NetBSD: db_command.c,v 1.153 2018/03/19 08:41:21 ozaki-r Exp $ */ +/* $NetBSD: db_command.c,v 1.154 2018/07/20 08:26:25 msaitoh Exp $ */ /* * Copyright (c) 1996, 1997, 1998, 1999, 2002, 2009 The NetBSD Foundation, Inc. @@ -60,7 +60,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: db_command.c,v 1.153 2018/03/19 08:41:21 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: db_command.c,v 1.154 2018/07/20 08:26:25 msaitoh Exp $"); #ifdef _KERNEL_OPT #include "opt_aio.h" @@ -89,6 +89,7 @@ __KERNEL_RCSID(0, "$NetBSD: db_command.c,v 1.153 2018/03/19 08:41:21 ozaki-r Exp #include #include #include +#include /*include queue macros*/ #include @@ -203,6 +204,7 @@ static void db_show_all_pages(db_expr_t, bool, db_expr_t, const char *); static void db_pool_print_cmd(db_expr_t, bool, db_expr_t, const char *); static void db_reboot_cmd(db_expr_t, bool, db_expr_t, const char *); static void db_sifting_cmd(db_expr_t, bool, db_expr_t, const char *); +static void db_socket_print_cmd(db_expr_t, bool, db_expr_t, const char *); static void db_stack_trace_cmd(db_expr_t, bool, db_expr_t, const char *); static void db_sync_cmd(db_expr_t, bool, db_expr_t, const char *); static void db_whatis_cmd(db_expr_t, bool, db_expr_t, const char *); @@ -257,6 +259,7 @@ static const struct db_command db_show_cmds[] = { "Print statistics of locks", NULL, NULL) }, { DDB_ADD_CMD("map", db_map_print_cmd, 0, "Print the vm_map at address.", "[/f] address",NULL) }, + { DDB_ADD_CMD("socket", db_socket_print_cmd, 0,NULL,NULL,NULL) }, { DDB_ADD_CMD("module", db_show_module_cmd, 0, "Print kernel modules", NULL, NULL) }, { DDB_ADD_CMD("mount", db_mount_print_cmd, 0, @@ -1211,6 +1214,17 @@ db_uvmexp_print_cmd(db_expr_t addr, bool have_addr, #endif } +/*ARGSUSED */ +static void +db_socket_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, + const char *modif) +{ + +#ifdef _KERNEL /* XXX CRASH(8) */ + socket_print(modif, db_printf); +#endif +} + #ifdef KERNHIST /*ARGSUSED*/ static void diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index 79204fbbb38b..3e081ba51d7d 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_socket2.c,v 1.130 2018/06/06 09:46:46 roy Exp $ */ +/* $NetBSD: uipc_socket2.c,v 1.131 2018/07/20 08:26:25 msaitoh Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -58,9 +58,10 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.130 2018/06/06 09:46:46 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.131 2018/07/20 08:26:25 msaitoh Exp $"); #ifdef _KERNEL_OPT +#include "opt_ddb.h" #include "opt_mbuftrace.h" #include "opt_sb_max.h" #endif @@ -81,6 +82,10 @@ __KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.130 2018/06/06 09:46:46 roy Exp $ #include #include +#ifdef DDB +#include +#endif + /* * Primitive routines for operating on sockets and socket buffers. * @@ -687,6 +692,7 @@ sbreserve(struct sockbuf *sb, u_long cc, struct socket *so) sb->sb_mbmax = min(cc * 2, sb_max); if (sb->sb_lowat > sb->sb_hiwat) sb->sb_lowat = sb->sb_hiwat; + return (1); } @@ -1541,3 +1547,192 @@ sowait(struct socket *so, bool catch_p, int timo) solockretry(so, lock); return error; } + +#ifdef DDB + +/* + * Currently, sofindproc() is used only from DDB. It could be used from others + * by using db_mutex_enter() + */ + +static inline int +db_mutex_enter(kmutex_t *mtx) +{ + extern int db_active; + int rv; + + if (!db_active) { + mutex_enter(mtx); + rv = 1; + } else + rv = mutex_tryenter(mtx); + + return rv; +} + +int +sofindproc(struct socket *so, int all, void (*pr)(const char *, ...)) +{ + proc_t *p; + filedesc_t *fdp; + fdtab_t *dt; + fdfile_t *ff; + file_t *fp = NULL; + int found = 0; + int i, t; + + if (so == NULL) + return 0; + + t = db_mutex_enter(proc_lock); + if (!t) { + pr("could not acquire proc_lock mutex\n"); + return 0; + } + PROCLIST_FOREACH(p, &allproc) { + if (p->p_stat == SIDL) + continue; + fdp = p->p_fd; + t = db_mutex_enter(&fdp->fd_lock); + if (!t) { + pr("could not acquire fd_lock mutex\n"); + continue; + } + dt = fdp->fd_dt; + for (i = 0; i < dt->dt_nfiles; i++) { + ff = dt->dt_ff[i]; + if (ff == NULL) + continue; + + fp = ff->ff_file; + if (fp == NULL) + continue; + + t = db_mutex_enter(&fp->f_lock); + if (!t) { + pr("could not acquire f_lock mutex\n"); + continue; + } + if ((struct socket *)fp->f_data != so) { + mutex_exit(&fp->f_lock); + continue; + } + found++; + if (pr) + pr("socket %p: owner %s(pid=%d)\n", + so, p->p_comm, p->p_pid); + mutex_exit(&fp->f_lock); + if (all == 0) + break; + } + mutex_exit(&fdp->fd_lock); + if (all == 0 && found != 0) + break; + } + mutex_exit(proc_lock); + + return found; +} + +void +socket_print(const char *modif, void (*pr)(const char *, ...)) +{ + file_t *fp; + struct socket *so; + struct sockbuf *sb_snd, *sb_rcv; + struct mbuf *m_rec, *m; + bool opt_v = false; + bool opt_m = false; + bool opt_a = false; + bool opt_p = false; + int nrecs, nmbufs; + char ch; + const char *family; + + while ( (ch = *(modif++)) != '\0') { + switch (ch) { + case 'v': + opt_v = true; + break; + case 'm': + opt_m = true; + break; + case 'a': + opt_a = true; + break; + case 'p': + opt_p = true; + break; + } + } + if (opt_v == false && pr) + (pr)("Ignore empty sockets. use /v to print all.\n"); + if (opt_p == true && pr) + (pr)("Don't search owner process.\n"); + + LIST_FOREACH(fp, &filehead, f_list) { + if (fp->f_type != DTYPE_SOCKET) + continue; + so = (struct socket *)fp->f_data; + if (so == NULL) + continue; + + if (so->so_proto->pr_domain->dom_family == AF_INET) + family = "INET"; +#ifdef INET6 + else if (so->so_proto->pr_domain->dom_family == AF_INET6) + family = "INET6"; +#endif + else if (so->so_proto->pr_domain->dom_family == pseudo_AF_KEY) + family = "KEY"; + else if (so->so_proto->pr_domain->dom_family == AF_ROUTE) + family = "ROUTE"; + else + continue; + + sb_snd = &so->so_snd; + sb_rcv = &so->so_rcv; + + if (opt_v != true && + sb_snd->sb_cc == 0 && sb_rcv->sb_cc == 0) + continue; + + pr("---SOCKET %p: type %s\n", so, family); + if (opt_p != true) + sofindproc(so, opt_a == true ? 1 : 0, pr); + pr("Send Buffer Bytes: %d [bytes]\n", sb_snd->sb_cc); + pr("Send Buffer mbufs:\n"); + m_rec = m = sb_snd->sb_mb; + nrecs = 0; + nmbufs = 0; + while (m_rec) { + nrecs++; + if (opt_m == true) + pr(" mbuf chain %p\n", m_rec); + while (m) { + nmbufs++; + m = m->m_next; + } + m_rec = m = m_rec->m_nextpkt; + } + pr(" Total %d records, %d mbufs.\n", nrecs, nmbufs); + + pr("Recv Buffer Usage: %d [bytes]\n", sb_rcv->sb_cc); + pr("Recv Buffer mbufs:\n"); + m_rec = m = sb_rcv->sb_mb; + nrecs = 0; + nmbufs = 0; + while (m_rec) { + nrecs++; + if (opt_m == true) + pr(" mbuf chain %p\n", m_rec); + while (m) { + nmbufs++; + m = m->m_next; + } + m_rec = m = m_rec->m_nextpkt; + } + pr(" Total %d records, %d mbufs.\n", nrecs, nmbufs); + } +} +#endif /* DDB */ diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index 7373ab3143c7..7d641e4605db 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: socketvar.h,v 1.156 2018/06/06 09:46:46 roy Exp $ */ +/* $NetBSD: socketvar.h,v 1.157 2018/07/20 08:26:25 msaitoh Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -575,6 +575,10 @@ SYSCTL_DECL(_net_inet_accf); #endif void accept_filter_init(void); #endif +#ifdef DDB +int sofindproc(struct socket *so, int all, void (*pr)(const char *, ...)); +void socket_print(const char *modif, void (*pr)(const char *, ...)); +#endif #endif /* _KERNEL */