linux/drivers/net/netconsole.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/net/netconsole.c
   3 *
   4 *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
   5 *
   6 *  This file contains the implementation of an IRQ-safe, crash-safe
   7 *  kernel console implementation that outputs kernel messages to the
   8 *  network.
   9 *
  10 * Modification history:
  11 *
  12 * 2001-09-17    started by Ingo Molnar.
  13 * 2003-08-11    2.6 port by Matt Mackall
  14 *               simplified options
  15 *               generic card hooks
  16 *               works non-modular
  17 * 2003-09-07    rewritten with netpoll api
  18 */
  19
  20/****************************************************************
  21 *      This program is free software; you can redistribute it and/or modify
  22 *      it under the terms of the GNU General Public License as published by
  23 *      the Free Software Foundation; either version 2, or (at your option)
  24 *      any later version.
  25 *
  26 *      This program is distributed in the hope that it will be useful,
  27 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  28 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  29 *      GNU General Public License for more details.
  30 *
  31 *      You should have received a copy of the GNU General Public License
  32 *      along with this program; if not, write to the Free Software
  33 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  34 *
  35 ****************************************************************/
  36
  37#include <linux/mm.h>
  38#include <linux/init.h>
  39#include <linux/module.h>
  40#include <linux/slab.h>
  41#include <linux/console.h>
  42#include <linux/moduleparam.h>
  43#include <linux/string.h>
  44#include <linux/netpoll.h>
  45#include <linux/inet.h>
  46#include <linux/configfs.h>
  47
  48MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
  49MODULE_DESCRIPTION("Console driver for network interfaces");
  50MODULE_LICENSE("GPL");
  51
  52#define MAX_PARAM_LENGTH        256
  53#define MAX_PRINT_CHUNK         1000
  54
  55static char config[MAX_PARAM_LENGTH];
  56module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
  57MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");
  58
  59#ifndef MODULE
  60static int __init option_setup(char *opt)
  61{
  62        strlcpy(config, opt, MAX_PARAM_LENGTH);
  63        return 1;
  64}
  65__setup("netconsole=", option_setup);
  66#endif  /* MODULE */
  67
  68/* Linked list of all configured targets */
  69static LIST_HEAD(target_list);
  70
  71/* This needs to be a spinlock because write_msg() cannot sleep */
  72static DEFINE_SPINLOCK(target_list_lock);
  73
  74/**
  75 * struct netconsole_target - Represents a configured netconsole target.
  76 * @list:       Links this target into the target_list.
  77 * @item:       Links us into the configfs subsystem hierarchy.
  78 * @enabled:    On / off knob to enable / disable target.
  79 *              Visible from userspace (read-write).
  80 *              We maintain a strict 1:1 correspondence between this and
  81 *              whether the corresponding netpoll is active or inactive.
  82 *              Also, other parameters of a target may be modified at
  83 *              runtime only when it is disabled (enabled == 0).
  84 * @np:         The netpoll structure for this target.
  85 *              Contains the other userspace visible parameters:
  86 *              dev_name        (read-write)
  87 *              local_port      (read-write)
  88 *              remote_port     (read-write)
  89 *              local_ip        (read-write)
  90 *              remote_ip       (read-write)
  91 *              local_mac       (read-only)
  92 *              remote_mac      (read-write)
  93 */
  94struct netconsole_target {
  95        struct list_head        list;
  96#ifdef  CONFIG_NETCONSOLE_DYNAMIC
  97        struct config_item      item;
  98#endif
  99        int                     enabled;
 100        struct netpoll          np;
 101};
 102
 103#ifdef  CONFIG_NETCONSOLE_DYNAMIC
 104
 105static struct configfs_subsystem netconsole_subsys;
 106
 107static int __init dynamic_netconsole_init(void)
 108{
 109        config_group_init(&netconsole_subsys.su_group);
 110        mutex_init(&netconsole_subsys.su_mutex);
 111        return configfs_register_subsystem(&netconsole_subsys);
 112}
 113
 114static void __exit dynamic_netconsole_exit(void)
 115{
 116        configfs_unregister_subsystem(&netconsole_subsys);
 117}
 118
 119/*
 120 * Targets that were created by parsing the boot/module option string
 121 * do not exist in the configfs hierarchy (and have NULL names) and will
 122 * never go away, so make these a no-op for them.
 123 */
 124static void netconsole_target_get(struct netconsole_target *nt)
 125{
 126        if (config_item_name(&nt->item))
 127                config_item_get(&nt->item);
 128}
 129
 130static void netconsole_target_put(struct netconsole_target *nt)
 131{
 132        if (config_item_name(&nt->item))
 133                config_item_put(&nt->item);
 134}
 135
 136#else   /* !CONFIG_NETCONSOLE_DYNAMIC */
 137
 138static int __init dynamic_netconsole_init(void)
 139{
 140        return 0;
 141}
 142
 143static void __exit dynamic_netconsole_exit(void)
 144{
 145}
 146
 147/*
 148 * No danger of targets going away from under us when dynamic
 149 * reconfigurability is off.
 150 */
 151static void netconsole_target_get(struct netconsole_target *nt)
 152{
 153}
 154
 155static void netconsole_target_put(struct netconsole_target *nt)
 156{
 157}
 158
 159#endif  /* CONFIG_NETCONSOLE_DYNAMIC */
 160
 161/* Allocate new target (from boot/module param) and setup netpoll for it */
 162static struct netconsole_target *alloc_param_target(char *target_config)
 163{
 164        int err = -ENOMEM;
 165        struct netconsole_target *nt;
 166
 167        /*
 168         * Allocate and initialize with defaults.
 169         * Note that these targets get their config_item fields zeroed-out.
 170         */
 171        nt = kzalloc(sizeof(*nt), GFP_KERNEL);
 172        if (!nt)
 173                goto fail;
 174
 175        nt->np.name = "netconsole";
 176        strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
 177        nt->np.local_port = 6665;
 178        nt->np.remote_port = 6666;
 179        memset(nt->np.remote_mac, 0xff, ETH_ALEN);
 180
 181        /* Parse parameters and setup netpoll */
 182        err = netpoll_parse_options(&nt->np, target_config);
 183        if (err)
 184                goto fail;
 185
 186        err = netpoll_setup(&nt->np);
 187        if (err)
 188                goto fail;
 189
 190        nt->enabled = 1;
 191
 192        return nt;
 193
 194fail:
 195        kfree(nt);
 196        return ERR_PTR(err);
 197}
 198
 199/* Cleanup netpoll for given target (from boot/module param) and free it */
 200static void free_param_target(struct netconsole_target *nt)
 201{
 202        netpoll_cleanup(&nt->np);
 203        kfree(nt);
 204}
 205
 206#ifdef  CONFIG_NETCONSOLE_DYNAMIC
 207
 208/*
 209 * Our subsystem hierarchy is:
 210 *
 211 * /sys/kernel/config/netconsole/
 212 *                              |
 213 *                              <target>/
 214 *                              |       enabled
 215 *                              |       dev_name
 216 *                              |       local_port
 217 *                              |       remote_port
 218 *                              |       local_ip
 219 *                              |       remote_ip
 220 *                              |       local_mac
 221 *                              |       remote_mac
 222 *                              |
 223 *                              <target>/...
 224 */
 225
 226struct netconsole_target_attr {
 227        struct configfs_attribute       attr;
 228        ssize_t                         (*show)(struct netconsole_target *nt,
 229                                                char *buf);
 230        ssize_t                         (*store)(struct netconsole_target *nt,
 231                                                 const char *buf,
 232                                                 size_t count);
 233};
 234
 235static struct netconsole_target *to_target(struct config_item *item)
 236{
 237        return item ?
 238                container_of(item, struct netconsole_target, item) :
 239                NULL;
 240}
 241
 242/*
 243 * Attribute operations for netconsole_target.
 244 */
 245
 246static ssize_t show_enabled(struct netconsole_target *nt, char *buf)
 247{
 248        return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled);
 249}
 250
 251static ssize_t show_dev_name(struct netconsole_target *nt, char *buf)
 252{
 253        return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name);
 254}
 255
 256static ssize_t show_local_port(struct netconsole_target *nt, char *buf)
 257{
 258        return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port);
 259}
 260
 261static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
 262{
 263        return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port);
 264}
 265
 266static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
 267{
 268        return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
 269}
 270
 271static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
 272{
 273        return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
 274}
 275
 276static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
 277{
 278        struct net_device *dev = nt->np.dev;
 279        static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 280
 281        return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast);
 282}
 283
 284static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf)
 285{
 286        return snprintf(buf, PAGE_SIZE, "%pM\n", nt->np.remote_mac);
 287}
 288
 289/*
 290 * This one is special -- targets created through the configfs interface
 291 * are not enabled (and the corresponding netpoll activated) by default.
 292 * The user is expected to set the desired parameters first (which
 293 * would enable him to dynamically add new netpoll targets for new
 294 * network interfaces as and when they come up).
 295 */
 296static ssize_t store_enabled(struct netconsole_target *nt,
 297                             const char *buf,
 298                             size_t count)
 299{
 300        int enabled;
 301        int err;
 302
 303        err = kstrtoint(buf, 10, &enabled);
 304        if (err < 0)
 305                return err;
 306        if (enabled < 0 || enabled > 1)
 307                return -EINVAL;
 308        if (enabled == nt->enabled) {
 309                printk(KERN_INFO "netconsole: network logging has already %s\n",
 310                                nt->enabled ? "started" : "stopped");
 311                return -EINVAL;
 312        }
 313
 314        if (enabled) {  /* 1 */
 315
 316                /*
 317                 * Skip netpoll_parse_options() -- all the attributes are
 318                 * already configured via configfs. Just print them out.
 319                 */
 320                netpoll_print_options(&nt->np);
 321
 322                err = netpoll_setup(&nt->np);
 323                if (err)
 324                        return err;
 325
 326                printk(KERN_INFO "netconsole: network logging started\n");
 327
 328        } else {        /* 0 */
 329                netpoll_cleanup(&nt->np);
 330        }
 331
 332        nt->enabled = enabled;
 333
 334        return strnlen(buf, count);
 335}
 336
 337static ssize_t store_dev_name(struct netconsole_target *nt,
 338                              const char *buf,
 339                              size_t count)
 340{
 341        size_t len;
 342
 343        if (nt->enabled) {
 344                printk(KERN_ERR "netconsole: target (%s) is enabled, "
 345                                "disable to update parameters\n",
 346                                config_item_name(&nt->item));
 347                return -EINVAL;
 348        }
 349
 350        strlcpy(nt->np.dev_name, buf, IFNAMSIZ);
 351
 352        /* Get rid of possible trailing newline from echo(1) */
 353        len = strnlen(nt->np.dev_name, IFNAMSIZ);
 354        if (nt->np.dev_name[len - 1] == '\n')
 355                nt->np.dev_name[len - 1] = '\0';
 356
 357        return strnlen(buf, count);
 358}
 359
 360static ssize_t store_local_port(struct netconsole_target *nt,
 361                                const char *buf,
 362                                size_t count)
 363{
 364        int rv;
 365
 366        if (nt->enabled) {
 367                printk(KERN_ERR "netconsole: target (%s) is enabled, "
 368                                "disable to update parameters\n",
 369                                config_item_name(&nt->item));
 370                return -EINVAL;
 371        }
 372
 373        rv = kstrtou16(buf, 10, &nt->np.local_port);
 374        if (rv < 0)
 375                return rv;
 376        return strnlen(buf, count);
 377}
 378
 379static ssize_t store_remote_port(struct netconsole_target *nt,
 380                                 const char *buf,
 381                                 size_t count)
 382{
 383        int rv;
 384
 385        if (nt->enabled) {
 386                printk(KERN_ERR "netconsole: target (%s) is enabled, "
 387                                "disable to update parameters\n",
 388                                config_item_name(&nt->item));
 389                return -EINVAL;
 390        }
 391
 392        rv = kstrtou16(buf, 10, &nt->np.remote_port);
 393        if (rv < 0)
 394                return rv;
 395        return strnlen(buf, count);
 396}
 397
 398static ssize_t store_local_ip(struct netconsole_target *nt,
 399                              const char *buf,
 400                              size_t count)
 401{
 402        if (nt->enabled) {
 403                printk(KERN_ERR "netconsole: target (%s) is enabled, "
 404                                "disable to update parameters\n",
 405                                config_item_name(&nt->item));
 406                return -EINVAL;
 407        }
 408
 409        nt->np.local_ip = in_aton(buf);
 410
 411        return strnlen(buf, count);
 412}
 413
 414static ssize_t store_remote_ip(struct netconsole_target *nt,
 415                               const char *buf,
 416                               size_t count)
 417{
 418        if (nt->enabled) {
 419                printk(KERN_ERR "netconsole: target (%s) is enabled, "
 420                                "disable to update parameters\n",
 421                                config_item_name(&nt->item));
 422                return -EINVAL;
 423        }
 424
 425        nt->np.remote_ip = in_aton(buf);
 426
 427        return strnlen(buf, count);
 428}
 429
 430static ssize_t store_remote_mac(struct netconsole_target *nt,
 431                                const char *buf,
 432                                size_t count)
 433{
 434        u8 remote_mac[ETH_ALEN];
 435
 436        if (nt->enabled) {
 437                printk(KERN_ERR "netconsole: target (%s) is enabled, "
 438                                "disable to update parameters\n",
 439                                config_item_name(&nt->item));
 440                return -EINVAL;
 441        }
 442
 443        if (!mac_pton(buf, remote_mac))
 444                return -EINVAL;
 445        if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n')
 446                return -EINVAL;
 447        memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
 448
 449        return strnlen(buf, count);
 450}
 451
 452/*
 453 * Attribute definitions for netconsole_target.
 454 */
 455
 456#define NETCONSOLE_TARGET_ATTR_RO(_name)                                \
 457static struct netconsole_target_attr netconsole_target_##_name =        \
 458        __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL)
 459
 460#define NETCONSOLE_TARGET_ATTR_RW(_name)                                \
 461static struct netconsole_target_attr netconsole_target_##_name =        \
 462        __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name)
 463
 464NETCONSOLE_TARGET_ATTR_RW(enabled);
 465NETCONSOLE_TARGET_ATTR_RW(dev_name);
 466NETCONSOLE_TARGET_ATTR_RW(local_port);
 467NETCONSOLE_TARGET_ATTR_RW(remote_port);
 468NETCONSOLE_TARGET_ATTR_RW(local_ip);
 469NETCONSOLE_TARGET_ATTR_RW(remote_ip);
 470NETCONSOLE_TARGET_ATTR_RO(local_mac);
 471NETCONSOLE_TARGET_ATTR_RW(remote_mac);
 472
 473static struct configfs_attribute *netconsole_target_attrs[] = {
 474        &netconsole_target_enabled.attr,
 475        &netconsole_target_dev_name.attr,
 476        &netconsole_target_local_port.attr,
 477        &netconsole_target_remote_port.attr,
 478        &netconsole_target_local_ip.attr,
 479        &netconsole_target_remote_ip.attr,
 480        &netconsole_target_local_mac.attr,
 481        &netconsole_target_remote_mac.attr,
 482        NULL,
 483};
 484
 485/*
 486 * Item operations and type for netconsole_target.
 487 */
 488
 489static void netconsole_target_release(struct config_item *item)
 490{
 491        kfree(to_target(item));
 492}
 493
 494static ssize_t netconsole_target_attr_show(struct config_item *item,
 495                                           struct configfs_attribute *attr,
 496                                           char *buf)
 497{
 498        ssize_t ret = -EINVAL;
 499        struct netconsole_target *nt = to_target(item);
 500        struct netconsole_target_attr *na =
 501                container_of(attr, struct netconsole_target_attr, attr);
 502
 503        if (na->show)
 504                ret = na->show(nt, buf);
 505
 506        return ret;
 507}
 508
 509static ssize_t netconsole_target_attr_store(struct config_item *item,
 510                                            struct configfs_attribute *attr,
 511                                            const char *buf,
 512                                            size_t count)
 513{
 514        ssize_t ret = -EINVAL;
 515        struct netconsole_target *nt = to_target(item);
 516        struct netconsole_target_attr *na =
 517                container_of(attr, struct netconsole_target_attr, attr);
 518
 519        if (na->store)
 520                ret = na->store(nt, buf, count);
 521
 522        return ret;
 523}
 524
 525static struct configfs_item_operations netconsole_target_item_ops = {
 526        .release                = netconsole_target_release,
 527        .show_attribute         = netconsole_target_attr_show,
 528        .store_attribute        = netconsole_target_attr_store,
 529};
 530
 531static struct config_item_type netconsole_target_type = {
 532        .ct_attrs               = netconsole_target_attrs,
 533        .ct_item_ops            = &netconsole_target_item_ops,
 534        .ct_owner               = THIS_MODULE,
 535};
 536
 537/*
 538 * Group operations and type for netconsole_subsys.
 539 */
 540
 541static struct config_item *make_netconsole_target(struct config_group *group,
 542                                                  const char *name)
 543{
 544        unsigned long flags;
 545        struct netconsole_target *nt;
 546
 547        /*
 548         * Allocate and initialize with defaults.
 549         * Target is disabled at creation (enabled == 0).
 550         */
 551        nt = kzalloc(sizeof(*nt), GFP_KERNEL);
 552        if (!nt)
 553                return ERR_PTR(-ENOMEM);
 554
 555        nt->np.name = "netconsole";
 556        strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
 557        nt->np.local_port = 6665;
 558        nt->np.remote_port = 6666;
 559        memset(nt->np.remote_mac, 0xff, ETH_ALEN);
 560
 561        /* Initialize the config_item member */
 562        config_item_init_type_name(&nt->item, name, &netconsole_target_type);
 563
 564        /* Adding, but it is disabled */
 565        spin_lock_irqsave(&target_list_lock, flags);
 566        list_add(&nt->list, &target_list);
 567        spin_unlock_irqrestore(&target_list_lock, flags);
 568
 569        return &nt->item;
 570}
 571
 572static void drop_netconsole_target(struct config_group *group,
 573                                   struct config_item *item)
 574{
 575        unsigned long flags;
 576        struct netconsole_target *nt = to_target(item);
 577
 578        spin_lock_irqsave(&target_list_lock, flags);
 579        list_del(&nt->list);
 580        spin_unlock_irqrestore(&target_list_lock, flags);
 581
 582        /*
 583         * The target may have never been enabled, or was manually disabled
 584         * before being removed so netpoll may have already been cleaned up.
 585         */
 586        if (nt->enabled)
 587                netpoll_cleanup(&nt->np);
 588
 589        config_item_put(&nt->item);
 590}
 591
 592static struct configfs_group_operations netconsole_subsys_group_ops = {
 593        .make_item      = make_netconsole_target,
 594        .drop_item      = drop_netconsole_target,
 595};
 596
 597static struct config_item_type netconsole_subsys_type = {
 598        .ct_group_ops   = &netconsole_subsys_group_ops,
 599        .ct_owner       = THIS_MODULE,
 600};
 601
 602/* The netconsole configfs subsystem */
 603static struct configfs_subsystem netconsole_subsys = {
 604        .su_group       = {
 605                .cg_item        = {
 606                        .ci_namebuf     = "netconsole",
 607                        .ci_type        = &netconsole_subsys_type,
 608                },
 609        },
 610};
 611
 612#endif  /* CONFIG_NETCONSOLE_DYNAMIC */
 613
 614/* Handle network interface device notifications */
 615static int netconsole_netdev_event(struct notifier_block *this,
 616                                   unsigned long event,
 617                                   void *ptr)
 618{
 619        unsigned long flags;
 620        struct netconsole_target *nt;
 621        struct net_device *dev = ptr;
 622        bool stopped = false;
 623
 624        if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
 625              event == NETDEV_RELEASE || event == NETDEV_JOIN))
 626                goto done;
 627
 628        spin_lock_irqsave(&target_list_lock, flags);
 629        list_for_each_entry(nt, &target_list, list) {
 630                netconsole_target_get(nt);
 631                if (nt->np.dev == dev) {
 632                        switch (event) {
 633                        case NETDEV_CHANGENAME:
 634                                strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
 635                                break;
 636                        case NETDEV_RELEASE:
 637                        case NETDEV_JOIN:
 638                        case NETDEV_UNREGISTER:
 639                                /*
 640                                 * rtnl_lock already held
 641                                 */
 642                                if (nt->np.dev) {
 643                                        __netpoll_cleanup(&nt->np);
 644                                        dev_put(nt->np.dev);
 645                                        nt->np.dev = NULL;
 646                                }
 647                                nt->enabled = 0;
 648                                stopped = true;
 649                                break;
 650                        }
 651                }
 652                netconsole_target_put(nt);
 653        }
 654        spin_unlock_irqrestore(&target_list_lock, flags);
 655        if (stopped) {
 656                printk(KERN_INFO "netconsole: network logging stopped on "
 657                       "interface %s as it ", dev->name);
 658                switch (event) {
 659                case NETDEV_UNREGISTER:
 660                        printk(KERN_CONT "unregistered\n");
 661                        break;
 662                case NETDEV_RELEASE:
 663                        printk(KERN_CONT "released slaves\n");
 664                        break;
 665                case NETDEV_JOIN:
 666                        printk(KERN_CONT "is joining a master device\n");
 667                        break;
 668                }
 669        }
 670
 671done:
 672        return NOTIFY_DONE;
 673}
 674
 675static struct notifier_block netconsole_netdev_notifier = {
 676        .notifier_call  = netconsole_netdev_event,
 677};
 678
 679static void write_msg(struct console *con, const char *msg, unsigned int len)
 680{
 681        int frag, left;
 682        unsigned long flags;
 683        struct netconsole_target *nt;
 684        const char *tmp;
 685
 686        /* Avoid taking lock and disabling interrupts unnecessarily */
 687        if (list_empty(&target_list))
 688                return;
 689
 690        spin_lock_irqsave(&target_list_lock, flags);
 691        list_for_each_entry(nt, &target_list, list) {
 692                netconsole_target_get(nt);
 693                if (nt->enabled && netif_running(nt->np.dev)) {
 694                        /*
 695                         * We nest this inside the for-each-target loop above
 696                         * so that we're able to get as much logging out to
 697                         * at least one target if we die inside here, instead
 698                         * of unnecessarily keeping all targets in lock-step.
 699                         */
 700                        tmp = msg;
 701                        for (left = len; left;) {
 702                                frag = min(left, MAX_PRINT_CHUNK);
 703                                netpoll_send_udp(&nt->np, tmp, frag);
 704                                tmp += frag;
 705                                left -= frag;
 706                        }
 707                }
 708                netconsole_target_put(nt);
 709        }
 710        spin_unlock_irqrestore(&target_list_lock, flags);
 711}
 712
 713static struct console netconsole = {
 714        .name   = "netcon",
 715        .flags  = CON_ENABLED,
 716        .write  = write_msg,
 717};
 718
 719static int __init init_netconsole(void)
 720{
 721        int err;
 722        struct netconsole_target *nt, *tmp;
 723        unsigned long flags;
 724        char *target_config;
 725        char *input = config;
 726
 727        if (strnlen(input, MAX_PARAM_LENGTH)) {
 728                while ((target_config = strsep(&input, ";"))) {
 729                        nt = alloc_param_target(target_config);
 730                        if (IS_ERR(nt)) {
 731                                err = PTR_ERR(nt);
 732                                goto fail;
 733                        }
 734                        /* Dump existing printks when we register */
 735                        netconsole.flags |= CON_PRINTBUFFER;
 736
 737                        spin_lock_irqsave(&target_list_lock, flags);
 738                        list_add(&nt->list, &target_list);
 739                        spin_unlock_irqrestore(&target_list_lock, flags);
 740                }
 741        }
 742
 743        err = register_netdevice_notifier(&netconsole_netdev_notifier);
 744        if (err)
 745                goto fail;
 746
 747        err = dynamic_netconsole_init();
 748        if (err)
 749                goto undonotifier;
 750
 751        register_console(&netconsole);
 752        printk(KERN_INFO "netconsole: network logging started\n");
 753
 754        return err;
 755
 756undonotifier:
 757        unregister_netdevice_notifier(&netconsole_netdev_notifier);
 758
 759fail:
 760        printk(KERN_ERR "netconsole: cleaning up\n");
 761
 762        /*
 763         * Remove all targets and destroy them (only targets created
 764         * from the boot/module option exist here). Skipping the list
 765         * lock is safe here, and netpoll_cleanup() will sleep.
 766         */
 767        list_for_each_entry_safe(nt, tmp, &target_list, list) {
 768                list_del(&nt->list);
 769                free_param_target(nt);
 770        }
 771
 772        return err;
 773}
 774
 775static void __exit cleanup_netconsole(void)
 776{
 777        struct netconsole_target *nt, *tmp;
 778
 779        unregister_console(&netconsole);
 780        dynamic_netconsole_exit();
 781        unregister_netdevice_notifier(&netconsole_netdev_notifier);
 782
 783        /*
 784         * Targets created via configfs pin references on our module
 785         * and would first be rmdir(2)'ed from userspace. We reach
 786         * here only when they are already destroyed, and only those
 787         * created from the boot/module option are left, so remove and
 788         * destroy them. Skipping the list lock is safe here, and
 789         * netpoll_cleanup() will sleep.
 790         */
 791        list_for_each_entry_safe(nt, tmp, &target_list, list) {
 792                list_del(&nt->list);
 793                free_param_target(nt);
 794        }
 795}
 796
 797/*
 798 * Use late_initcall to ensure netconsole is
 799 * initialized after network device driver if built-in.
 800 *
 801 * late_initcall() and module_init() are identical if built as module.
 802 */
 803late_initcall(init_netconsole);
 804module_exit(cleanup_netconsole);
 805
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.