1328970deSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2fa60ce2cSMasahiro Yamada /*
32309e9e0SSunil Mushran * netdebug.c
42309e9e0SSunil Mushran *
52309e9e0SSunil Mushran * debug functionality for o2net
62309e9e0SSunil Mushran *
72309e9e0SSunil Mushran * Copyright (C) 2005, 2008 Oracle. All rights reserved.
82309e9e0SSunil Mushran */
92309e9e0SSunil Mushran
102309e9e0SSunil Mushran #ifdef CONFIG_DEBUG_FS
112309e9e0SSunil Mushran
122309e9e0SSunil Mushran #include <linux/module.h>
132309e9e0SSunil Mushran #include <linux/types.h>
142309e9e0SSunil Mushran #include <linux/slab.h>
152309e9e0SSunil Mushran #include <linux/idr.h>
162309e9e0SSunil Mushran #include <linux/kref.h>
172309e9e0SSunil Mushran #include <linux/seq_file.h>
182309e9e0SSunil Mushran #include <linux/debugfs.h>
192309e9e0SSunil Mushran
202309e9e0SSunil Mushran #include <linux/uaccess.h>
212309e9e0SSunil Mushran
222309e9e0SSunil Mushran #include "tcp.h"
232309e9e0SSunil Mushran #include "nodemanager.h"
242309e9e0SSunil Mushran #define MLOG_MASK_PREFIX ML_TCP
252309e9e0SSunil Mushran #include "masklog.h"
262309e9e0SSunil Mushran
272309e9e0SSunil Mushran #include "tcp_internal.h"
282309e9e0SSunil Mushran
292309e9e0SSunil Mushran #define O2NET_DEBUG_DIR "o2net"
302309e9e0SSunil Mushran #define SC_DEBUG_NAME "sock_containers"
312309e9e0SSunil Mushran #define NST_DEBUG_NAME "send_tracking"
32db02754cSSunil Mushran #define STATS_DEBUG_NAME "stats"
333ba169ccSSunil Mushran #define NODES_DEBUG_NAME "connected_nodes"
34db02754cSSunil Mushran
35db02754cSSunil Mushran #define SHOW_SOCK_CONTAINERS 0
36db02754cSSunil Mushran #define SHOW_SOCK_STATS 1
372309e9e0SSunil Mushran
382309e9e0SSunil Mushran static struct dentry *o2net_dentry;
392309e9e0SSunil Mushran
402309e9e0SSunil Mushran static DEFINE_SPINLOCK(o2net_debug_lock);
412309e9e0SSunil Mushran
422309e9e0SSunil Mushran static LIST_HEAD(sock_containers);
432309e9e0SSunil Mushran static LIST_HEAD(send_tracking);
442309e9e0SSunil Mushran
o2net_debug_add_nst(struct o2net_send_tracking * nst)452309e9e0SSunil Mushran void o2net_debug_add_nst(struct o2net_send_tracking *nst)
462309e9e0SSunil Mushran {
47*84c10951SChengfeng Ye spin_lock_bh(&o2net_debug_lock);
482309e9e0SSunil Mushran list_add(&nst->st_net_debug_item, &send_tracking);
49*84c10951SChengfeng Ye spin_unlock_bh(&o2net_debug_lock);
502309e9e0SSunil Mushran }
512309e9e0SSunil Mushran
o2net_debug_del_nst(struct o2net_send_tracking * nst)522309e9e0SSunil Mushran void o2net_debug_del_nst(struct o2net_send_tracking *nst)
532309e9e0SSunil Mushran {
54*84c10951SChengfeng Ye spin_lock_bh(&o2net_debug_lock);
552309e9e0SSunil Mushran if (!list_empty(&nst->st_net_debug_item))
562309e9e0SSunil Mushran list_del_init(&nst->st_net_debug_item);
57*84c10951SChengfeng Ye spin_unlock_bh(&o2net_debug_lock);
582309e9e0SSunil Mushran }
592309e9e0SSunil Mushran
602309e9e0SSunil Mushran static struct o2net_send_tracking
next_nst(struct o2net_send_tracking * nst_start)612309e9e0SSunil Mushran *next_nst(struct o2net_send_tracking *nst_start)
622309e9e0SSunil Mushran {
632309e9e0SSunil Mushran struct o2net_send_tracking *nst, *ret = NULL;
642309e9e0SSunil Mushran
652309e9e0SSunil Mushran assert_spin_locked(&o2net_debug_lock);
662309e9e0SSunil Mushran
672309e9e0SSunil Mushran list_for_each_entry(nst, &nst_start->st_net_debug_item,
682309e9e0SSunil Mushran st_net_debug_item) {
692309e9e0SSunil Mushran /* discover the head of the list */
702309e9e0SSunil Mushran if (&nst->st_net_debug_item == &send_tracking)
712309e9e0SSunil Mushran break;
722309e9e0SSunil Mushran
732309e9e0SSunil Mushran /* use st_task to detect real nsts in the list */
742309e9e0SSunil Mushran if (nst->st_task != NULL) {
752309e9e0SSunil Mushran ret = nst;
762309e9e0SSunil Mushran break;
772309e9e0SSunil Mushran }
782309e9e0SSunil Mushran }
792309e9e0SSunil Mushran
802309e9e0SSunil Mushran return ret;
812309e9e0SSunil Mushran }
822309e9e0SSunil Mushran
nst_seq_start(struct seq_file * seq,loff_t * pos)832309e9e0SSunil Mushran static void *nst_seq_start(struct seq_file *seq, loff_t *pos)
842309e9e0SSunil Mushran {
852309e9e0SSunil Mushran struct o2net_send_tracking *nst, *dummy_nst = seq->private;
862309e9e0SSunil Mushran
87*84c10951SChengfeng Ye spin_lock_bh(&o2net_debug_lock);
882309e9e0SSunil Mushran nst = next_nst(dummy_nst);
89*84c10951SChengfeng Ye spin_unlock_bh(&o2net_debug_lock);
902309e9e0SSunil Mushran
912309e9e0SSunil Mushran return nst;
922309e9e0SSunil Mushran }
932309e9e0SSunil Mushran
nst_seq_next(struct seq_file * seq,void * v,loff_t * pos)942309e9e0SSunil Mushran static void *nst_seq_next(struct seq_file *seq, void *v, loff_t *pos)
952309e9e0SSunil Mushran {
962309e9e0SSunil Mushran struct o2net_send_tracking *nst, *dummy_nst = seq->private;
972309e9e0SSunil Mushran
98*84c10951SChengfeng Ye spin_lock_bh(&o2net_debug_lock);
992309e9e0SSunil Mushran nst = next_nst(dummy_nst);
1002309e9e0SSunil Mushran list_del_init(&dummy_nst->st_net_debug_item);
1012309e9e0SSunil Mushran if (nst)
1022309e9e0SSunil Mushran list_add(&dummy_nst->st_net_debug_item,
1032309e9e0SSunil Mushran &nst->st_net_debug_item);
104*84c10951SChengfeng Ye spin_unlock_bh(&o2net_debug_lock);
1052309e9e0SSunil Mushran
1062309e9e0SSunil Mushran return nst; /* unused, just needs to be null when done */
1072309e9e0SSunil Mushran }
1082309e9e0SSunil Mushran
nst_seq_show(struct seq_file * seq,void * v)1092309e9e0SSunil Mushran static int nst_seq_show(struct seq_file *seq, void *v)
1102309e9e0SSunil Mushran {
1112309e9e0SSunil Mushran struct o2net_send_tracking *nst, *dummy_nst = seq->private;
1123f9c14faSSunil Mushran ktime_t now;
1133f9c14faSSunil Mushran s64 sock, send, status;
1142309e9e0SSunil Mushran
115*84c10951SChengfeng Ye spin_lock_bh(&o2net_debug_lock);
1162309e9e0SSunil Mushran nst = next_nst(dummy_nst);
117cc548166SDan Carpenter if (!nst)
118cc548166SDan Carpenter goto out;
1192309e9e0SSunil Mushran
1203f9c14faSSunil Mushran now = ktime_get();
1213f9c14faSSunil Mushran sock = ktime_to_us(ktime_sub(now, nst->st_sock_time));
1223f9c14faSSunil Mushran send = ktime_to_us(ktime_sub(now, nst->st_send_time));
1233f9c14faSSunil Mushran status = ktime_to_us(ktime_sub(now, nst->st_status_time));
1243f9c14faSSunil Mushran
1252309e9e0SSunil Mushran /* get_task_comm isn't exported. oh well. */
1262309e9e0SSunil Mushran seq_printf(seq, "%p:\n"
1272309e9e0SSunil Mushran " pid: %lu\n"
1282309e9e0SSunil Mushran " tgid: %lu\n"
1292309e9e0SSunil Mushran " process name: %s\n"
1302309e9e0SSunil Mushran " node: %u\n"
1312309e9e0SSunil Mushran " sc: %p\n"
1322309e9e0SSunil Mushran " message id: %d\n"
1332309e9e0SSunil Mushran " message type: %u\n"
1342309e9e0SSunil Mushran " message key: 0x%08x\n"
1353f9c14faSSunil Mushran " sock acquiry: %lld usecs ago\n"
1363f9c14faSSunil Mushran " send start: %lld usecs ago\n"
1373f9c14faSSunil Mushran " wait start: %lld usecs ago\n",
13837096a79SSunil Mushran nst, (unsigned long)task_pid_nr(nst->st_task),
1392309e9e0SSunil Mushran (unsigned long)nst->st_task->tgid,
1402309e9e0SSunil Mushran nst->st_task->comm, nst->st_node,
1412309e9e0SSunil Mushran nst->st_sc, nst->st_id, nst->st_msg_type,
1422309e9e0SSunil Mushran nst->st_msg_key,
1433f9c14faSSunil Mushran (long long)sock,
1443f9c14faSSunil Mushran (long long)send,
1453f9c14faSSunil Mushran (long long)status);
1462309e9e0SSunil Mushran
147cc548166SDan Carpenter out:
148*84c10951SChengfeng Ye spin_unlock_bh(&o2net_debug_lock);
1492309e9e0SSunil Mushran
1502309e9e0SSunil Mushran return 0;
1512309e9e0SSunil Mushran }
1522309e9e0SSunil Mushran
nst_seq_stop(struct seq_file * seq,void * v)1532309e9e0SSunil Mushran static void nst_seq_stop(struct seq_file *seq, void *v)
1542309e9e0SSunil Mushran {
1552309e9e0SSunil Mushran }
1562309e9e0SSunil Mushran
15788e9d34cSJames Morris static const struct seq_operations nst_seq_ops = {
1582309e9e0SSunil Mushran .start = nst_seq_start,
1592309e9e0SSunil Mushran .next = nst_seq_next,
1602309e9e0SSunil Mushran .stop = nst_seq_stop,
1612309e9e0SSunil Mushran .show = nst_seq_show,
1622309e9e0SSunil Mushran };
1632309e9e0SSunil Mushran
nst_fop_open(struct inode * inode,struct file * file)1642309e9e0SSunil Mushran static int nst_fop_open(struct inode *inode, struct file *file)
1652309e9e0SSunil Mushran {
1662309e9e0SSunil Mushran struct o2net_send_tracking *dummy_nst;
1672309e9e0SSunil Mushran
168f3288338SRob Jones dummy_nst = __seq_open_private(file, &nst_seq_ops, sizeof(*dummy_nst));
169f3288338SRob Jones if (!dummy_nst)
170f3288338SRob Jones return -ENOMEM;
1712309e9e0SSunil Mushran o2net_debug_add_nst(dummy_nst);
1722309e9e0SSunil Mushran
173f3288338SRob Jones return 0;
1742309e9e0SSunil Mushran }
1752309e9e0SSunil Mushran
nst_fop_release(struct inode * inode,struct file * file)1762309e9e0SSunil Mushran static int nst_fop_release(struct inode *inode, struct file *file)
1772309e9e0SSunil Mushran {
1782309e9e0SSunil Mushran struct seq_file *seq = file->private_data;
1792309e9e0SSunil Mushran struct o2net_send_tracking *dummy_nst = seq->private;
1802309e9e0SSunil Mushran
1812309e9e0SSunil Mushran o2net_debug_del_nst(dummy_nst);
1822309e9e0SSunil Mushran return seq_release_private(inode, file);
1832309e9e0SSunil Mushran }
1842309e9e0SSunil Mushran
185828c0950SAlexey Dobriyan static const struct file_operations nst_seq_fops = {
1862309e9e0SSunil Mushran .open = nst_fop_open,
1872309e9e0SSunil Mushran .read = seq_read,
1882309e9e0SSunil Mushran .llseek = seq_lseek,
1892309e9e0SSunil Mushran .release = nst_fop_release,
1902309e9e0SSunil Mushran };
1912309e9e0SSunil Mushran
o2net_debug_add_sc(struct o2net_sock_container * sc)1922309e9e0SSunil Mushran void o2net_debug_add_sc(struct o2net_sock_container *sc)
1932309e9e0SSunil Mushran {
194*84c10951SChengfeng Ye spin_lock_bh(&o2net_debug_lock);
1952309e9e0SSunil Mushran list_add(&sc->sc_net_debug_item, &sock_containers);
196*84c10951SChengfeng Ye spin_unlock_bh(&o2net_debug_lock);
1972309e9e0SSunil Mushran }
1982309e9e0SSunil Mushran
o2net_debug_del_sc(struct o2net_sock_container * sc)1992309e9e0SSunil Mushran void o2net_debug_del_sc(struct o2net_sock_container *sc)
2002309e9e0SSunil Mushran {
201*84c10951SChengfeng Ye spin_lock_bh(&o2net_debug_lock);
2022309e9e0SSunil Mushran list_del_init(&sc->sc_net_debug_item);
203*84c10951SChengfeng Ye spin_unlock_bh(&o2net_debug_lock);
2042309e9e0SSunil Mushran }
2052309e9e0SSunil Mushran
206db02754cSSunil Mushran struct o2net_sock_debug {
207db02754cSSunil Mushran int dbg_ctxt;
208db02754cSSunil Mushran struct o2net_sock_container *dbg_sock;
209db02754cSSunil Mushran };
210db02754cSSunil Mushran
2112309e9e0SSunil Mushran static struct o2net_sock_container
next_sc(struct o2net_sock_container * sc_start)2122309e9e0SSunil Mushran *next_sc(struct o2net_sock_container *sc_start)
2132309e9e0SSunil Mushran {
2142309e9e0SSunil Mushran struct o2net_sock_container *sc, *ret = NULL;
2152309e9e0SSunil Mushran
2162309e9e0SSunil Mushran assert_spin_locked(&o2net_debug_lock);
2172309e9e0SSunil Mushran
2182309e9e0SSunil Mushran list_for_each_entry(sc, &sc_start->sc_net_debug_item,
2192309e9e0SSunil Mushran sc_net_debug_item) {
2202309e9e0SSunil Mushran /* discover the head of the list miscast as a sc */
2212309e9e0SSunil Mushran if (&sc->sc_net_debug_item == &sock_containers)
2222309e9e0SSunil Mushran break;
2232309e9e0SSunil Mushran
2242309e9e0SSunil Mushran /* use sc_page to detect real scs in the list */
2252309e9e0SSunil Mushran if (sc->sc_page != NULL) {
2262309e9e0SSunil Mushran ret = sc;
2272309e9e0SSunil Mushran break;
2282309e9e0SSunil Mushran }
2292309e9e0SSunil Mushran }
2302309e9e0SSunil Mushran
2312309e9e0SSunil Mushran return ret;
2322309e9e0SSunil Mushran }
2332309e9e0SSunil Mushran
sc_seq_start(struct seq_file * seq,loff_t * pos)2342309e9e0SSunil Mushran static void *sc_seq_start(struct seq_file *seq, loff_t *pos)
2352309e9e0SSunil Mushran {
236db02754cSSunil Mushran struct o2net_sock_debug *sd = seq->private;
237db02754cSSunil Mushran struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
2382309e9e0SSunil Mushran
239*84c10951SChengfeng Ye spin_lock_bh(&o2net_debug_lock);
2402309e9e0SSunil Mushran sc = next_sc(dummy_sc);
241*84c10951SChengfeng Ye spin_unlock_bh(&o2net_debug_lock);
2422309e9e0SSunil Mushran
2432309e9e0SSunil Mushran return sc;
2442309e9e0SSunil Mushran }
2452309e9e0SSunil Mushran
sc_seq_next(struct seq_file * seq,void * v,loff_t * pos)2462309e9e0SSunil Mushran static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2472309e9e0SSunil Mushran {
248db02754cSSunil Mushran struct o2net_sock_debug *sd = seq->private;
249db02754cSSunil Mushran struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
2502309e9e0SSunil Mushran
251*84c10951SChengfeng Ye spin_lock_bh(&o2net_debug_lock);
2522309e9e0SSunil Mushran sc = next_sc(dummy_sc);
2532309e9e0SSunil Mushran list_del_init(&dummy_sc->sc_net_debug_item);
2542309e9e0SSunil Mushran if (sc)
2552309e9e0SSunil Mushran list_add(&dummy_sc->sc_net_debug_item, &sc->sc_net_debug_item);
256*84c10951SChengfeng Ye spin_unlock_bh(&o2net_debug_lock);
2572309e9e0SSunil Mushran
2582309e9e0SSunil Mushran return sc; /* unused, just needs to be null when done */
2592309e9e0SSunil Mushran }
2602309e9e0SSunil Mushran
261db02754cSSunil Mushran #ifdef CONFIG_OCFS2_FS_STATS
262db02754cSSunil Mushran # define sc_send_count(_s) ((_s)->sc_send_count)
263db02754cSSunil Mushran # define sc_recv_count(_s) ((_s)->sc_recv_count)
264db02754cSSunil Mushran # define sc_tv_acquiry_total_ns(_s) (ktime_to_ns((_s)->sc_tv_acquiry_total))
265db02754cSSunil Mushran # define sc_tv_send_total_ns(_s) (ktime_to_ns((_s)->sc_tv_send_total))
266db02754cSSunil Mushran # define sc_tv_status_total_ns(_s) (ktime_to_ns((_s)->sc_tv_status_total))
267db02754cSSunil Mushran # define sc_tv_process_total_ns(_s) (ktime_to_ns((_s)->sc_tv_process_total))
268db02754cSSunil Mushran #else
269db02754cSSunil Mushran # define sc_send_count(_s) (0U)
270db02754cSSunil Mushran # define sc_recv_count(_s) (0U)
271db02754cSSunil Mushran # define sc_tv_acquiry_total_ns(_s) (0LL)
272db02754cSSunil Mushran # define sc_tv_send_total_ns(_s) (0LL)
273db02754cSSunil Mushran # define sc_tv_status_total_ns(_s) (0LL)
274db02754cSSunil Mushran # define sc_tv_process_total_ns(_s) (0LL)
275db02754cSSunil Mushran #endif
276db02754cSSunil Mushran
277db02754cSSunil Mushran /* So that debugfs.ocfs2 can determine which format is being used */
278db02754cSSunil Mushran #define O2NET_STATS_STR_VERSION 1
sc_show_sock_stats(struct seq_file * seq,struct o2net_sock_container * sc)279db02754cSSunil Mushran static void sc_show_sock_stats(struct seq_file *seq,
280db02754cSSunil Mushran struct o2net_sock_container *sc)
2812309e9e0SSunil Mushran {
282db02754cSSunil Mushran if (!sc)
283db02754cSSunil Mushran return;
2842309e9e0SSunil Mushran
285db02754cSSunil Mushran seq_printf(seq, "%d,%u,%lu,%lld,%lld,%lld,%lu,%lld\n", O2NET_STATS_STR_VERSION,
286db02754cSSunil Mushran sc->sc_node->nd_num, (unsigned long)sc_send_count(sc),
287db02754cSSunil Mushran (long long)sc_tv_acquiry_total_ns(sc),
288db02754cSSunil Mushran (long long)sc_tv_send_total_ns(sc),
289db02754cSSunil Mushran (long long)sc_tv_status_total_ns(sc),
290db02754cSSunil Mushran (unsigned long)sc_recv_count(sc),
291db02754cSSunil Mushran (long long)sc_tv_process_total_ns(sc));
292db02754cSSunil Mushran }
2932309e9e0SSunil Mushran
sc_show_sock_container(struct seq_file * seq,struct o2net_sock_container * sc)294db02754cSSunil Mushran static void sc_show_sock_container(struct seq_file *seq,
295db02754cSSunil Mushran struct o2net_sock_container *sc)
296db02754cSSunil Mushran {
2972309e9e0SSunil Mushran struct inet_sock *inet = NULL;
2982309e9e0SSunil Mushran __be32 saddr = 0, daddr = 0;
2992309e9e0SSunil Mushran __be16 sport = 0, dport = 0;
3002309e9e0SSunil Mushran
301db02754cSSunil Mushran if (!sc)
302db02754cSSunil Mushran return;
303db02754cSSunil Mushran
3042309e9e0SSunil Mushran if (sc->sc_sock) {
3052309e9e0SSunil Mushran inet = inet_sk(sc->sc_sock->sk);
3062309e9e0SSunil Mushran /* the stack's structs aren't sparse endian clean */
307c720c7e8SEric Dumazet saddr = (__force __be32)inet->inet_saddr;
308c720c7e8SEric Dumazet daddr = (__force __be32)inet->inet_daddr;
309c720c7e8SEric Dumazet sport = (__force __be16)inet->inet_sport;
310c720c7e8SEric Dumazet dport = (__force __be16)inet->inet_dport;
3112309e9e0SSunil Mushran }
3122309e9e0SSunil Mushran
3132309e9e0SSunil Mushran /* XXX sigh, inet-> doesn't have sparse annotation so any
3142309e9e0SSunil Mushran * use of it here generates a warning with -Wbitwise */
3152309e9e0SSunil Mushran seq_printf(seq, "%p:\n"
3162309e9e0SSunil Mushran " krefs: %d\n"
317be859405SHarvey Harrison " sock: %pI4:%u -> "
318be859405SHarvey Harrison "%pI4:%u\n"
3192309e9e0SSunil Mushran " remote node: %s\n"
3202309e9e0SSunil Mushran " page off: %zu\n"
3212309e9e0SSunil Mushran " handshake ok: %u\n"
322ff1becbfSSunil Mushran " timer: %lld usecs\n"
323ff1becbfSSunil Mushran " data ready: %lld usecs\n"
324ff1becbfSSunil Mushran " advance start: %lld usecs\n"
325ff1becbfSSunil Mushran " advance stop: %lld usecs\n"
326ff1becbfSSunil Mushran " func start: %lld usecs\n"
327ff1becbfSSunil Mushran " func stop: %lld usecs\n"
328ff1becbfSSunil Mushran " func key: 0x%08x\n"
3292309e9e0SSunil Mushran " func type: %u\n",
3302309e9e0SSunil Mushran sc,
3312c935bc5SPeter Zijlstra kref_read(&sc->sc_kref),
332be859405SHarvey Harrison &saddr, inet ? ntohs(sport) : 0,
333be859405SHarvey Harrison &daddr, inet ? ntohs(dport) : 0,
3342309e9e0SSunil Mushran sc->sc_node->nd_name,
3352309e9e0SSunil Mushran sc->sc_page_off,
3362309e9e0SSunil Mushran sc->sc_handshake_ok,
337ff1becbfSSunil Mushran (long long)ktime_to_us(sc->sc_tv_timer),
338ff1becbfSSunil Mushran (long long)ktime_to_us(sc->sc_tv_data_ready),
339ff1becbfSSunil Mushran (long long)ktime_to_us(sc->sc_tv_advance_start),
340ff1becbfSSunil Mushran (long long)ktime_to_us(sc->sc_tv_advance_stop),
341ff1becbfSSunil Mushran (long long)ktime_to_us(sc->sc_tv_func_start),
342ff1becbfSSunil Mushran (long long)ktime_to_us(sc->sc_tv_func_stop),
3432309e9e0SSunil Mushran sc->sc_msg_key,
3442309e9e0SSunil Mushran sc->sc_msg_type);
3452309e9e0SSunil Mushran }
3462309e9e0SSunil Mushran
sc_seq_show(struct seq_file * seq,void * v)347db02754cSSunil Mushran static int sc_seq_show(struct seq_file *seq, void *v)
348db02754cSSunil Mushran {
349db02754cSSunil Mushran struct o2net_sock_debug *sd = seq->private;
350db02754cSSunil Mushran struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
351db02754cSSunil Mushran
352*84c10951SChengfeng Ye spin_lock_bh(&o2net_debug_lock);
353db02754cSSunil Mushran sc = next_sc(dummy_sc);
354db02754cSSunil Mushran
355db02754cSSunil Mushran if (sc) {
356db02754cSSunil Mushran if (sd->dbg_ctxt == SHOW_SOCK_CONTAINERS)
357db02754cSSunil Mushran sc_show_sock_container(seq, sc);
358db02754cSSunil Mushran else
359db02754cSSunil Mushran sc_show_sock_stats(seq, sc);
360db02754cSSunil Mushran }
3612309e9e0SSunil Mushran
362*84c10951SChengfeng Ye spin_unlock_bh(&o2net_debug_lock);
3632309e9e0SSunil Mushran
3642309e9e0SSunil Mushran return 0;
3652309e9e0SSunil Mushran }
3662309e9e0SSunil Mushran
sc_seq_stop(struct seq_file * seq,void * v)3672309e9e0SSunil Mushran static void sc_seq_stop(struct seq_file *seq, void *v)
3682309e9e0SSunil Mushran {
3692309e9e0SSunil Mushran }
3702309e9e0SSunil Mushran
37188e9d34cSJames Morris static const struct seq_operations sc_seq_ops = {
3722309e9e0SSunil Mushran .start = sc_seq_start,
3732309e9e0SSunil Mushran .next = sc_seq_next,
3742309e9e0SSunil Mushran .stop = sc_seq_stop,
3752309e9e0SSunil Mushran .show = sc_seq_show,
3762309e9e0SSunil Mushran };
3772309e9e0SSunil Mushran
sc_common_open(struct file * file,int ctxt)378f3288338SRob Jones static int sc_common_open(struct file *file, int ctxt)
3792309e9e0SSunil Mushran {
380f3288338SRob Jones struct o2net_sock_debug *sd;
3812309e9e0SSunil Mushran struct o2net_sock_container *dummy_sc;
3822309e9e0SSunil Mushran
383f3288338SRob Jones dummy_sc = kzalloc(sizeof(*dummy_sc), GFP_KERNEL);
384f3288338SRob Jones if (!dummy_sc)
385f3288338SRob Jones return -ENOMEM;
386f3288338SRob Jones
387f3288338SRob Jones sd = __seq_open_private(file, &sc_seq_ops, sizeof(*sd));
388f3288338SRob Jones if (!sd) {
389f3288338SRob Jones kfree(dummy_sc);
390f3288338SRob Jones return -ENOMEM;
3912309e9e0SSunil Mushran }
3922309e9e0SSunil Mushran
393f3288338SRob Jones sd->dbg_ctxt = ctxt;
394db02754cSSunil Mushran sd->dbg_sock = dummy_sc;
395f3288338SRob Jones
3962309e9e0SSunil Mushran o2net_debug_add_sc(dummy_sc);
3972309e9e0SSunil Mushran
398f3288338SRob Jones return 0;
3992309e9e0SSunil Mushran }
4002309e9e0SSunil Mushran
sc_fop_release(struct inode * inode,struct file * file)4012309e9e0SSunil Mushran static int sc_fop_release(struct inode *inode, struct file *file)
4022309e9e0SSunil Mushran {
4032309e9e0SSunil Mushran struct seq_file *seq = file->private_data;
404db02754cSSunil Mushran struct o2net_sock_debug *sd = seq->private;
405db02754cSSunil Mushran struct o2net_sock_container *dummy_sc = sd->dbg_sock;
4062309e9e0SSunil Mushran
4072309e9e0SSunil Mushran o2net_debug_del_sc(dummy_sc);
40825b1c72eSpiaojun kfree(dummy_sc);
4092309e9e0SSunil Mushran return seq_release_private(inode, file);
4102309e9e0SSunil Mushran }
4112309e9e0SSunil Mushran
stats_fop_open(struct inode * inode,struct file * file)412db02754cSSunil Mushran static int stats_fop_open(struct inode *inode, struct file *file)
413db02754cSSunil Mushran {
414f3288338SRob Jones return sc_common_open(file, SHOW_SOCK_STATS);
415db02754cSSunil Mushran }
416db02754cSSunil Mushran
417db02754cSSunil Mushran static const struct file_operations stats_seq_fops = {
418db02754cSSunil Mushran .open = stats_fop_open,
419db02754cSSunil Mushran .read = seq_read,
420db02754cSSunil Mushran .llseek = seq_lseek,
421db02754cSSunil Mushran .release = sc_fop_release,
422db02754cSSunil Mushran };
423db02754cSSunil Mushran
sc_fop_open(struct inode * inode,struct file * file)424db02754cSSunil Mushran static int sc_fop_open(struct inode *inode, struct file *file)
425db02754cSSunil Mushran {
426f3288338SRob Jones return sc_common_open(file, SHOW_SOCK_CONTAINERS);
427db02754cSSunil Mushran }
428db02754cSSunil Mushran
429828c0950SAlexey Dobriyan static const struct file_operations sc_seq_fops = {
4302309e9e0SSunil Mushran .open = sc_fop_open,
4312309e9e0SSunil Mushran .read = seq_read,
4322309e9e0SSunil Mushran .llseek = seq_lseek,
4332309e9e0SSunil Mushran .release = sc_fop_release,
4342309e9e0SSunil Mushran };
4352309e9e0SSunil Mushran
o2net_fill_bitmap(char * buf,int len)4363ba169ccSSunil Mushran static int o2net_fill_bitmap(char *buf, int len)
4372309e9e0SSunil Mushran {
4383ba169ccSSunil Mushran unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)];
4393ba169ccSSunil Mushran int i = -1, out = 0;
4403ba169ccSSunil Mushran
4416d4a93b6SJoseph Qi o2net_fill_node_map(map, O2NM_MAX_NODES);
4423ba169ccSSunil Mushran
4433ba169ccSSunil Mushran while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES)
444d293d3afSTakashi Iwai out += scnprintf(buf + out, PAGE_SIZE - out, "%d ", i);
445d293d3afSTakashi Iwai out += scnprintf(buf + out, PAGE_SIZE - out, "\n");
4463ba169ccSSunil Mushran
4473ba169ccSSunil Mushran return out;
4482309e9e0SSunil Mushran }
4492309e9e0SSunil Mushran
nodes_fop_open(struct inode * inode,struct file * file)4503ba169ccSSunil Mushran static int nodes_fop_open(struct inode *inode, struct file *file)
4513ba169ccSSunil Mushran {
4523ba169ccSSunil Mushran char *buf;
4532309e9e0SSunil Mushran
4543ba169ccSSunil Mushran buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
4553ba169ccSSunil Mushran if (!buf)
4563ba169ccSSunil Mushran return -ENOMEM;
4572309e9e0SSunil Mushran
4583ba169ccSSunil Mushran i_size_write(inode, o2net_fill_bitmap(buf, PAGE_SIZE));
4593ba169ccSSunil Mushran
4603ba169ccSSunil Mushran file->private_data = buf;
461db02754cSSunil Mushran
4622309e9e0SSunil Mushran return 0;
4632309e9e0SSunil Mushran }
4642309e9e0SSunil Mushran
o2net_debug_release(struct inode * inode,struct file * file)4653ba169ccSSunil Mushran static int o2net_debug_release(struct inode *inode, struct file *file)
4663ba169ccSSunil Mushran {
4673ba169ccSSunil Mushran kfree(file->private_data);
4683ba169ccSSunil Mushran return 0;
4693ba169ccSSunil Mushran }
4703ba169ccSSunil Mushran
o2net_debug_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)4713ba169ccSSunil Mushran static ssize_t o2net_debug_read(struct file *file, char __user *buf,
4723ba169ccSSunil Mushran size_t nbytes, loff_t *ppos)
4733ba169ccSSunil Mushran {
4743ba169ccSSunil Mushran return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
4753ba169ccSSunil Mushran i_size_read(file->f_mapping->host));
4763ba169ccSSunil Mushran }
4773ba169ccSSunil Mushran
4783ba169ccSSunil Mushran static const struct file_operations nodes_fops = {
4793ba169ccSSunil Mushran .open = nodes_fop_open,
4803ba169ccSSunil Mushran .release = o2net_debug_release,
4813ba169ccSSunil Mushran .read = o2net_debug_read,
4823ba169ccSSunil Mushran .llseek = generic_file_llseek,
4833ba169ccSSunil Mushran };
4843ba169ccSSunil Mushran
o2net_debugfs_exit(void)4852309e9e0SSunil Mushran void o2net_debugfs_exit(void)
4862309e9e0SSunil Mushran {
487e581595eSGreg Kroah-Hartman debugfs_remove_recursive(o2net_dentry);
4882309e9e0SSunil Mushran }
4892309e9e0SSunil Mushran
o2net_debugfs_init(void)490e581595eSGreg Kroah-Hartman void o2net_debugfs_init(void)
4913ba169ccSSunil Mushran {
492f4ae40a6SAl Viro umode_t mode = S_IFREG|S_IRUSR;
4933ba169ccSSunil Mushran
4943ba169ccSSunil Mushran o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL);
4953ba169ccSSunil Mushran
496e581595eSGreg Kroah-Hartman debugfs_create_file(NST_DEBUG_NAME, mode, o2net_dentry, NULL,
497e581595eSGreg Kroah-Hartman &nst_seq_fops);
498e581595eSGreg Kroah-Hartman debugfs_create_file(SC_DEBUG_NAME, mode, o2net_dentry, NULL,
499e581595eSGreg Kroah-Hartman &sc_seq_fops);
500e581595eSGreg Kroah-Hartman debugfs_create_file(STATS_DEBUG_NAME, mode, o2net_dentry, NULL,
501e581595eSGreg Kroah-Hartman &stats_seq_fops);
502e581595eSGreg Kroah-Hartman debugfs_create_file(NODES_DEBUG_NAME, mode, o2net_dentry, NULL,
503e581595eSGreg Kroah-Hartman &nodes_fops);
5043ba169ccSSunil Mushran }
5053ba169ccSSunil Mushran
5062309e9e0SSunil Mushran #endif /* CONFIG_DEBUG_FS */
507