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        struct seq_file *seq;
 189        int ret;
 190
 191        dummy_nst = kmalloc(sizeof(struct o2net_send_tracking), GFP_KERNEL);
 192        if (dummy_nst == NULL) {
 193                ret = -ENOMEM;
 194                goto out;
 195        }
 196        dummy_nst->st_task = NULL;
 197
 198        ret = seq_open(file, &nst_seq_ops);
 199        if (ret)
 200                goto out;
 201
 202        seq = file->private_data;
 203        seq->private = dummy_nst;
 204        o2net_debug_add_nst(dummy_nst);
 205
 206        dummy_nst = NULL;
 207
 208out:
 209        kfree(dummy_nst);
 210        return ret;
 211}
 212
 213static int nst_fop_release(struct inode *inode, struct file *file)
 214{
 215        struct seq_file *seq = file->private_data;
 216        struct o2net_send_tracking *dummy_nst = seq->private;
 217
 218        o2net_debug_del_nst(dummy_nst);
 219        return seq_release_private(inode, file);
 220}
 221
 222static const struct file_operations nst_seq_fops = {
 223        .open = nst_fop_open,
 224        .read = seq_read,
 225        .llseek = seq_lseek,
 226        .release = nst_fop_release,
 227};
 228
 229void o2net_debug_add_sc(struct o2net_sock_container *sc)
 230{
 231        spin_lock(&o2net_debug_lock);
 232        list_add(&sc->sc_net_debug_item, &sock_containers);
 233        spin_unlock(&o2net_debug_lock);
 234}
 235
 236void o2net_debug_del_sc(struct o2net_sock_container *sc)
 237{
 238        spin_lock(&o2net_debug_lock);
 239        list_del_init(&sc->sc_net_debug_item);
 240        spin_unlock(&o2net_debug_lock);
 241}
 242
 243struct o2net_sock_debug {
 244        int dbg_ctxt;
 245        struct o2net_sock_container *dbg_sock;
 246};
 247
 248static struct o2net_sock_container
 249                        *next_sc(struct o2net_sock_container *sc_start)
 250{
 251        struct o2net_sock_container *sc, *ret = NULL;
 252
 253        assert_spin_locked(&o2net_debug_lock);
 254
 255        list_for_each_entry(sc, &sc_start->sc_net_debug_item,
 256                            sc_net_debug_item) {
 257                /* discover the head of the list miscast as a sc */
 258                if (&sc->sc_net_debug_item == &sock_containers)
 259                        break;
 260
 261                /* use sc_page to detect real scs in the list */
 262                if (sc->sc_page != NULL) {
 263                        ret = sc;
 264                        break;
 265                }
 266        }
 267
 268        return ret;
 269}
 270
 271static void *sc_seq_start(struct seq_file *seq, loff_t *pos)
 272{
 273        struct o2net_sock_debug *sd = seq->private;
 274        struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
 275
 276        spin_lock(&o2net_debug_lock);
 277        sc = next_sc(dummy_sc);
 278        spin_unlock(&o2net_debug_lock);
 279
 280        return sc;
 281}
 282
 283static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 284{
 285        struct o2net_sock_debug *sd = seq->private;
 286        struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
 287
 288        spin_lock(&o2net_debug_lock);
 289        sc = next_sc(dummy_sc);
 290        list_del_init(&dummy_sc->sc_net_debug_item);
 291        if (sc)
 292                list_add(&dummy_sc->sc_net_debug_item, &sc->sc_net_debug_item);
 293        spin_unlock(&o2net_debug_lock);
 294
 295        return sc; /* unused, just needs to be null when done */
 296}
 297
 298#ifdef CONFIG_OCFS2_FS_STATS
 299# define sc_send_count(_s)              ((_s)->sc_send_count)
 300# define sc_recv_count(_s)              ((_s)->sc_recv_count)
 301# define sc_tv_acquiry_total_ns(_s)     (ktime_to_ns((_s)->sc_tv_acquiry_total))
 302# define sc_tv_send_total_ns(_s)        (ktime_to_ns((_s)->sc_tv_send_total))
 303# define sc_tv_status_total_ns(_s)      (ktime_to_ns((_s)->sc_tv_status_total))
 304# define sc_tv_process_total_ns(_s)     (ktime_to_ns((_s)->sc_tv_process_total))
 305#else
 306# define sc_send_count(_s)              (0U)
 307# define sc_recv_count(_s)              (0U)
 308# define sc_tv_acquiry_total_ns(_s)     (0LL)
 309# define sc_tv_send_total_ns(_s)        (0LL)
 310# define sc_tv_status_total_ns(_s)      (0LL)
 311# define sc_tv_process_total_ns(_s)     (0LL)
 312#endif
 313
 314/* So that debugfs.ocfs2 can determine which format is being used */
 315#define O2NET_STATS_STR_VERSION         1
 316static void sc_show_sock_stats(struct seq_file *seq,
 317                               struct o2net_sock_container *sc)
 318{
 319        if (!sc)
 320                return;
 321
 322        seq_printf(seq, "%d,%u,%lu,%lld,%lld,%lld,%lu,%lld\n", O2NET_STATS_STR_VERSION,
 323                   sc->sc_node->nd_num, (unsigned long)sc_send_count(sc),
 324                   (long long)sc_tv_acquiry_total_ns(sc),
 325                   (long long)sc_tv_send_total_ns(sc),
 326                   (long long)sc_tv_status_total_ns(sc),
 327                   (unsigned long)sc_recv_count(sc),
 328                   (long long)sc_tv_process_total_ns(sc));
 329}
 330
 331static void sc_show_sock_container(struct seq_file *seq,
 332                                   struct o2net_sock_container *sc)
 333{
 334        struct inet_sock *inet = NULL;
 335        __be32 saddr = 0, daddr = 0;
 336        __be16 sport = 0, dport = 0;
 337
 338        if (!sc)
 339                return;
 340
 341        if (sc->sc_sock) {
 342                inet = inet_sk(sc->sc_sock->sk);
 343                /* the stack's structs aren't sparse endian clean */
 344                saddr = (__force __be32)inet->inet_saddr;
 345                daddr = (__force __be32)inet->inet_daddr;
 346                sport = (__force __be16)inet->inet_sport;
 347                dport = (__force __be16)inet->inet_dport;
 348        }
 349
 350        /* XXX sigh, inet-> doesn't have sparse annotation so any
 351         * use of it here generates a warning with -Wbitwise */
 352        seq_printf(seq, "%p:\n"
 353                   "  krefs:           %d\n"
 354                   "  sock:            %pI4:%u -> "
 355                                      "%pI4:%u\n"
 356                   "  remote node:     %s\n"
 357                   "  page off:        %zu\n"
 358                   "  handshake ok:    %u\n"
 359                   "  timer:           %lld usecs\n"
 360                   "  data ready:      %lld usecs\n"
 361                   "  advance start:   %lld usecs\n"
 362                   "  advance stop:    %lld usecs\n"
 363                   "  func start:      %lld usecs\n"
 364                   "  func stop:       %lld usecs\n"
 365                   "  func key:        0x%08x\n"
 366                   "  func type:       %u\n",
 367                   sc,
 368                   atomic_read(&sc->sc_kref.refcount),
 369                   &saddr, inet ? ntohs(sport) : 0,
 370                   &daddr, inet ? ntohs(dport) : 0,
 371                   sc->sc_node->nd_name,
 372                   sc->sc_page_off,
 373                   sc->sc_handshake_ok,
 374                   (long long)ktime_to_us(sc->sc_tv_timer),
 375                   (long long)ktime_to_us(sc->sc_tv_data_ready),
 376                   (long long)ktime_to_us(sc->sc_tv_advance_start),
 377                   (long long)ktime_to_us(sc->sc_tv_advance_stop),
 378                   (long long)ktime_to_us(sc->sc_tv_func_start),
 379                   (long long)ktime_to_us(sc->sc_tv_func_stop),
 380                   sc->sc_msg_key,
 381                   sc->sc_msg_type);
 382}
 383
 384static int sc_seq_show(struct seq_file *seq, void *v)
 385{
 386        struct o2net_sock_debug *sd = seq->private;
 387        struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;
 388
 389        spin_lock(&o2net_debug_lock);
 390        sc = next_sc(dummy_sc);
 391
 392        if (sc) {
 393                if (sd->dbg_ctxt == SHOW_SOCK_CONTAINERS)
 394                        sc_show_sock_container(seq, sc);
 395                else
 396                        sc_show_sock_stats(seq, sc);
 397        }
 398
 399        spin_unlock(&o2net_debug_lock);
 400
 401        return 0;
 402}
 403
 404static void sc_seq_stop(struct seq_file *seq, void *v)
 405{
 406}
 407
 408static const struct seq_operations sc_seq_ops = {
 409        .start = sc_seq_start,
 410        .next = sc_seq_next,
 411        .stop = sc_seq_stop,
 412        .show = sc_seq_show,
 413};
 414
 415static int sc_common_open(struct file *file, struct o2net_sock_debug *sd)
 416{
 417        struct o2net_sock_container *dummy_sc;
 418        struct seq_file *seq;
 419        int ret;
 420
 421        dummy_sc = kmalloc(sizeof(struct o2net_sock_container), GFP_KERNEL);
 422        if (dummy_sc == NULL) {
 423                ret = -ENOMEM;
 424                goto out;
 425        }
 426        dummy_sc->sc_page = NULL;
 427
 428        ret = seq_open(file, &sc_seq_ops);
 429        if (ret)
 430                goto out;
 431
 432        seq = file->private_data;
 433        seq->private = sd;
 434        sd->dbg_sock = dummy_sc;
 435        o2net_debug_add_sc(dummy_sc);
 436
 437        dummy_sc = NULL;
 438
 439out:
 440        kfree(dummy_sc);
 441        return ret;
 442}
 443
 444static int sc_fop_release(struct inode *inode, struct file *file)
 445{
 446        struct seq_file *seq = file->private_data;
 447        struct o2net_sock_debug *sd = seq->private;
 448        struct o2net_sock_container *dummy_sc = sd->dbg_sock;
 449
 450        o2net_debug_del_sc(dummy_sc);
 451        return seq_release_private(inode, file);
 452}
 453
 454static int stats_fop_open(struct inode *inode, struct file *file)
 455{
 456        struct o2net_sock_debug *sd;
 457
 458        sd = kmalloc(sizeof(struct o2net_sock_debug), GFP_KERNEL);
 459        if (sd == NULL)
 460                return -ENOMEM;
 461
 462        sd->dbg_ctxt = SHOW_SOCK_STATS;
 463        sd->dbg_sock = NULL;
 464
 465        return sc_common_open(file, sd);
 466}
 467
 468static const struct file_operations stats_seq_fops = {
 469        .open = stats_fop_open,
 470        .read = seq_read,
 471        .llseek = seq_lseek,
 472        .release = sc_fop_release,
 473};
 474
 475static int sc_fop_open(struct inode *inode, struct file *file)
 476{
 477        struct o2net_sock_debug *sd;
 478
 479        sd = kmalloc(sizeof(struct o2net_sock_debug), GFP_KERNEL);
 480        if (sd == NULL)
 481                return -ENOMEM;
 482
 483        sd->dbg_ctxt = SHOW_SOCK_CONTAINERS;
 484        sd->dbg_sock = NULL;
 485
 486        return sc_common_open(file, sd);
 487}
 488
 489static const struct file_operations sc_seq_fops = {
 490        .open = sc_fop_open,
 491        .read = seq_read,
 492        .llseek = seq_lseek,
 493        .release = sc_fop_release,
 494};
 495
 496static int o2net_fill_bitmap(char *buf, int len)
 497{
 498        unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)];
 499        int i = -1, out = 0;
 500
 501        o2net_fill_node_map(map, sizeof(map));
 502
 503        while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES)
 504                out += snprintf(buf + out, PAGE_SIZE - out, "%d ", i);
 505        out += snprintf(buf + out, PAGE_SIZE - out, "\n");
 506
 507        return out;
 508}
 509
 510static int nodes_fop_open(struct inode *inode, struct file *file)
 511{
 512        char *buf;
 513
 514        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 515        if (!buf)
 516                return -ENOMEM;
 517
 518        i_size_write(inode, o2net_fill_bitmap(buf, PAGE_SIZE));
 519
 520        file->private_data = buf;
 521
 522        return 0;
 523}
 524
 525static int o2net_debug_release(struct inode *inode, struct file *file)
 526{
 527        kfree(file->private_data);
 528        return 0;
 529}
 530
 531static ssize_t o2net_debug_read(struct file *file, char __user *buf,
 532                                size_t nbytes, loff_t *ppos)
 533{
 534        return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
 535                                       i_size_read(file->f_mapping->host));
 536}
 537
 538static const struct file_operations nodes_fops = {
 539        .open           = nodes_fop_open,
 540        .release        = o2net_debug_release,
 541        .read           = o2net_debug_read,
 542        .llseek         = generic_file_llseek,
 543};
 544
 545void o2net_debugfs_exit(void)
 546{
 547        debugfs_remove(nodes_dentry);
 548        debugfs_remove(stats_dentry);
 549        debugfs_remove(sc_dentry);
 550        debugfs_remove(nst_dentry);
 551        debugfs_remove(o2net_dentry);
 552}
 553
 554int o2net_debugfs_init(void)
 555{
 556        umode_t mode = S_IFREG|S_IRUSR;
 557
 558        o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL);
 559        if (o2net_dentry)
 560                nst_dentry = debugfs_create_file(NST_DEBUG_NAME, mode,
 561                                        o2net_dentry, NULL, &nst_seq_fops);
 562        if (nst_dentry)
 563                sc_dentry = debugfs_create_file(SC_DEBUG_NAME, mode,
 564                                        o2net_dentry, NULL, &sc_seq_fops);
 565        if (sc_dentry)
 566                stats_dentry = debugfs_create_file(STATS_DEBUG_NAME, mode,
 567                                        o2net_dentry, NULL, &stats_seq_fops);
 568        if (stats_dentry)
 569                nodes_dentry = debugfs_create_file(NODES_DEBUG_NAME, mode,
 570                                        o2net_dentry, NULL, &nodes_fops);
 571        if (nodes_dentry)
 572                return 0;
 573
 574        o2net_debugfs_exit();
 575        mlog_errno(-ENOMEM);
 576        return -ENOMEM;
 577}
 578
 579#endif  /* CONFIG_DEBUG_FS */
 580