Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * netdebug.c
0004  *
0005  * debug functionality for o2net
0006  *
0007  * Copyright (C) 2005, 2008 Oracle.  All rights reserved.
0008  */
0009 
0010 #ifdef CONFIG_DEBUG_FS
0011 
0012 #include <linux/module.h>
0013 #include <linux/types.h>
0014 #include <linux/slab.h>
0015 #include <linux/idr.h>
0016 #include <linux/kref.h>
0017 #include <linux/seq_file.h>
0018 #include <linux/debugfs.h>
0019 
0020 #include <linux/uaccess.h>
0021 
0022 #include "tcp.h"
0023 #include "nodemanager.h"
0024 #define MLOG_MASK_PREFIX ML_TCP
0025 #include "masklog.h"
0026 
0027 #include "tcp_internal.h"
0028 
0029 #define O2NET_DEBUG_DIR     "o2net"
0030 #define SC_DEBUG_NAME       "sock_containers"
0031 #define NST_DEBUG_NAME      "send_tracking"
0032 #define STATS_DEBUG_NAME    "stats"
0033 #define NODES_DEBUG_NAME    "connected_nodes"
0034 
0035 #define SHOW_SOCK_CONTAINERS    0
0036 #define SHOW_SOCK_STATS     1
0037 
0038 static struct dentry *o2net_dentry;
0039 
0040 static DEFINE_SPINLOCK(o2net_debug_lock);
0041 
0042 static LIST_HEAD(sock_containers);
0043 static LIST_HEAD(send_tracking);
0044 
0045 void o2net_debug_add_nst(struct o2net_send_tracking *nst)
0046 {
0047     spin_lock(&o2net_debug_lock);
0048     list_add(&nst->st_net_debug_item, &send_tracking);
0049     spin_unlock(&o2net_debug_lock);
0050 }
0051 
0052 void o2net_debug_del_nst(struct o2net_send_tracking *nst)
0053 {
0054     spin_lock(&o2net_debug_lock);
0055     if (!list_empty(&nst->st_net_debug_item))
0056         list_del_init(&nst->st_net_debug_item);
0057     spin_unlock(&o2net_debug_lock);
0058 }
0059 
0060 static struct o2net_send_tracking
0061             *next_nst(struct o2net_send_tracking *nst_start)
0062 {
0063     struct o2net_send_tracking *nst, *ret = NULL;
0064 
0065     assert_spin_locked(&o2net_debug_lock);
0066 
0067     list_for_each_entry(nst, &nst_start->st_net_debug_item,
0068                 st_net_debug_item) {
0069         /* discover the head of the list */
0070         if (&nst->st_net_debug_item == &send_tracking)
0071             break;
0072 
0073         /* use st_task to detect real nsts in the list */
0074         if (nst->st_task != NULL) {
0075             ret = nst;
0076             break;
0077         }
0078     }
0079 
0080     return ret;
0081 }
0082 
0083 static void *nst_seq_start(struct seq_file *seq, loff_t *pos)
0084 {
0085     struct o2net_send_tracking *nst, *dummy_nst = seq->private;
0086 
0087     spin_lock(&o2net_debug_lock);
0088     nst = next_nst(dummy_nst);
0089     spin_unlock(&o2net_debug_lock);
0090 
0091     return nst;
0092 }
0093 
0094 static void *nst_seq_next(struct seq_file *seq, void *v, loff_t *pos)
0095 {
0096     struct o2net_send_tracking *nst, *dummy_nst = seq->private;
0097 
0098     spin_lock(&o2net_debug_lock);
0099     nst = next_nst(dummy_nst);
0100     list_del_init(&dummy_nst->st_net_debug_item);
0101     if (nst)
0102         list_add(&dummy_nst->st_net_debug_item,
0103              &nst->st_net_debug_item);
0104     spin_unlock(&o2net_debug_lock);
0105 
0106     return nst; /* unused, just needs to be null when done */
0107 }
0108 
0109 static int nst_seq_show(struct seq_file *seq, void *v)
0110 {
0111     struct o2net_send_tracking *nst, *dummy_nst = seq->private;
0112     ktime_t now;
0113     s64 sock, send, status;
0114 
0115     spin_lock(&o2net_debug_lock);
0116     nst = next_nst(dummy_nst);
0117     if (!nst)
0118         goto out;
0119 
0120     now = ktime_get();
0121     sock = ktime_to_us(ktime_sub(now, nst->st_sock_time));
0122     send = ktime_to_us(ktime_sub(now, nst->st_send_time));
0123     status = ktime_to_us(ktime_sub(now, nst->st_status_time));
0124 
0125     /* get_task_comm isn't exported.  oh well. */
0126     seq_printf(seq, "%p:\n"
0127            "  pid:          %lu\n"
0128            "  tgid:         %lu\n"
0129            "  process name: %s\n"
0130            "  node:         %u\n"
0131            "  sc:           %p\n"
0132            "  message id:   %d\n"
0133            "  message type: %u\n"
0134            "  message key:  0x%08x\n"
0135            "  sock acquiry: %lld usecs ago\n"
0136            "  send start:   %lld usecs ago\n"
0137            "  wait start:   %lld usecs ago\n",
0138            nst, (unsigned long)task_pid_nr(nst->st_task),
0139            (unsigned long)nst->st_task->tgid,
0140            nst->st_task->comm, nst->st_node,
0141            nst->st_sc, nst->st_id, nst->st_msg_type,
0142            nst->st_msg_key,
0143            (long long)sock,
0144            (long long)send,
0145            (long long)status);
0146 
0147 out:
0148     spin_unlock(&o2net_debug_lock);
0149 
0150     return 0;
0151 }
0152 
0153 static void nst_seq_stop(struct seq_file *seq, void *v)
0154 {
0155 }
0156 
0157 static const struct seq_operations nst_seq_ops = {
0158     .start = nst_seq_start,
0159     .next = nst_seq_next,
0160     .stop = nst_seq_stop,
0161     .show = nst_seq_show,
0162 };
0163 
0164 static int nst_fop_open(struct inode *inode, struct file *file)
0165 {
0166     struct o2net_send_tracking *dummy_nst;
0167 
0168     dummy_nst = __seq_open_private(file, &nst_seq_ops, sizeof(*dummy_nst));
0169     if (!dummy_nst)
0170         return -ENOMEM;
0171     o2net_debug_add_nst(dummy_nst);
0172 
0173     return 0;
0174 }
0175 
0176 static int nst_fop_release(struct inode *inode, struct file *file)
0177 {
0178     struct seq_file *seq = file->private_data;
0179     struct o2net_send_tracking *dummy_nst = seq->private;
0180 
0181     o2net_debug_del_nst(dummy_nst);
0182     return seq_release_private(inode, file);
0183 }
0184 
0185 static const struct file_operations nst_seq_fops = {
0186     .open = nst_fop_open,
0187     .read = seq_read,
0188     .llseek = seq_lseek,
0189     .release = nst_fop_release,
0190 };
0191 
0192 void o2net_debug_add_sc(struct o2net_sock_container *sc)
0193 {
0194     spin_lock(&o2net_debug_lock);
0195     list_add(&sc->sc_net_debug_item, &sock_containers);
0196     spin_unlock(&o2net_debug_lock);
0197 }
0198 
0199 void o2net_debug_del_sc(struct o2net_sock_container *sc)
0200 {
0201     spin_lock(&o2net_debug_lock);
0202     list_del_init(&sc->sc_net_debug_item);
0203     spin_unlock(&o2net_debug_lock);
0204 }
0205 
0206 struct o2net_sock_debug {
0207     int dbg_ctxt;
0208     struct o2net_sock_container *dbg_sock;
0209 };
0210 
0211 static struct o2net_sock_container
0212             *next_sc(struct o2net_sock_container *sc_start)
0213 {
0214     struct o2net_sock_container *sc, *ret = NULL;
0215 
0216     assert_spin_locked(&o2net_debug_lock);
0217 
0218     list_for_each_entry(sc, &sc_start->sc_net_debug_item,
0219                 sc_net_debug_item) {
0220         /* discover the head of the list miscast as a sc */
0221         if (&sc->sc_net_debug_item == &sock_containers)
0222             break;
0223 
0224         /* use sc_page to detect real scs in the list */
0225         if (sc->sc_page != NULL) {
0226             ret = sc;
0227             break;
0228         }
0229     }
0230 
0231     return ret;
0232 }
0233 
0234 static void *sc_seq_start(struct seq_file *seq, loff_t *pos)
0235 {
0236     struct o2net_sock_debug *sd = seq->private;
0237     struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
0238 
0239     spin_lock(&o2net_debug_lock);
0240     sc = next_sc(dummy_sc);
0241     spin_unlock(&o2net_debug_lock);
0242 
0243     return sc;
0244 }
0245 
0246 static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
0247 {
0248     struct o2net_sock_debug *sd = seq->private;
0249     struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
0250 
0251     spin_lock(&o2net_debug_lock);
0252     sc = next_sc(dummy_sc);
0253     list_del_init(&dummy_sc->sc_net_debug_item);
0254     if (sc)
0255         list_add(&dummy_sc->sc_net_debug_item, &sc->sc_net_debug_item);
0256     spin_unlock(&o2net_debug_lock);
0257 
0258     return sc; /* unused, just needs to be null when done */
0259 }
0260 
0261 #ifdef CONFIG_OCFS2_FS_STATS
0262 # define sc_send_count(_s)      ((_s)->sc_send_count)
0263 # define sc_recv_count(_s)      ((_s)->sc_recv_count)
0264 # define sc_tv_acquiry_total_ns(_s) (ktime_to_ns((_s)->sc_tv_acquiry_total))
0265 # define sc_tv_send_total_ns(_s)    (ktime_to_ns((_s)->sc_tv_send_total))
0266 # define sc_tv_status_total_ns(_s)  (ktime_to_ns((_s)->sc_tv_status_total))
0267 # define sc_tv_process_total_ns(_s) (ktime_to_ns((_s)->sc_tv_process_total))
0268 #else
0269 # define sc_send_count(_s)      (0U)
0270 # define sc_recv_count(_s)      (0U)
0271 # define sc_tv_acquiry_total_ns(_s) (0LL)
0272 # define sc_tv_send_total_ns(_s)    (0LL)
0273 # define sc_tv_status_total_ns(_s)  (0LL)
0274 # define sc_tv_process_total_ns(_s) (0LL)
0275 #endif
0276 
0277 /* So that debugfs.ocfs2 can determine which format is being used */
0278 #define O2NET_STATS_STR_VERSION     1
0279 static void sc_show_sock_stats(struct seq_file *seq,
0280                    struct o2net_sock_container *sc)
0281 {
0282     if (!sc)
0283         return;
0284 
0285     seq_printf(seq, "%d,%u,%lu,%lld,%lld,%lld,%lu,%lld\n", O2NET_STATS_STR_VERSION,
0286            sc->sc_node->nd_num, (unsigned long)sc_send_count(sc),
0287            (long long)sc_tv_acquiry_total_ns(sc),
0288            (long long)sc_tv_send_total_ns(sc),
0289            (long long)sc_tv_status_total_ns(sc),
0290            (unsigned long)sc_recv_count(sc),
0291            (long long)sc_tv_process_total_ns(sc));
0292 }
0293 
0294 static void sc_show_sock_container(struct seq_file *seq,
0295                    struct o2net_sock_container *sc)
0296 {
0297     struct inet_sock *inet = NULL;
0298     __be32 saddr = 0, daddr = 0;
0299     __be16 sport = 0, dport = 0;
0300 
0301     if (!sc)
0302         return;
0303 
0304     if (sc->sc_sock) {
0305         inet = inet_sk(sc->sc_sock->sk);
0306         /* the stack's structs aren't sparse endian clean */
0307         saddr = (__force __be32)inet->inet_saddr;
0308         daddr = (__force __be32)inet->inet_daddr;
0309         sport = (__force __be16)inet->inet_sport;
0310         dport = (__force __be16)inet->inet_dport;
0311     }
0312 
0313     /* XXX sigh, inet-> doesn't have sparse annotation so any
0314      * use of it here generates a warning with -Wbitwise */
0315     seq_printf(seq, "%p:\n"
0316            "  krefs:           %d\n"
0317            "  sock:            %pI4:%u -> "
0318                       "%pI4:%u\n"
0319            "  remote node:     %s\n"
0320            "  page off:        %zu\n"
0321            "  handshake ok:    %u\n"
0322            "  timer:           %lld usecs\n"
0323            "  data ready:      %lld usecs\n"
0324            "  advance start:   %lld usecs\n"
0325            "  advance stop:    %lld usecs\n"
0326            "  func start:      %lld usecs\n"
0327            "  func stop:       %lld usecs\n"
0328            "  func key:        0x%08x\n"
0329            "  func type:       %u\n",
0330            sc,
0331            kref_read(&sc->sc_kref),
0332            &saddr, inet ? ntohs(sport) : 0,
0333            &daddr, inet ? ntohs(dport) : 0,
0334            sc->sc_node->nd_name,
0335            sc->sc_page_off,
0336            sc->sc_handshake_ok,
0337            (long long)ktime_to_us(sc->sc_tv_timer),
0338            (long long)ktime_to_us(sc->sc_tv_data_ready),
0339            (long long)ktime_to_us(sc->sc_tv_advance_start),
0340            (long long)ktime_to_us(sc->sc_tv_advance_stop),
0341            (long long)ktime_to_us(sc->sc_tv_func_start),
0342            (long long)ktime_to_us(sc->sc_tv_func_stop),
0343            sc->sc_msg_key,
0344            sc->sc_msg_type);
0345 }
0346 
0347 static int sc_seq_show(struct seq_file *seq, void *v)
0348 {
0349     struct o2net_sock_debug *sd = seq->private;
0350     struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
0351 
0352     spin_lock(&o2net_debug_lock);
0353     sc = next_sc(dummy_sc);
0354 
0355     if (sc) {
0356         if (sd->dbg_ctxt == SHOW_SOCK_CONTAINERS)
0357             sc_show_sock_container(seq, sc);
0358         else
0359             sc_show_sock_stats(seq, sc);
0360     }
0361 
0362     spin_unlock(&o2net_debug_lock);
0363 
0364     return 0;
0365 }
0366 
0367 static void sc_seq_stop(struct seq_file *seq, void *v)
0368 {
0369 }
0370 
0371 static const struct seq_operations sc_seq_ops = {
0372     .start = sc_seq_start,
0373     .next = sc_seq_next,
0374     .stop = sc_seq_stop,
0375     .show = sc_seq_show,
0376 };
0377 
0378 static int sc_common_open(struct file *file, int ctxt)
0379 {
0380     struct o2net_sock_debug *sd;
0381     struct o2net_sock_container *dummy_sc;
0382 
0383     dummy_sc = kzalloc(sizeof(*dummy_sc), GFP_KERNEL);
0384     if (!dummy_sc)
0385         return -ENOMEM;
0386 
0387     sd = __seq_open_private(file, &sc_seq_ops, sizeof(*sd));
0388     if (!sd) {
0389         kfree(dummy_sc);
0390         return -ENOMEM;
0391     }
0392 
0393     sd->dbg_ctxt = ctxt;
0394     sd->dbg_sock = dummy_sc;
0395 
0396     o2net_debug_add_sc(dummy_sc);
0397 
0398     return 0;
0399 }
0400 
0401 static int sc_fop_release(struct inode *inode, struct file *file)
0402 {
0403     struct seq_file *seq = file->private_data;
0404     struct o2net_sock_debug *sd = seq->private;
0405     struct o2net_sock_container *dummy_sc = sd->dbg_sock;
0406 
0407     o2net_debug_del_sc(dummy_sc);
0408     kfree(dummy_sc);
0409     return seq_release_private(inode, file);
0410 }
0411 
0412 static int stats_fop_open(struct inode *inode, struct file *file)
0413 {
0414     return sc_common_open(file, SHOW_SOCK_STATS);
0415 }
0416 
0417 static const struct file_operations stats_seq_fops = {
0418     .open = stats_fop_open,
0419     .read = seq_read,
0420     .llseek = seq_lseek,
0421     .release = sc_fop_release,
0422 };
0423 
0424 static int sc_fop_open(struct inode *inode, struct file *file)
0425 {
0426     return sc_common_open(file, SHOW_SOCK_CONTAINERS);
0427 }
0428 
0429 static const struct file_operations sc_seq_fops = {
0430     .open = sc_fop_open,
0431     .read = seq_read,
0432     .llseek = seq_lseek,
0433     .release = sc_fop_release,
0434 };
0435 
0436 static int o2net_fill_bitmap(char *buf, int len)
0437 {
0438     unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)];
0439     int i = -1, out = 0;
0440 
0441     o2net_fill_node_map(map, sizeof(map));
0442 
0443     while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES)
0444         out += scnprintf(buf + out, PAGE_SIZE - out, "%d ", i);
0445     out += scnprintf(buf + out, PAGE_SIZE - out, "\n");
0446 
0447     return out;
0448 }
0449 
0450 static int nodes_fop_open(struct inode *inode, struct file *file)
0451 {
0452     char *buf;
0453 
0454     buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
0455     if (!buf)
0456         return -ENOMEM;
0457 
0458     i_size_write(inode, o2net_fill_bitmap(buf, PAGE_SIZE));
0459 
0460     file->private_data = buf;
0461 
0462     return 0;
0463 }
0464 
0465 static int o2net_debug_release(struct inode *inode, struct file *file)
0466 {
0467     kfree(file->private_data);
0468     return 0;
0469 }
0470 
0471 static ssize_t o2net_debug_read(struct file *file, char __user *buf,
0472                 size_t nbytes, loff_t *ppos)
0473 {
0474     return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
0475                        i_size_read(file->f_mapping->host));
0476 }
0477 
0478 static const struct file_operations nodes_fops = {
0479     .open       = nodes_fop_open,
0480     .release    = o2net_debug_release,
0481     .read       = o2net_debug_read,
0482     .llseek     = generic_file_llseek,
0483 };
0484 
0485 void o2net_debugfs_exit(void)
0486 {
0487     debugfs_remove_recursive(o2net_dentry);
0488 }
0489 
0490 void o2net_debugfs_init(void)
0491 {
0492     umode_t mode = S_IFREG|S_IRUSR;
0493 
0494     o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL);
0495 
0496     debugfs_create_file(NST_DEBUG_NAME, mode, o2net_dentry, NULL,
0497                 &nst_seq_fops);
0498     debugfs_create_file(SC_DEBUG_NAME, mode, o2net_dentry, NULL,
0499                 &sc_seq_fops);
0500     debugfs_create_file(STATS_DEBUG_NAME, mode, o2net_dentry, NULL,
0501                 &stats_seq_fops);
0502     debugfs_create_file(NODES_DEBUG_NAME, mode, o2net_dentry, NULL,
0503                 &nodes_fops);
0504 }
0505 
0506 #endif  /* CONFIG_DEBUG_FS */