linux/lib/dynamic_debug.c
<<
>>
Prefs
   1/*
   2 * lib/dynamic_debug.c
   3 *
   4 * make pr_debug()/dev_dbg() calls runtime configurable based upon their
   5 * source module.
   6 *
   7 * Copyright (C) 2008 Jason Baron <jbaron@redhat.com>
   8 * By Greg Banks <gnb@melbourne.sgi.com>
   9 * Copyright (c) 2008 Silicon Graphics Inc.  All Rights Reserved.
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/moduleparam.h>
  15#include <linux/kallsyms.h>
  16#include <linux/version.h>
  17#include <linux/types.h>
  18#include <linux/mutex.h>
  19#include <linux/proc_fs.h>
  20#include <linux/seq_file.h>
  21#include <linux/list.h>
  22#include <linux/sysctl.h>
  23#include <linux/ctype.h>
  24#include <linux/string.h>
  25#include <linux/uaccess.h>
  26#include <linux/dynamic_debug.h>
  27#include <linux/debugfs.h>
  28#include <linux/slab.h>
  29
  30extern struct _ddebug __start___verbose[];
  31extern struct _ddebug __stop___verbose[];
  32
  33/* dynamic_debug_enabled, and dynamic_debug_enabled2 are bitmasks in which
  34 * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
  35 * use independent hash functions, to reduce the chance of false positives.
  36 */
  37long long dynamic_debug_enabled;
  38EXPORT_SYMBOL_GPL(dynamic_debug_enabled);
  39long long dynamic_debug_enabled2;
  40EXPORT_SYMBOL_GPL(dynamic_debug_enabled2);
  41
  42struct ddebug_table {
  43        struct list_head link;
  44        char *mod_name;
  45        unsigned int num_ddebugs;
  46        unsigned int num_enabled;
  47        struct _ddebug *ddebugs;
  48};
  49
  50struct ddebug_query {
  51        const char *filename;
  52        const char *module;
  53        const char *function;
  54        const char *format;
  55        unsigned int first_lineno, last_lineno;
  56};
  57
  58struct ddebug_iter {
  59        struct ddebug_table *table;
  60        unsigned int idx;
  61};
  62
  63static DEFINE_MUTEX(ddebug_lock);
  64static LIST_HEAD(ddebug_tables);
  65static int verbose = 0;
  66
  67/* Return the last part of a pathname */
  68static inline const char *basename(const char *path)
  69{
  70        const char *tail = strrchr(path, '/');
  71        return tail ? tail+1 : path;
  72}
  73
  74/* format a string into buf[] which describes the _ddebug's flags */
  75static char *ddebug_describe_flags(struct _ddebug *dp, char *buf,
  76                                    size_t maxlen)
  77{
  78        char *p = buf;
  79
  80        BUG_ON(maxlen < 4);
  81        if (dp->flags & _DPRINTK_FLAGS_PRINT)
  82                *p++ = 'p';
  83        if (p == buf)
  84                *p++ = '-';
  85        *p = '\0';
  86
  87        return buf;
  88}
  89
  90/*
  91 * must be called with ddebug_lock held
  92 */
  93
  94static int disabled_hash(char hash, bool first_table)
  95{
  96        struct ddebug_table *dt;
  97        char table_hash_value;
  98
  99        list_for_each_entry(dt, &ddebug_tables, link) {
 100                if (first_table)
 101                        table_hash_value = dt->ddebugs->primary_hash;
 102                else
 103                        table_hash_value = dt->ddebugs->secondary_hash;
 104                if (dt->num_enabled && (hash == table_hash_value))
 105                        return 0;
 106        }
 107        return 1;
 108}
 109
 110/*
 111 * Search the tables for _ddebug's which match the given
 112 * `query' and apply the `flags' and `mask' to them.  Tells
 113 * the user which ddebug's were changed, or whether none
 114 * were matched.
 115 */
 116static void ddebug_change(const struct ddebug_query *query,
 117                           unsigned int flags, unsigned int mask)
 118{
 119        int i;
 120        struct ddebug_table *dt;
 121        unsigned int newflags;
 122        unsigned int nfound = 0;
 123        char flagbuf[8];
 124
 125        /* search for matching ddebugs */
 126        mutex_lock(&ddebug_lock);
 127        list_for_each_entry(dt, &ddebug_tables, link) {
 128
 129                /* match against the module name */
 130                if (query->module != NULL &&
 131                    strcmp(query->module, dt->mod_name))
 132                        continue;
 133
 134                for (i = 0 ; i < dt->num_ddebugs ; i++) {
 135                        struct _ddebug *dp = &dt->ddebugs[i];
 136
 137                        /* match against the source filename */
 138                        if (query->filename != NULL &&
 139                            strcmp(query->filename, dp->filename) &&
 140                            strcmp(query->filename, basename(dp->filename)))
 141                                continue;
 142
 143                        /* match against the function */
 144                        if (query->function != NULL &&
 145                            strcmp(query->function, dp->function))
 146                                continue;
 147
 148                        /* match against the format */
 149                        if (query->format != NULL &&
 150                            strstr(dp->format, query->format) == NULL)
 151                                continue;
 152
 153                        /* match against the line number range */
 154                        if (query->first_lineno &&
 155                            dp->lineno < query->first_lineno)
 156                                continue;
 157                        if (query->last_lineno &&
 158                            dp->lineno > query->last_lineno)
 159                                continue;
 160
 161                        nfound++;
 162
 163                        newflags = (dp->flags & mask) | flags;
 164                        if (newflags == dp->flags)
 165                                continue;
 166
 167                        if (!newflags)
 168                                dt->num_enabled--;
 169                        else if (!dp->flags)
 170                                dt->num_enabled++;
 171                        dp->flags = newflags;
 172                        if (newflags) {
 173                                dynamic_debug_enabled |=
 174                                                (1LL << dp->primary_hash);
 175                                dynamic_debug_enabled2 |=
 176                                                (1LL << dp->secondary_hash);
 177                        } else {
 178                                if (disabled_hash(dp->primary_hash, true))
 179                                        dynamic_debug_enabled &=
 180                                                ~(1LL << dp->primary_hash);
 181                                if (disabled_hash(dp->secondary_hash, false))
 182                                        dynamic_debug_enabled2 &=
 183                                                ~(1LL << dp->secondary_hash);
 184                        }
 185                        if (verbose)
 186                                printk(KERN_INFO
 187                                        "ddebug: changed %s:%d [%s]%s %s\n",
 188                                        dp->filename, dp->lineno,
 189                                        dt->mod_name, dp->function,
 190                                        ddebug_describe_flags(dp, flagbuf,
 191                                                        sizeof(flagbuf)));
 192                }
 193        }
 194        mutex_unlock(&ddebug_lock);
 195
 196        if (!nfound && verbose)
 197                printk(KERN_INFO "ddebug: no matches for query\n");
 198}
 199
 200/*
 201 * Split the buffer `buf' into space-separated words.
 202 * Handles simple " and ' quoting, i.e. without nested,
 203 * embedded or escaped \".  Return the number of words
 204 * or <0 on error.
 205 */
 206static int ddebug_tokenize(char *buf, char *words[], int maxwords)
 207{
 208        int nwords = 0;
 209
 210        while (*buf) {
 211                char *end;
 212
 213                /* Skip leading whitespace */
 214                buf = skip_spaces(buf);
 215                if (!*buf)
 216                        break;  /* oh, it was trailing whitespace */
 217
 218                /* Run `end' over a word, either whitespace separated or quoted */
 219                if (*buf == '"' || *buf == '\'') {
 220                        int quote = *buf++;
 221                        for (end = buf ; *end && *end != quote ; end++)
 222                                ;
 223                        if (!*end)
 224                                return -EINVAL; /* unclosed quote */
 225                } else {
 226                        for (end = buf ; *end && !isspace(*end) ; end++)
 227                                ;
 228                        BUG_ON(end == buf);
 229                }
 230                /* Here `buf' is the start of the word, `end' is one past the end */
 231
 232                if (nwords == maxwords)
 233                        return -EINVAL; /* ran out of words[] before bytes */
 234                if (*end)
 235                        *end++ = '\0';  /* terminate the word */
 236                words[nwords++] = buf;
 237                buf = end;
 238        }
 239
 240        if (verbose) {
 241                int i;
 242                printk(KERN_INFO "%s: split into words:", __func__);
 243                for (i = 0 ; i < nwords ; i++)
 244                        printk(" \"%s\"", words[i]);
 245                printk("\n");
 246        }
 247
 248        return nwords;
 249}
 250
 251/*
 252 * Parse a single line number.  Note that the empty string ""
 253 * is treated as a special case and converted to zero, which
 254 * is later treated as a "don't care" value.
 255 */
 256static inline int parse_lineno(const char *str, unsigned int *val)
 257{
 258        char *end = NULL;
 259        BUG_ON(str == NULL);
 260        if (*str == '\0') {
 261                *val = 0;
 262                return 0;
 263        }
 264        *val = simple_strtoul(str, &end, 10);
 265        return end == NULL || end == str || *end != '\0' ? -EINVAL : 0;
 266}
 267
 268/*
 269 * Undo octal escaping in a string, inplace.  This is useful to
 270 * allow the user to express a query which matches a format
 271 * containing embedded spaces.
 272 */
 273#define isodigit(c)             ((c) >= '0' && (c) <= '7')
 274static char *unescape(char *str)
 275{
 276        char *in = str;
 277        char *out = str;
 278
 279        while (*in) {
 280                if (*in == '\\') {
 281                        if (in[1] == '\\') {
 282                                *out++ = '\\';
 283                                in += 2;
 284                                continue;
 285                        } else if (in[1] == 't') {
 286                                *out++ = '\t';
 287                                in += 2;
 288                                continue;
 289                        } else if (in[1] == 'n') {
 290                                *out++ = '\n';
 291                                in += 2;
 292                                continue;
 293                        } else if (isodigit(in[1]) &&
 294                                 isodigit(in[2]) &&
 295                                 isodigit(in[3])) {
 296                                *out++ = ((in[1] - '0')<<6) |
 297                                          ((in[2] - '0')<<3) |
 298                                          (in[3] - '0');
 299                                in += 4;
 300                                continue;
 301                        }
 302                }
 303                *out++ = *in++;
 304        }
 305        *out = '\0';
 306
 307        return str;
 308}
 309
 310/*
 311 * Parse words[] as a ddebug query specification, which is a series
 312 * of (keyword, value) pairs chosen from these possibilities:
 313 *
 314 * func <function-name>
 315 * file <full-pathname>
 316 * file <base-filename>
 317 * module <module-name>
 318 * format <escaped-string-to-find-in-format>
 319 * line <lineno>
 320 * line <first-lineno>-<last-lineno> // where either may be empty
 321 */
 322static int ddebug_parse_query(char *words[], int nwords,
 323                               struct ddebug_query *query)
 324{
 325        unsigned int i;
 326
 327        /* check we have an even number of words */
 328        if (nwords % 2 != 0)
 329                return -EINVAL;
 330        memset(query, 0, sizeof(*query));
 331
 332        for (i = 0 ; i < nwords ; i += 2) {
 333                if (!strcmp(words[i], "func"))
 334                        query->function = words[i+1];
 335                else if (!strcmp(words[i], "file"))
 336                        query->filename = words[i+1];
 337                else if (!strcmp(words[i], "module"))
 338                        query->module = words[i+1];
 339                else if (!strcmp(words[i], "format"))
 340                        query->format = unescape(words[i+1]);
 341                else if (!strcmp(words[i], "line")) {
 342                        char *first = words[i+1];
 343                        char *last = strchr(first, '-');
 344                        if (last)
 345                                *last++ = '\0';
 346                        if (parse_lineno(first, &query->first_lineno) < 0)
 347                                return -EINVAL;
 348                        if (last != NULL) {
 349                                /* range <first>-<last> */
 350                                if (parse_lineno(last, &query->last_lineno) < 0)
 351                                        return -EINVAL;
 352                        } else {
 353                                query->last_lineno = query->first_lineno;
 354                        }
 355                } else {
 356                        if (verbose)
 357                                printk(KERN_ERR "%s: unknown keyword \"%s\"\n",
 358                                        __func__, words[i]);
 359                        return -EINVAL;
 360                }
 361        }
 362
 363        if (verbose)
 364                printk(KERN_INFO "%s: q->function=\"%s\" q->filename=\"%s\" "
 365                       "q->module=\"%s\" q->format=\"%s\" q->lineno=%u-%u\n",
 366                        __func__, query->function, query->filename,
 367                        query->module, query->format, query->first_lineno,
 368                        query->last_lineno);
 369
 370        return 0;
 371}
 372
 373/*
 374 * Parse `str' as a flags specification, format [-+=][p]+.
 375 * Sets up *maskp and *flagsp to be used when changing the
 376 * flags fields of matched _ddebug's.  Returns 0 on success
 377 * or <0 on error.
 378 */
 379static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
 380                               unsigned int *maskp)
 381{
 382        unsigned flags = 0;
 383        int op = '=';
 384
 385        switch (*str) {
 386        case '+':
 387        case '-':
 388        case '=':
 389                op = *str++;
 390                break;
 391        default:
 392                return -EINVAL;
 393        }
 394        if (verbose)
 395                printk(KERN_INFO "%s: op='%c'\n", __func__, op);
 396
 397        for ( ; *str ; ++str) {
 398                switch (*str) {
 399                case 'p':
 400                        flags |= _DPRINTK_FLAGS_PRINT;
 401                        break;
 402                default:
 403                        return -EINVAL;
 404                }
 405        }
 406        if (flags == 0)
 407                return -EINVAL;
 408        if (verbose)
 409                printk(KERN_INFO "%s: flags=0x%x\n", __func__, flags);
 410
 411        /* calculate final *flagsp, *maskp according to mask and op */
 412        switch (op) {
 413        case '=':
 414                *maskp = 0;
 415                *flagsp = flags;
 416                break;
 417        case '+':
 418                *maskp = ~0U;
 419                *flagsp = flags;
 420                break;
 421        case '-':
 422                *maskp = ~flags;
 423                *flagsp = 0;
 424                break;
 425        }
 426        if (verbose)
 427                printk(KERN_INFO "%s: *flagsp=0x%x *maskp=0x%x\n",
 428                        __func__, *flagsp, *maskp);
 429        return 0;
 430}
 431
 432/*
 433 * File_ops->write method for <debugfs>/dynamic_debug/conrol.  Gathers the
 434 * command text from userspace, parses and executes it.
 435 */
 436static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
 437                                  size_t len, loff_t *offp)
 438{
 439        unsigned int flags = 0, mask = 0;
 440        struct ddebug_query query;
 441#define MAXWORDS 9
 442        int nwords;
 443        char *words[MAXWORDS];
 444        char tmpbuf[256];
 445
 446        if (len == 0)
 447                return 0;
 448        /* we don't check *offp -- multiple writes() are allowed */
 449        if (len > sizeof(tmpbuf)-1)
 450                return -E2BIG;
 451        if (copy_from_user(tmpbuf, ubuf, len))
 452                return -EFAULT;
 453        tmpbuf[len] = '\0';
 454        if (verbose)
 455                printk(KERN_INFO "%s: read %d bytes from userspace\n",
 456                        __func__, (int)len);
 457
 458        nwords = ddebug_tokenize(tmpbuf, words, MAXWORDS);
 459        if (nwords <= 0)
 460                return -EINVAL;
 461        if (ddebug_parse_query(words, nwords-1, &query))
 462                return -EINVAL;
 463        if (ddebug_parse_flags(words[nwords-1], &flags, &mask))
 464                return -EINVAL;
 465
 466        /* actually go and implement the change */
 467        ddebug_change(&query, flags, mask);
 468
 469        *offp += len;
 470        return len;
 471}
 472
 473/*
 474 * Set the iterator to point to the first _ddebug object
 475 * and return a pointer to that first object.  Returns
 476 * NULL if there are no _ddebugs at all.
 477 */
 478static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
 479{
 480        if (list_empty(&ddebug_tables)) {
 481                iter->table = NULL;
 482                iter->idx = 0;
 483                return NULL;
 484        }
 485        iter->table = list_entry(ddebug_tables.next,
 486                                 struct ddebug_table, link);
 487        iter->idx = 0;
 488        return &iter->table->ddebugs[iter->idx];
 489}
 490
 491/*
 492 * Advance the iterator to point to the next _ddebug
 493 * object from the one the iterator currently points at,
 494 * and returns a pointer to the new _ddebug.  Returns
 495 * NULL if the iterator has seen all the _ddebugs.
 496 */
 497static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
 498{
 499        if (iter->table == NULL)
 500                return NULL;
 501        if (++iter->idx == iter->table->num_ddebugs) {
 502                /* iterate to next table */
 503                iter->idx = 0;
 504                if (list_is_last(&iter->table->link, &ddebug_tables)) {
 505                        iter->table = NULL;
 506                        return NULL;
 507                }
 508                iter->table = list_entry(iter->table->link.next,
 509                                         struct ddebug_table, link);
 510        }
 511        return &iter->table->ddebugs[iter->idx];
 512}
 513
 514/*
 515 * Seq_ops start method.  Called at the start of every
 516 * read() call from userspace.  Takes the ddebug_lock and
 517 * seeks the seq_file's iterator to the given position.
 518 */
 519static void *ddebug_proc_start(struct seq_file *m, loff_t *pos)
 520{
 521        struct ddebug_iter *iter = m->private;
 522        struct _ddebug *dp;
 523        int n = *pos;
 524
 525        if (verbose)
 526                printk(KERN_INFO "%s: called m=%p *pos=%lld\n",
 527                        __func__, m, (unsigned long long)*pos);
 528
 529        mutex_lock(&ddebug_lock);
 530
 531        if (!n)
 532                return SEQ_START_TOKEN;
 533        if (n < 0)
 534                return NULL;
 535        dp = ddebug_iter_first(iter);
 536        while (dp != NULL && --n > 0)
 537                dp = ddebug_iter_next(iter);
 538        return dp;
 539}
 540
 541/*
 542 * Seq_ops next method.  Called several times within a read()
 543 * call from userspace, with ddebug_lock held.  Walks to the
 544 * next _ddebug object with a special case for the header line.
 545 */
 546static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
 547{
 548        struct ddebug_iter *iter = m->private;
 549        struct _ddebug *dp;
 550
 551        if (verbose)
 552                printk(KERN_INFO "%s: called m=%p p=%p *pos=%lld\n",
 553                        __func__, m, p, (unsigned long long)*pos);
 554
 555        if (p == SEQ_START_TOKEN)
 556                dp = ddebug_iter_first(iter);
 557        else
 558                dp = ddebug_iter_next(iter);
 559        ++*pos;
 560        return dp;
 561}
 562
 563/*
 564 * Seq_ops show method.  Called several times within a read()
 565 * call from userspace, with ddebug_lock held.  Formats the
 566 * current _ddebug as a single human-readable line, with a
 567 * special case for the header line.
 568 */
 569static int ddebug_proc_show(struct seq_file *m, void *p)
 570{
 571        struct ddebug_iter *iter = m->private;
 572        struct _ddebug *dp = p;
 573        char flagsbuf[8];
 574
 575        if (verbose)
 576                printk(KERN_INFO "%s: called m=%p p=%p\n",
 577                        __func__, m, p);
 578
 579        if (p == SEQ_START_TOKEN) {
 580                seq_puts(m,
 581                        "# filename:lineno [module]function flags format\n");
 582                return 0;
 583        }
 584
 585        seq_printf(m, "%s:%u [%s]%s %s \"",
 586                   dp->filename, dp->lineno,
 587                   iter->table->mod_name, dp->function,
 588                   ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf)));
 589        seq_escape(m, dp->format, "\t\r\n\"");
 590        seq_puts(m, "\"\n");
 591
 592        return 0;
 593}
 594
 595/*
 596 * Seq_ops stop method.  Called at the end of each read()
 597 * call from userspace.  Drops ddebug_lock.
 598 */
 599static void ddebug_proc_stop(struct seq_file *m, void *p)
 600{
 601        if (verbose)
 602                printk(KERN_INFO "%s: called m=%p p=%p\n",
 603                        __func__, m, p);
 604        mutex_unlock(&ddebug_lock);
 605}
 606
 607static const struct seq_operations ddebug_proc_seqops = {
 608        .start = ddebug_proc_start,
 609        .next = ddebug_proc_next,
 610        .show = ddebug_proc_show,
 611        .stop = ddebug_proc_stop
 612};
 613
 614/*
 615 * File_ops->open method for <debugfs>/dynamic_debug/control.  Does the seq_file
 616 * setup dance, and also creates an iterator to walk the _ddebugs.
 617 * Note that we create a seq_file always, even for O_WRONLY files
 618 * where it's not needed, as doing so simplifies the ->release method.
 619 */
 620static int ddebug_proc_open(struct inode *inode, struct file *file)
 621{
 622        struct ddebug_iter *iter;
 623        int err;
 624
 625        if (verbose)
 626                printk(KERN_INFO "%s: called\n", __func__);
 627
 628        iter = kzalloc(sizeof(*iter), GFP_KERNEL);
 629        if (iter == NULL)
 630                return -ENOMEM;
 631
 632        err = seq_open(file, &ddebug_proc_seqops);
 633        if (err) {
 634                kfree(iter);
 635                return err;
 636        }
 637        ((struct seq_file *) file->private_data)->private = iter;
 638        return 0;
 639}
 640
 641static const struct file_operations ddebug_proc_fops = {
 642        .owner = THIS_MODULE,
 643        .open = ddebug_proc_open,
 644        .read = seq_read,
 645        .llseek = seq_lseek,
 646        .release = seq_release_private,
 647        .write = ddebug_proc_write
 648};
 649
 650/*
 651 * Allocate a new ddebug_table for the given module
 652 * and add it to the global list.
 653 */
 654int ddebug_add_module(struct _ddebug *tab, unsigned int n,
 655                             const char *name)
 656{
 657        struct ddebug_table *dt;
 658        char *new_name;
 659
 660        dt = kzalloc(sizeof(*dt), GFP_KERNEL);
 661        if (dt == NULL)
 662                return -ENOMEM;
 663        new_name = kstrdup(name, GFP_KERNEL);
 664        if (new_name == NULL) {
 665                kfree(dt);
 666                return -ENOMEM;
 667        }
 668        dt->mod_name = new_name;
 669        dt->num_ddebugs = n;
 670        dt->num_enabled = 0;
 671        dt->ddebugs = tab;
 672
 673        mutex_lock(&ddebug_lock);
 674        list_add_tail(&dt->link, &ddebug_tables);
 675        mutex_unlock(&ddebug_lock);
 676
 677        if (verbose)
 678                printk(KERN_INFO "%u debug prints in module %s\n",
 679                                 n, dt->mod_name);
 680        return 0;
 681}
 682EXPORT_SYMBOL_GPL(ddebug_add_module);
 683
 684static void ddebug_table_free(struct ddebug_table *dt)
 685{
 686        list_del_init(&dt->link);
 687        kfree(dt->mod_name);
 688        kfree(dt);
 689}
 690
 691/*
 692 * Called in response to a module being unloaded.  Removes
 693 * any ddebug_table's which point at the module.
 694 */
 695int ddebug_remove_module(const char *mod_name)
 696{
 697        struct ddebug_table *dt, *nextdt;
 698        int ret = -ENOENT;
 699
 700        if (verbose)
 701                printk(KERN_INFO "%s: removing module \"%s\"\n",
 702                                __func__, mod_name);
 703
 704        mutex_lock(&ddebug_lock);
 705        list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
 706                if (!strcmp(dt->mod_name, mod_name)) {
 707                        ddebug_table_free(dt);
 708                        ret = 0;
 709                }
 710        }
 711        mutex_unlock(&ddebug_lock);
 712        return ret;
 713}
 714EXPORT_SYMBOL_GPL(ddebug_remove_module);
 715
 716static void ddebug_remove_all_tables(void)
 717{
 718        mutex_lock(&ddebug_lock);
 719        while (!list_empty(&ddebug_tables)) {
 720                struct ddebug_table *dt = list_entry(ddebug_tables.next,
 721                                                      struct ddebug_table,
 722                                                      link);
 723                ddebug_table_free(dt);
 724        }
 725        mutex_unlock(&ddebug_lock);
 726}
 727
 728static int __init dynamic_debug_init(void)
 729{
 730        struct dentry *dir, *file;
 731        struct _ddebug *iter, *iter_start;
 732        const char *modname = NULL;
 733        int ret = 0;
 734        int n = 0;
 735
 736        dir = debugfs_create_dir("dynamic_debug", NULL);
 737        if (!dir)
 738                return -ENOMEM;
 739        file = debugfs_create_file("control", 0644, dir, NULL,
 740                                        &ddebug_proc_fops);
 741        if (!file) {
 742                debugfs_remove(dir);
 743                return -ENOMEM;
 744        }
 745        if (__start___verbose != __stop___verbose) {
 746                iter = __start___verbose;
 747                modname = iter->modname;
 748                iter_start = iter;
 749                for (; iter < __stop___verbose; iter++) {
 750                        if (strcmp(modname, iter->modname)) {
 751                                ret = ddebug_add_module(iter_start, n, modname);
 752                                if (ret)
 753                                        goto out_free;
 754                                n = 0;
 755                                modname = iter->modname;
 756                                iter_start = iter;
 757                        }
 758                        n++;
 759                }
 760                ret = ddebug_add_module(iter_start, n, modname);
 761        }
 762out_free:
 763        if (ret) {
 764                ddebug_remove_all_tables();
 765                debugfs_remove(dir);
 766                debugfs_remove(file);
 767        }
 768        return 0;
 769}
 770module_init(dynamic_debug_init);
 771
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.