linux/fs/ocfs2/cluster/netdebug.c
<<
>>
Prefs
   1/* -*- mode: c; c-basic-offset: 8; -*-
   2 * vim: noexpandtab sw=8 ts=8 sts=0:
   3 *
   4 * netdebug.c
   5 *
   6 * debug functionality for o2net
   7 *
   8 * Copyright (C) 2005, 2008 Oracle.  All rights reserved.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public
  12 * License as published by the Free Software Foundation; either
  13 * version 2 of the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public
  21 * License along with this program; if not, write to the
  22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  23 * Boston, MA 021110-1307, USA.
  24 *
  25 */
  26
  27#ifdef CONFIG_DEBUG_FS
  28
  29#include <linux/module.h>
  30#include <linux/types.h>
  31#include <linux/slab.h>
  32#include <linux/idr.h>
  33#include <linux/kref.h>
  34#include <linux/seq_file.h>
  35#include <linux/debugfs.h>
  36
  37#include <linux/uaccess.h>
  38
  39#include "tcp.h"
  40#include "nodemanager.h"
  41#define MLOG_MASK_PREFIX ML_TCP
  42#include "masklog.h"
  43
  44#include "tcp_internal.h"
  45
  46#define O2NET_DEBUG_DIR         "o2net"
  47#define SC_DEBUG_NAME           "sock_containers"
  48#define NST_DEBUG_NAME          "send_tracking"
  49#define STATS_DEBUG_NAME        "stats"
  50#define NODES_DEBUG_NAME        "connected_nodes"
  51
  52#define SHOW_SOCK_CONTAINERS    0
  53#define SHOW_SOCK_STATS         1
  54
  55static struct dentry *o2net_dentry;
  56static struct dentry *sc_dentry;
  57static struct dentry *nst_dentry;
  58static struct dentry *stats_dentry;
  59static struct dentry *nodes_dentry;
  60
  61static DEFINE_SPINLOCK(o2net_debug_lock);
  62
  63static LIST_HEAD(sock_containers);
  64static LIST_HEAD(send_tracking);
  65
  66void o2net_debug_add_nst(struct o2net_send_tracking *nst)
  67{
  68        spin_lock(&o2net_debug_lock);
  69        list_add(&nst->st_net_debug_item, &send_tracking);
  70        spin_unlock(&o2net_debug_lock);
  71}
  72
  73void o2net_debug_del_nst(struct o2net_send_tracking *nst)
  74{
  75        spin_lock(&o2net_debug_lock);
  76        if (!list_empty(&nst->st_net_debug_item))
  77                list_del_init(&nst->st_net_debug_item);
  78        spin_unlock(&o2net_debug_lock);
  79}
  80
  81static struct o2net_send_tracking
  82                        *next_nst(struct o2net_send_tracking *nst_start)
  83{
  84        struct o2net_send_tracking *nst, *ret = NULL;
  85
  86        assert_spin_locked(&o2net_debug_lock);
  87
  88        list_for_each_entry(nst, &nst_start->st_net_debug_item,
  89                            st_net_debug_item) {
  90                /* discover the head of the list */
  91                if (&nst->st_net_debug_item == &send_tracking)
  92                        break;
  93
  94                /* use st_task to detect real nsts in the list */
  95                if (nst->st_task != NULL) {
  96                        ret = nst;
  97                        break;
  98                }
  99        }
 100
 101        return ret;
 102}
 103
 104static void *nst_seq_start(struct seq_file *seq, loff_t *pos)
 105{
 106        struct o2net_send_tracking *nst, *dummy_nst = seq->private;
 107
 108        spin_lock(&o2net_debug_lock);
 109        nst = next_nst(dummy_nst);
 110        spin_unlock(&o2net_debug_lock);
 111
 112        return nst;
 113}
 114
 115static void *nst_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 116{
 117        struct o2net_send_tracking *nst, *dummy_nst = seq->private;
 118
 119        spin_lock(&o2net_debug_lock);
 120        nst = next_nst(dummy_nst);
 121        list_del_init(&dummy_nst->st_net_debug_item);
 122        if (nst)
 123                list_add(&dummy_nst->st_net_debug_item,
 124                         &nst->st_net_debug_item);
 125        spin_unlock(&o2net_debug_lock);
 126
 127        return nst; /* unused, just needs to be null when done */
 128}
 129
 130static int nst_seq_show(struct seq_file *seq, void *v)
 131{
 132        struct o2net_send_tracking *nst, *dummy_nst = seq->private;
 133        ktime_t now;
 134        s64 sock, send, status;
 135
 136        spin_lock(&o2net_debug_lock);
 137        nst = next_nst(dummy_nst);
 138        if (!nst)
 139                goto out;
 140
 141        now = ktime_get();
 142        sock = ktime_to_us(ktime_sub(now, nst->st_sock_time));
 143        send = ktime_to_us(ktime_sub(now, nst->st_send_time));
 144        status = ktime_to_us(ktime_sub(now, nst->st_status_time));
 145
 146        /* get_task_comm isn't exported.  oh well. */
 147        seq_printf(seq, "%p:\n"
 148                   "  pid:          %lu\n"
 149                   "  tgid:         %lu\n"
 150                   "  process name: %s\n"
 151                   "  node:         %u\n"
 152                   "  sc:           %p\n"
 153                   "  message id:   %d\n"
 154                   "  message type: %u\n"
 155                   "  message key:  0x%08x\n"
 156                   "  sock acquiry: %lld usecs ago\n"
 157                   "  send start:   %lld usecs ago\n"
 158                   "  wait start:   %lld usecs ago\n",
 159                   nst, (unsigned long)task_pid_nr(nst->st_task),
 160                   (unsigned long)nst->st_task->tgid,
 161                   nst->st_task->comm, nst->st_node,
 162                   nst->st_sc, nst->st_id, nst->st_msg_type,
 163                   nst->st_msg_key,
 164                   (long long)sock,
 165                   (long long)send,
 166                   (long long)status);
 167
 168out:
 169        spin_unlock(&o2net_debug_lock);
 170
 171        return 0;
 172}
 173
 174static void nst_seq_stop(struct seq_file *seq, void *v)
 175{
 176}
 177
 178static const struct seq_operations nst_seq_ops = {
 179        .start = nst_seq_start,
 180        .next = nst_seq_next,
 181        .stop = nst_seq_stop,
 182        .show = nst_seq_show,
 183};
 184
 185static int nst_fop_open(struct inode *inode, struct file *file)
 186{
 187        struct o2net_send_tracking *dummy_nst;
 188
 189        dummy_nst = __seq_open_private(file, &nst_seq_ops, sizeof(*dummy_nst));
 190        if (!dummy_nst)
 191                return -ENOMEM;
 192        o2net_debug_add_nst(dummy_nst);
 193
 194        return 0;
 195}
 196
 197static int nst_fop_release(struct inode *inode, struct file *file)
 198{
 199        struct seq_file *seq = file->private_data;
 200        struct o2net_send_tracking *dummy_nst = seq->private;
 201
 202        o2net_debug_del_nst(dummy_nst);
 203        return seq_release_private(inode, file);
 204}
 205
 206static const struct file_operations nst_seq_fops = {
 207        .open = nst_fop_open,
 208        .read = seq_read,
 209        .llseek = seq_lseek,
 210        .release = nst_fop_release,
 211};
 212
 213void o2net_debug_add_sc(struct o2net_sock_container *sc)
 214{
 215        spin_lock(&o2net_debug_lock);
 216        list_add(&sc->sc_net_debug_item, &sock_containers);
 217        spin_unlock(&o2net_debug_lock);
 218}
 219
 220void o2net_debug_del_sc(struct o2net_sock_container *sc)
 221{
 222        spin_lock(&o2net_debug_lock);
 223        list_del_init(&sc->sc_net_debug_item);
 224        spin_unlock(&o2net_debug_lock);
 225}
 226
 227struct o2net_sock_debug {
 228        int dbg_ctxt;
 229        struct o2net_sock_container *dbg_sock;
 230};
 231
 232static struct o2net_sock_container
 233                        *next_sc(struct o2net_sock_container *sc_start)
 234{
 235        struct o2net_sock_container *sc, *ret = NULL;
 236
 237        assert_spin_locked(&o2net_debug_lock);
 238
 239        list_for_each_entry(sc, &sc_start->sc_net_debug_item,
 240                            sc_net_debug_item) {
 241                /* discover the head of the list miscast as a sc */
 242                if (&sc->sc_net_debug_item == &sock_containers)
 243                        break;
 244
 245                /* use sc_page to detect real scs in the list */
 246                if (sc->sc_page != NULL) {
 247                        ret = sc;
 248                        break;
 249                }
 250        }
 251
 252        return ret;
 253}
 254
 255static void *sc_seq_start(struct seq_file *seq, loff_t *pos)
 256{
 257        struct o2net_sock_debug *sd = seq->private;
 258        struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
 259
 260        spin_lock(&o2net_debug_lock);
 261        sc = next_sc(dummy_sc);
 262        spin_unlock(&o2net_debug_lock);
 263
 264        return sc;
 265}
 266
 267static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 268{
 269        struct o2net_sock_debug *sd = seq->private;
 270        struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
 271
 272        spin_lock(&o2net_debug_lock);
 273        sc = next_sc(dummy_sc);
 274        list_del_init(&dummy_sc->sc_net_debug_item);
 275        if (sc)
 276                list_add(&dummy_sc->sc_net_debug_item, &sc->sc_net_debug_item);
 277        spin_unlock(&o2net_debug_lock);
 278
 279        return sc; /* unused, just needs to be null when done */
 280}
 281
 282#ifdef CONFIG_OCFS2_FS_STATS
 283# define sc_send_count(_s)              ((_s)->sc_send_count)
 284# define sc_recv_count(_s)              ((_s)->sc_recv_count)
 285# define sc_tv_acquiry_total_ns(_s)     (ktime_to_ns((_s)->sc_tv_acquiry_total))
 286# define sc_tv_send_total_ns(_s)        (ktime_to_ns((_s)->sc_tv_send_total))
 287# define sc_tv_status_total_ns(_s)      (ktime_to_ns((_s)->sc_tv_status_total))
 288# define sc_tv_process_total_ns(_s)     (ktime_to_ns((_s)->sc_tv_process_total))
 289#else
 290# define sc_send_count(_s)              (0U)
 291# define sc_recv_count(_s)              (0U)
 292# define sc_tv_acquiry_total_ns(_s)     (0LL)
 293# define sc_tv_send_total_ns(_s)        (0LL)
 294# define sc_tv_status_total_ns(_s)      (0LL)
 295# define sc_tv_process_total_ns(_s)     (0LL)
 296#endif
 297
 298/* So that debugfs.ocfs2 can determine which format is being used */
 299#define O2NET_STATS_STR_VERSION         1
 300static void sc_show_sock_stats(struct seq_file *seq,
 301                               struct o2net_sock_container *sc)
 302{
 303        if (!sc)
 304                return;
 305
 306        seq_printf(seq, "%d,%u,%lu,%lld,%lld,%lld,%lu,%lld\n", O2NET_STATS_STR_VERSION,
 307                   sc->sc_node->nd_num, (unsigned long)sc_send_count(sc),
 308                   (long long)sc_tv_acquiry_total_ns(sc),
 309                   (long long)sc_tv_send_total_ns(sc),
 310                   (long long)sc_tv_status_total_ns(sc),
 311                   (unsigned long)sc_recv_count(sc),
 312                   (long long)sc_tv_process_total_ns(sc));
 313}
 314
 315static void sc_show_sock_container(struct seq_file *seq,
 316                                   struct o2net_sock_container *sc)
 317{
 318        struct inet_sock *inet = NULL;
 319        __be32 saddr = 0, daddr = 0;
 320        __be16 sport = 0, dport = 0;
 321
 322        if (!sc)
 323                return;
 324
 325        if (sc->sc_sock) {
 326                inet = inet_sk(sc->sc_sock->sk);
 327                /* the stack's structs aren't sparse endian clean */
 328                saddr = (__force __be32)inet->inet_saddr;
 329                daddr = (__force __be32)inet->inet_daddr;
 330                sport = (__force __be16)inet->inet_sport;
 331                dport = (__force __be16)inet->inet_dport;
 332        }
 333
 334        /* XXX sigh, inet-> doesn't have sparse annotation so any
 335         * use of it here generates a warning with -Wbitwise */
 336        seq_printf(seq, "%p:\n"
 337                   "  krefs:           %d\n"
 338                   "  sock:            %pI4:%u -> "
 339                                      "%pI4:%u\n"
 340                   "  remote node:     %s\n"
 341                   "  page off:        %zu\n"
 342                   "  handshake ok:    %u\n"
 343                   "  timer:           %lld usecs\n"
 344                   "  data ready:      %lld usecs\n"
 345                   "  advance start:   %lld usecs\n"
 346                   "  advance stop:    %lld usecs\n"
 347                   "  func start:      %lld usecs\n"
 348                   "  func stop:       %lld usecs\n"
 349                   "  func key:        0x%08x\n"
 350                   "  func type:       %u\n",
 351                   sc,
 352                   atomic_read(&sc->sc_kref.refcount),
 353                   &saddr, inet ? ntohs(sport) : 0,
 354                   &daddr, inet ? ntohs(dport) : 0,
 355                   sc->sc_node->nd_name,
 356                   sc->sc_page_off,
 357                   sc->sc_handshake_ok,
 358                   (long long)ktime_to_us(sc->sc_tv_timer),
 359                   (long long)ktime_to_us(sc->sc_tv_data_ready),
 360                   (long long)ktime_to_us(sc->sc_tv_advance_start),
 361                   (long long)ktime_to_us(sc->sc_tv_advance_stop),
 362                   (long long)ktime_to_us(sc->sc_tv_func_start),
 363                   (long long)ktime_to_us(sc->sc_tv_func_stop),
 364                   sc->sc_msg_key,
 365                   sc->sc_msg_type);
 366}
 367
 368static int sc_seq_show(struct seq_file *seq, void *v)
 369{
 370        struct o2net_sock_debug *sd = seq->private;
 371        struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
 372
 373        spin_lock(&o2net_debug_lock);
 374        sc = next_sc(dummy_sc);
 375
 376        if (sc) {
 377                if (sd->dbg_ctxt == SHOW_SOCK_CONTAINERS)
 378                        sc_show_sock_container(seq, sc);
 379                else
 380                        sc_show_sock_stats(seq, sc);
 381        }
 382
 383        spin_unlock(&o2net_debug_lock);
 384
 385        return 0;
 386}
 387
 388static void sc_seq_stop(struct seq_file *seq, void *v)
 389{
 390}
 391
 392static const struct seq_operations sc_seq_ops = {
 393        .start = sc_seq_start,
 394        .next = sc_seq_next,
 395        .stop = sc_seq_stop,
 396        .show = sc_seq_show,
 397};
 398
 399static int sc_common_open(struct file *file, int ctxt)
 400{
 401        struct o2net_sock_debug *sd;
 402        struct o2net_sock_container *dummy_sc;
 403
 404        dummy_sc = kzalloc(sizeof(*dummy_sc), GFP_KERNEL);
 405        if (!dummy_sc)
 406                return -ENOMEM;
 407
 408        sd = __seq_open_private(file, &sc_seq_ops, sizeof(*sd));
 409        if (!sd) {
 410                kfree(dummy_sc);
 411                return -ENOMEM;
 412        }
 413
 414        sd->dbg_ctxt = ctxt;
 415        sd->dbg_sock = dummy_sc;
 416
 417        o2net_debug_add_sc(dummy_sc);
 418
 419        return 0;
 420}
 421
 422static int sc_fop_release(struct inode *inode, struct file *file)
 423{
 424        struct seq_file *seq = file->private_data;
 425        struct o2net_sock_debug *sd = seq->private;
 426        struct o2net_sock_container *dummy_sc = sd->dbg_sock;
 427
 428        o2net_debug_del_sc(dummy_sc);
 429        return seq_release_private(inode, file);
 430}
 431
 432static int stats_fop_open(struct inode *inode, struct file *file)
 433{
 434        return sc_common_open(file, SHOW_SOCK_STATS);
 435}
 436
 437static const struct file_operations stats_seq_fops = {
 438        .open = stats_fop_open,
 439        .read = seq_read,
 440        .llseek = seq_lseek,
 441        .release = sc_fop_release,
 442};
 443
 444static int sc_fop_open(struct inode *inode, struct file *file)
 445{
 446        return sc_common_open(file, SHOW_SOCK_CONTAINERS);
 447}
 448
 449static const struct file_operations sc_seq_fops = {
 450        .open = sc_fop_open,
 451        .read = seq_read,
 452        .llseek = seq_lseek,
 453        .release = sc_fop_release,
 454};
 455
 456static int o2net_fill_bitmap(char *buf, int len)
 457{
 458        unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)];
 459        int i = -1, out = 0;
 460
 461        o2net_fill_node_map(map, sizeof(map));
 462
 463        while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES)
 464                out += snprintf(buf + out, PAGE_SIZE - out, "%d ", i);
 465        out += snprintf(buf + out, PAGE_SIZE - out, "\n");
 466
 467        return out;
 468}
 469
 470static int nodes_fop_open(struct inode *inode, struct file *file)
 471{
 472        char *buf;
 473
 474        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 475        if (!buf)
 476                return -ENOMEM;
 477
 478        i_size_write(inode, o2net_fill_bitmap(buf, PAGE_SIZE));
 479
 480        file->private_data = buf;
 481
 482        return 0;
 483}
 484
 485static int o2net_debug_release(struct inode *inode, struct file *file)
 486{
 487        kfree(file->private_data);
 488        return 0;
 489}
 490
 491static ssize_t o2net_debug_read(struct file *file, char __user *buf,
 492                                size_t nbytes, loff_t *ppos)
 493{
 494        return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
 495                                       i_size_read(file->f_mapping->host));
 496}
 497
 498static const struct file_operations nodes_fops = {
 499        .open           = nodes_fop_open,
 500        .release        = o2net_debug_release,
 501        .read           = o2net_debug_read,
 502        .llseek         = generic_file_llseek,
 503};
 504
 505void o2net_debugfs_exit(void)
 506{
 507        debugfs_remove(nodes_dentry);
 508        debugfs_remove(stats_dentry);
 509        debugfs_remove(sc_dentry);
 510        debugfs_remove(nst_dentry);
 511        debugfs_remove(o2net_dentry);
 512}
 513
 514int o2net_debugfs_init(void)
 515{
 516        umode_t mode = S_IFREG|S_IRUSR;
 517
 518        o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL);
 519        if (o2net_dentry)
 520                nst_dentry = debugfs_create_file(NST_DEBUG_NAME, mode,
 521                                        o2net_dentry, NULL, &nst_seq_fops);
 522        if (nst_dentry)
 523                sc_dentry = debugfs_create_file(SC_DEBUG_NAME, mode,
 524                                        o2net_dentry, NULL, &sc_seq_fops);
 525        if (sc_dentry)
 526                stats_dentry = debugfs_create_file(STATS_DEBUG_NAME, mode,
 527                                        o2net_dentry, NULL, &stats_seq_fops);
 528        if (stats_dentry)
 529                nodes_dentry = debugfs_create_file(NODES_DEBUG_NAME, mode,
 530                                        o2net_dentry, NULL, &nodes_fops);
 531        if (nodes_dentry)
 532                return 0;
 533
 534        o2net_debugfs_exit();
 535        mlog_errno(-ENOMEM);
 536        return -ENOMEM;
 537}
 538
 539#endif  /* CONFIG_DEBUG_FS */
 540