root/drivers/net/netconsole.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. option_setup
  2. dynamic_netconsole_init
  3. dynamic_netconsole_exit
  4. netconsole_target_get
  5. netconsole_target_put
  6. dynamic_netconsole_init
  7. dynamic_netconsole_exit
  8. netconsole_target_get
  9. netconsole_target_put
  10. alloc_param_target
  11. free_param_target
  12. to_target
  13. enabled_show
  14. extended_show
  15. dev_name_show
  16. local_port_show
  17. remote_port_show
  18. local_ip_show
  19. remote_ip_show
  20. local_mac_show
  21. remote_mac_show
  22. enabled_store
  23. extended_store
  24. dev_name_store
  25. local_port_store
  26. remote_port_store
  27. local_ip_store
  28. remote_ip_store
  29. remote_mac_store
  30. netconsole_target_release
  31. make_netconsole_target
  32. drop_netconsole_target
  33. netconsole_netdev_event
  34. send_ext_msg_udp
  35. write_ext_msg
  36. write_msg
  37. init_netconsole
  38. cleanup_netconsole

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  linux/drivers/net/netconsole.c
   4  *
   5  *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
   6  *
   7  *  This file contains the implementation of an IRQ-safe, crash-safe
   8  *  kernel console implementation that outputs kernel messages to the
   9  *  network.
  10  *
  11  * Modification history:
  12  *
  13  * 2001-09-17    started by Ingo Molnar.
  14  * 2003-08-11    2.6 port by Matt Mackall
  15  *               simplified options
  16  *               generic card hooks
  17  *               works non-modular
  18  * 2003-09-07    rewritten with netpoll api
  19  */
  20 
  21 /****************************************************************
  22  *
  23  ****************************************************************/
  24 
  25 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  26 
  27 #include <linux/mm.h>
  28 #include <linux/init.h>
  29 #include <linux/module.h>
  30 #include <linux/slab.h>
  31 #include <linux/console.h>
  32 #include <linux/moduleparam.h>
  33 #include <linux/kernel.h>
  34 #include <linux/string.h>
  35 #include <linux/netpoll.h>
  36 #include <linux/inet.h>
  37 #include <linux/configfs.h>
  38 #include <linux/etherdevice.h>
  39 
  40 MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
  41 MODULE_DESCRIPTION("Console driver for network interfaces");
  42 MODULE_LICENSE("GPL");
  43 
  44 #define MAX_PARAM_LENGTH        256
  45 #define MAX_PRINT_CHUNK         1000
  46 
  47 static char config[MAX_PARAM_LENGTH];
  48 module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
  49 MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");
  50 
  51 static bool oops_only = false;
  52 module_param(oops_only, bool, 0600);
  53 MODULE_PARM_DESC(oops_only, "Only log oops messages");
  54 
  55 #ifndef MODULE
  56 static int __init option_setup(char *opt)
  57 {
  58         strlcpy(config, opt, MAX_PARAM_LENGTH);
  59         return 1;
  60 }
  61 __setup("netconsole=", option_setup);
  62 #endif  /* MODULE */
  63 
  64 /* Linked list of all configured targets */
  65 static LIST_HEAD(target_list);
  66 
  67 /* This needs to be a spinlock because write_msg() cannot sleep */
  68 static DEFINE_SPINLOCK(target_list_lock);
  69 
  70 /*
  71  * Console driver for extended netconsoles.  Registered on the first use to
  72  * avoid unnecessarily enabling ext message formatting.
  73  */
  74 static struct console netconsole_ext;
  75 
  76 /**
  77  * struct netconsole_target - Represents a configured netconsole target.
  78  * @list:       Links this target into the target_list.
  79  * @item:       Links us into the configfs subsystem hierarchy.
  80  * @enabled:    On / off knob to enable / disable target.
  81  *              Visible from userspace (read-write).
  82  *              We maintain a strict 1:1 correspondence between this and
  83  *              whether the corresponding netpoll is active or inactive.
  84  *              Also, other parameters of a target may be modified at
  85  *              runtime only when it is disabled (enabled == 0).
  86  * @np:         The netpoll structure for this target.
  87  *              Contains the other userspace visible parameters:
  88  *              dev_name        (read-write)
  89  *              local_port      (read-write)
  90  *              remote_port     (read-write)
  91  *              local_ip        (read-write)
  92  *              remote_ip       (read-write)
  93  *              local_mac       (read-only)
  94  *              remote_mac      (read-write)
  95  */
  96 struct netconsole_target {
  97         struct list_head        list;
  98 #ifdef  CONFIG_NETCONSOLE_DYNAMIC
  99         struct config_item      item;
 100 #endif
 101         bool                    enabled;
 102         bool                    extended;
 103         struct netpoll          np;
 104 };
 105 
 106 #ifdef  CONFIG_NETCONSOLE_DYNAMIC
 107 
 108 static struct configfs_subsystem netconsole_subsys;
 109 static DEFINE_MUTEX(dynamic_netconsole_mutex);
 110 
 111 static int __init dynamic_netconsole_init(void)
 112 {
 113         config_group_init(&netconsole_subsys.su_group);
 114         mutex_init(&netconsole_subsys.su_mutex);
 115         return configfs_register_subsystem(&netconsole_subsys);
 116 }
 117 
 118 static void __exit dynamic_netconsole_exit(void)
 119 {
 120         configfs_unregister_subsystem(&netconsole_subsys);
 121 }
 122 
 123 /*
 124  * Targets that were created by parsing the boot/module option string
 125  * do not exist in the configfs hierarchy (and have NULL names) and will
 126  * never go away, so make these a no-op for them.
 127  */
 128 static void netconsole_target_get(struct netconsole_target *nt)
 129 {
 130         if (config_item_name(&nt->item))
 131                 config_item_get(&nt->item);
 132 }
 133 
 134 static void netconsole_target_put(struct netconsole_target *nt)
 135 {
 136         if (config_item_name(&nt->item))
 137                 config_item_put(&nt->item);
 138 }
 139 
 140 #else   /* !CONFIG_NETCONSOLE_DYNAMIC */
 141 
 142 static int __init dynamic_netconsole_init(void)
 143 {
 144         return 0;
 145 }
 146 
 147 static void __exit dynamic_netconsole_exit(void)
 148 {
 149 }
 150 
 151 /*
 152  * No danger of targets going away from under us when dynamic
 153  * reconfigurability is off.
 154  */
 155 static void netconsole_target_get(struct netconsole_target *nt)
 156 {
 157 }
 158 
 159 static void netconsole_target_put(struct netconsole_target *nt)
 160 {
 161 }
 162 
 163 #endif  /* CONFIG_NETCONSOLE_DYNAMIC */
 164 
 165 /* Allocate new target (from boot/module param) and setup netpoll for it */
 166 static struct netconsole_target *alloc_param_target(char *target_config)
 167 {
 168         int err = -ENOMEM;
 169         struct netconsole_target *nt;
 170 
 171         /*
 172          * Allocate and initialize with defaults.
 173          * Note that these targets get their config_item fields zeroed-out.
 174          */
 175         nt = kzalloc(sizeof(*nt), GFP_KERNEL);
 176         if (!nt)
 177                 goto fail;
 178 
 179         nt->np.name = "netconsole";
 180         strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
 181         nt->np.local_port = 6665;
 182         nt->np.remote_port = 6666;
 183         eth_broadcast_addr(nt->np.remote_mac);
 184 
 185         if (*target_config == '+') {
 186                 nt->extended = true;
 187                 target_config++;
 188         }
 189 
 190         /* Parse parameters and setup netpoll */
 191         err = netpoll_parse_options(&nt->np, target_config);
 192         if (err)
 193                 goto fail;
 194 
 195         err = netpoll_setup(&nt->np);
 196         if (err)
 197                 goto fail;
 198 
 199         nt->enabled = true;
 200 
 201         return nt;
 202 
 203 fail:
 204         kfree(nt);
 205         return ERR_PTR(err);
 206 }
 207 
 208 /* Cleanup netpoll for given target (from boot/module param) and free it */
 209 static void free_param_target(struct netconsole_target *nt)
 210 {
 211         netpoll_cleanup(&nt->np);
 212         kfree(nt);
 213 }
 214 
 215 #ifdef  CONFIG_NETCONSOLE_DYNAMIC
 216 
 217 /*
 218  * Our subsystem hierarchy is:
 219  *
 220  * /sys/kernel/config/netconsole/
 221  *                              |
 222  *                              <target>/
 223  *                              |       enabled
 224  *                              |       dev_name
 225  *                              |       local_port
 226  *                              |       remote_port
 227  *                              |       local_ip
 228  *                              |       remote_ip
 229  *                              |       local_mac
 230  *                              |       remote_mac
 231  *                              |
 232  *                              <target>/...
 233  */
 234 
 235 static 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 
 246 static ssize_t enabled_show(struct config_item *item, char *buf)
 247 {
 248         return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->enabled);
 249 }
 250 
 251 static ssize_t extended_show(struct config_item *item, char *buf)
 252 {
 253         return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->extended);
 254 }
 255 
 256 static ssize_t dev_name_show(struct config_item *item, char *buf)
 257 {
 258         return snprintf(buf, PAGE_SIZE, "%s\n", to_target(item)->np.dev_name);
 259 }
 260 
 261 static ssize_t local_port_show(struct config_item *item, char *buf)
 262 {
 263         return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.local_port);
 264 }
 265 
 266 static ssize_t remote_port_show(struct config_item *item, char *buf)
 267 {
 268         return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.remote_port);
 269 }
 270 
 271 static ssize_t local_ip_show(struct config_item *item, char *buf)
 272 {
 273         struct netconsole_target *nt = to_target(item);
 274 
 275         if (nt->np.ipv6)
 276                 return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
 277         else
 278                 return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
 279 }
 280 
 281 static ssize_t remote_ip_show(struct config_item *item, char *buf)
 282 {
 283         struct netconsole_target *nt = to_target(item);
 284 
 285         if (nt->np.ipv6)
 286                 return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
 287         else
 288                 return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
 289 }
 290 
 291 static ssize_t local_mac_show(struct config_item *item, char *buf)
 292 {
 293         struct net_device *dev = to_target(item)->np.dev;
 294         static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 295 
 296         return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast);
 297 }
 298 
 299 static ssize_t remote_mac_show(struct config_item *item, char *buf)
 300 {
 301         return snprintf(buf, PAGE_SIZE, "%pM\n", to_target(item)->np.remote_mac);
 302 }
 303 
 304 /*
 305  * This one is special -- targets created through the configfs interface
 306  * are not enabled (and the corresponding netpoll activated) by default.
 307  * The user is expected to set the desired parameters first (which
 308  * would enable him to dynamically add new netpoll targets for new
 309  * network interfaces as and when they come up).
 310  */
 311 static ssize_t enabled_store(struct config_item *item,
 312                 const char *buf, size_t count)
 313 {
 314         struct netconsole_target *nt = to_target(item);
 315         unsigned long flags;
 316         int enabled;
 317         int err;
 318 
 319         mutex_lock(&dynamic_netconsole_mutex);
 320         err = kstrtoint(buf, 10, &enabled);
 321         if (err < 0)
 322                 goto out_unlock;
 323 
 324         err = -EINVAL;
 325         if (enabled < 0 || enabled > 1)
 326                 goto out_unlock;
 327         if ((bool)enabled == nt->enabled) {
 328                 pr_info("network logging has already %s\n",
 329                         nt->enabled ? "started" : "stopped");
 330                 goto out_unlock;
 331         }
 332 
 333         if (enabled) {  /* true */
 334                 if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) {
 335                         netconsole_ext.flags |= CON_ENABLED;
 336                         register_console(&netconsole_ext);
 337                 }
 338 
 339                 /*
 340                  * Skip netpoll_parse_options() -- all the attributes are
 341                  * already configured via configfs. Just print them out.
 342                  */
 343                 netpoll_print_options(&nt->np);
 344 
 345                 err = netpoll_setup(&nt->np);
 346                 if (err)
 347                         goto out_unlock;
 348 
 349                 pr_info("network logging started\n");
 350         } else {        /* false */
 351                 /* We need to disable the netconsole before cleaning it up
 352                  * otherwise we might end up in write_msg() with
 353                  * nt->np.dev == NULL and nt->enabled == true
 354                  */
 355                 spin_lock_irqsave(&target_list_lock, flags);
 356                 nt->enabled = false;
 357                 spin_unlock_irqrestore(&target_list_lock, flags);
 358                 netpoll_cleanup(&nt->np);
 359         }
 360 
 361         nt->enabled = enabled;
 362 
 363         mutex_unlock(&dynamic_netconsole_mutex);
 364         return strnlen(buf, count);
 365 out_unlock:
 366         mutex_unlock(&dynamic_netconsole_mutex);
 367         return err;
 368 }
 369 
 370 static ssize_t extended_store(struct config_item *item, const char *buf,
 371                 size_t count)
 372 {
 373         struct netconsole_target *nt = to_target(item);
 374         int extended;
 375         int err;
 376 
 377         mutex_lock(&dynamic_netconsole_mutex);
 378         if (nt->enabled) {
 379                 pr_err("target (%s) is enabled, disable to update parameters\n",
 380                        config_item_name(&nt->item));
 381                 err = -EINVAL;
 382                 goto out_unlock;
 383         }
 384 
 385         err = kstrtoint(buf, 10, &extended);
 386         if (err < 0)
 387                 goto out_unlock;
 388         if (extended < 0 || extended > 1) {
 389                 err = -EINVAL;
 390                 goto out_unlock;
 391         }
 392 
 393         nt->extended = extended;
 394 
 395         mutex_unlock(&dynamic_netconsole_mutex);
 396         return strnlen(buf, count);
 397 out_unlock:
 398         mutex_unlock(&dynamic_netconsole_mutex);
 399         return err;
 400 }
 401 
 402 static ssize_t dev_name_store(struct config_item *item, const char *buf,
 403                 size_t count)
 404 {
 405         struct netconsole_target *nt = to_target(item);
 406         size_t len;
 407 
 408         mutex_lock(&dynamic_netconsole_mutex);
 409         if (nt->enabled) {
 410                 pr_err("target (%s) is enabled, disable to update parameters\n",
 411                        config_item_name(&nt->item));
 412                 mutex_unlock(&dynamic_netconsole_mutex);
 413                 return -EINVAL;
 414         }
 415 
 416         strlcpy(nt->np.dev_name, buf, IFNAMSIZ);
 417 
 418         /* Get rid of possible trailing newline from echo(1) */
 419         len = strnlen(nt->np.dev_name, IFNAMSIZ);
 420         if (nt->np.dev_name[len - 1] == '\n')
 421                 nt->np.dev_name[len - 1] = '\0';
 422 
 423         mutex_unlock(&dynamic_netconsole_mutex);
 424         return strnlen(buf, count);
 425 }
 426 
 427 static ssize_t local_port_store(struct config_item *item, const char *buf,
 428                 size_t count)
 429 {
 430         struct netconsole_target *nt = to_target(item);
 431         int rv = -EINVAL;
 432 
 433         mutex_lock(&dynamic_netconsole_mutex);
 434         if (nt->enabled) {
 435                 pr_err("target (%s) is enabled, disable to update parameters\n",
 436                        config_item_name(&nt->item));
 437                 goto out_unlock;
 438         }
 439 
 440         rv = kstrtou16(buf, 10, &nt->np.local_port);
 441         if (rv < 0)
 442                 goto out_unlock;
 443         mutex_unlock(&dynamic_netconsole_mutex);
 444         return strnlen(buf, count);
 445 out_unlock:
 446         mutex_unlock(&dynamic_netconsole_mutex);
 447         return rv;
 448 }
 449 
 450 static ssize_t remote_port_store(struct config_item *item,
 451                 const char *buf, size_t count)
 452 {
 453         struct netconsole_target *nt = to_target(item);
 454         int rv = -EINVAL;
 455 
 456         mutex_lock(&dynamic_netconsole_mutex);
 457         if (nt->enabled) {
 458                 pr_err("target (%s) is enabled, disable to update parameters\n",
 459                        config_item_name(&nt->item));
 460                 goto out_unlock;
 461         }
 462 
 463         rv = kstrtou16(buf, 10, &nt->np.remote_port);
 464         if (rv < 0)
 465                 goto out_unlock;
 466         mutex_unlock(&dynamic_netconsole_mutex);
 467         return strnlen(buf, count);
 468 out_unlock:
 469         mutex_unlock(&dynamic_netconsole_mutex);
 470         return rv;
 471 }
 472 
 473 static ssize_t local_ip_store(struct config_item *item, const char *buf,
 474                 size_t count)
 475 {
 476         struct netconsole_target *nt = to_target(item);
 477 
 478         mutex_lock(&dynamic_netconsole_mutex);
 479         if (nt->enabled) {
 480                 pr_err("target (%s) is enabled, disable to update parameters\n",
 481                        config_item_name(&nt->item));
 482                 goto out_unlock;
 483         }
 484 
 485         if (strnchr(buf, count, ':')) {
 486                 const char *end;
 487                 if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
 488                         if (*end && *end != '\n') {
 489                                 pr_err("invalid IPv6 address at: <%c>\n", *end);
 490                                 goto out_unlock;
 491                         }
 492                         nt->np.ipv6 = true;
 493                 } else
 494                         goto out_unlock;
 495         } else {
 496                 if (!nt->np.ipv6) {
 497                         nt->np.local_ip.ip = in_aton(buf);
 498                 } else
 499                         goto out_unlock;
 500         }
 501 
 502         mutex_unlock(&dynamic_netconsole_mutex);
 503         return strnlen(buf, count);
 504 out_unlock:
 505         mutex_unlock(&dynamic_netconsole_mutex);
 506         return -EINVAL;
 507 }
 508 
 509 static ssize_t remote_ip_store(struct config_item *item, const char *buf,
 510                size_t count)
 511 {
 512         struct netconsole_target *nt = to_target(item);
 513 
 514         mutex_lock(&dynamic_netconsole_mutex);
 515         if (nt->enabled) {
 516                 pr_err("target (%s) is enabled, disable to update parameters\n",
 517                        config_item_name(&nt->item));
 518                 goto out_unlock;
 519         }
 520 
 521         if (strnchr(buf, count, ':')) {
 522                 const char *end;
 523                 if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
 524                         if (*end && *end != '\n') {
 525                                 pr_err("invalid IPv6 address at: <%c>\n", *end);
 526                                 goto out_unlock;
 527                         }
 528                         nt->np.ipv6 = true;
 529                 } else
 530                         goto out_unlock;
 531         } else {
 532                 if (!nt->np.ipv6) {
 533                         nt->np.remote_ip.ip = in_aton(buf);
 534                 } else
 535                         goto out_unlock;
 536         }
 537 
 538         mutex_unlock(&dynamic_netconsole_mutex);
 539         return strnlen(buf, count);
 540 out_unlock:
 541         mutex_unlock(&dynamic_netconsole_mutex);
 542         return -EINVAL;
 543 }
 544 
 545 static ssize_t remote_mac_store(struct config_item *item, const char *buf,
 546                 size_t count)
 547 {
 548         struct netconsole_target *nt = to_target(item);
 549         u8 remote_mac[ETH_ALEN];
 550 
 551         mutex_lock(&dynamic_netconsole_mutex);
 552         if (nt->enabled) {
 553                 pr_err("target (%s) is enabled, disable to update parameters\n",
 554                        config_item_name(&nt->item));
 555                 goto out_unlock;
 556         }
 557 
 558         if (!mac_pton(buf, remote_mac))
 559                 goto out_unlock;
 560         if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n')
 561                 goto out_unlock;
 562         memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
 563 
 564         mutex_unlock(&dynamic_netconsole_mutex);
 565         return strnlen(buf, count);
 566 out_unlock:
 567         mutex_unlock(&dynamic_netconsole_mutex);
 568         return -EINVAL;
 569 }
 570 
 571 CONFIGFS_ATTR(, enabled);
 572 CONFIGFS_ATTR(, extended);
 573 CONFIGFS_ATTR(, dev_name);
 574 CONFIGFS_ATTR(, local_port);
 575 CONFIGFS_ATTR(, remote_port);
 576 CONFIGFS_ATTR(, local_ip);
 577 CONFIGFS_ATTR(, remote_ip);
 578 CONFIGFS_ATTR_RO(, local_mac);
 579 CONFIGFS_ATTR(, remote_mac);
 580 
 581 static struct configfs_attribute *netconsole_target_attrs[] = {
 582         &attr_enabled,
 583         &attr_extended,
 584         &attr_dev_name,
 585         &attr_local_port,
 586         &attr_remote_port,
 587         &attr_local_ip,
 588         &attr_remote_ip,
 589         &attr_local_mac,
 590         &attr_remote_mac,
 591         NULL,
 592 };
 593 
 594 /*
 595  * Item operations and type for netconsole_target.
 596  */
 597 
 598 static void netconsole_target_release(struct config_item *item)
 599 {
 600         kfree(to_target(item));
 601 }
 602 
 603 static struct configfs_item_operations netconsole_target_item_ops = {
 604         .release                = netconsole_target_release,
 605 };
 606 
 607 static const struct config_item_type netconsole_target_type = {
 608         .ct_attrs               = netconsole_target_attrs,
 609         .ct_item_ops            = &netconsole_target_item_ops,
 610         .ct_owner               = THIS_MODULE,
 611 };
 612 
 613 /*
 614  * Group operations and type for netconsole_subsys.
 615  */
 616 
 617 static struct config_item *make_netconsole_target(struct config_group *group,
 618                                                   const char *name)
 619 {
 620         unsigned long flags;
 621         struct netconsole_target *nt;
 622 
 623         /*
 624          * Allocate and initialize with defaults.
 625          * Target is disabled at creation (!enabled).
 626          */
 627         nt = kzalloc(sizeof(*nt), GFP_KERNEL);
 628         if (!nt)
 629                 return ERR_PTR(-ENOMEM);
 630 
 631         nt->np.name = "netconsole";
 632         strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
 633         nt->np.local_port = 6665;
 634         nt->np.remote_port = 6666;
 635         eth_broadcast_addr(nt->np.remote_mac);
 636 
 637         /* Initialize the config_item member */
 638         config_item_init_type_name(&nt->item, name, &netconsole_target_type);
 639 
 640         /* Adding, but it is disabled */
 641         spin_lock_irqsave(&target_list_lock, flags);
 642         list_add(&nt->list, &target_list);
 643         spin_unlock_irqrestore(&target_list_lock, flags);
 644 
 645         return &nt->item;
 646 }
 647 
 648 static void drop_netconsole_target(struct config_group *group,
 649                                    struct config_item *item)
 650 {
 651         unsigned long flags;
 652         struct netconsole_target *nt = to_target(item);
 653 
 654         spin_lock_irqsave(&target_list_lock, flags);
 655         list_del(&nt->list);
 656         spin_unlock_irqrestore(&target_list_lock, flags);
 657 
 658         /*
 659          * The target may have never been enabled, or was manually disabled
 660          * before being removed so netpoll may have already been cleaned up.
 661          */
 662         if (nt->enabled)
 663                 netpoll_cleanup(&nt->np);
 664 
 665         config_item_put(&nt->item);
 666 }
 667 
 668 static struct configfs_group_operations netconsole_subsys_group_ops = {
 669         .make_item      = make_netconsole_target,
 670         .drop_item      = drop_netconsole_target,
 671 };
 672 
 673 static const struct config_item_type netconsole_subsys_type = {
 674         .ct_group_ops   = &netconsole_subsys_group_ops,
 675         .ct_owner       = THIS_MODULE,
 676 };
 677 
 678 /* The netconsole configfs subsystem */
 679 static struct configfs_subsystem netconsole_subsys = {
 680         .su_group       = {
 681                 .cg_item        = {
 682                         .ci_namebuf     = "netconsole",
 683                         .ci_type        = &netconsole_subsys_type,
 684                 },
 685         },
 686 };
 687 
 688 #endif  /* CONFIG_NETCONSOLE_DYNAMIC */
 689 
 690 /* Handle network interface device notifications */
 691 static int netconsole_netdev_event(struct notifier_block *this,
 692                                    unsigned long event, void *ptr)
 693 {
 694         unsigned long flags;
 695         struct netconsole_target *nt;
 696         struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 697         bool stopped = false;
 698 
 699         if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
 700               event == NETDEV_RELEASE || event == NETDEV_JOIN))
 701                 goto done;
 702 
 703         spin_lock_irqsave(&target_list_lock, flags);
 704 restart:
 705         list_for_each_entry(nt, &target_list, list) {
 706                 netconsole_target_get(nt);
 707                 if (nt->np.dev == dev) {
 708                         switch (event) {
 709                         case NETDEV_CHANGENAME:
 710                                 strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
 711                                 break;
 712                         case NETDEV_RELEASE:
 713                         case NETDEV_JOIN:
 714                         case NETDEV_UNREGISTER:
 715                                 /* rtnl_lock already held
 716                                  * we might sleep in __netpoll_cleanup()
 717                                  */
 718                                 spin_unlock_irqrestore(&target_list_lock, flags);
 719 
 720                                 __netpoll_cleanup(&nt->np);
 721 
 722                                 spin_lock_irqsave(&target_list_lock, flags);
 723                                 dev_put(nt->np.dev);
 724                                 nt->np.dev = NULL;
 725                                 nt->enabled = false;
 726                                 stopped = true;
 727                                 netconsole_target_put(nt);
 728                                 goto restart;
 729                         }
 730                 }
 731                 netconsole_target_put(nt);
 732         }
 733         spin_unlock_irqrestore(&target_list_lock, flags);
 734         if (stopped) {
 735                 const char *msg = "had an event";
 736                 switch (event) {
 737                 case NETDEV_UNREGISTER:
 738                         msg = "unregistered";
 739                         break;
 740                 case NETDEV_RELEASE:
 741                         msg = "released slaves";
 742                         break;
 743                 case NETDEV_JOIN:
 744                         msg = "is joining a master device";
 745                         break;
 746                 }
 747                 pr_info("network logging stopped on interface %s as it %s\n",
 748                         dev->name, msg);
 749         }
 750 
 751 done:
 752         return NOTIFY_DONE;
 753 }
 754 
 755 static struct notifier_block netconsole_netdev_notifier = {
 756         .notifier_call  = netconsole_netdev_event,
 757 };
 758 
 759 /**
 760  * send_ext_msg_udp - send extended log message to target
 761  * @nt: target to send message to
 762  * @msg: extended log message to send
 763  * @msg_len: length of message
 764  *
 765  * Transfer extended log @msg to @nt.  If @msg is longer than
 766  * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with
 767  * ncfrag header field added to identify them.
 768  */
 769 static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg,
 770                              int msg_len)
 771 {
 772         static char buf[MAX_PRINT_CHUNK]; /* protected by target_list_lock */
 773         const char *header, *body;
 774         int offset = 0;
 775         int header_len, body_len;
 776 
 777         if (msg_len <= MAX_PRINT_CHUNK) {
 778                 netpoll_send_udp(&nt->np, msg, msg_len);
 779                 return;
 780         }
 781 
 782         /* need to insert extra header fields, detect header and body */
 783         header = msg;
 784         body = memchr(msg, ';', msg_len);
 785         if (WARN_ON_ONCE(!body))
 786                 return;
 787 
 788         header_len = body - header;
 789         body_len = msg_len - header_len - 1;
 790         body++;
 791 
 792         /*
 793          * Transfer multiple chunks with the following extra header.
 794          * "ncfrag=<byte-offset>/<total-bytes>"
 795          */
 796         memcpy(buf, header, header_len);
 797 
 798         while (offset < body_len) {
 799                 int this_header = header_len;
 800                 int this_chunk;
 801 
 802                 this_header += scnprintf(buf + this_header,
 803                                          sizeof(buf) - this_header,
 804                                          ",ncfrag=%d/%d;", offset, body_len);
 805 
 806                 this_chunk = min(body_len - offset,
 807                                  MAX_PRINT_CHUNK - this_header);
 808                 if (WARN_ON_ONCE(this_chunk <= 0))
 809                         return;
 810 
 811                 memcpy(buf + this_header, body + offset, this_chunk);
 812 
 813                 netpoll_send_udp(&nt->np, buf, this_header + this_chunk);
 814 
 815                 offset += this_chunk;
 816         }
 817 }
 818 
 819 static void write_ext_msg(struct console *con, const char *msg,
 820                           unsigned int len)
 821 {
 822         struct netconsole_target *nt;
 823         unsigned long flags;
 824 
 825         if ((oops_only && !oops_in_progress) || list_empty(&target_list))
 826                 return;
 827 
 828         spin_lock_irqsave(&target_list_lock, flags);
 829         list_for_each_entry(nt, &target_list, list)
 830                 if (nt->extended && nt->enabled && netif_running(nt->np.dev))
 831                         send_ext_msg_udp(nt, msg, len);
 832         spin_unlock_irqrestore(&target_list_lock, flags);
 833 }
 834 
 835 static void write_msg(struct console *con, const char *msg, unsigned int len)
 836 {
 837         int frag, left;
 838         unsigned long flags;
 839         struct netconsole_target *nt;
 840         const char *tmp;
 841 
 842         if (oops_only && !oops_in_progress)
 843                 return;
 844         /* Avoid taking lock and disabling interrupts unnecessarily */
 845         if (list_empty(&target_list))
 846                 return;
 847 
 848         spin_lock_irqsave(&target_list_lock, flags);
 849         list_for_each_entry(nt, &target_list, list) {
 850                 if (!nt->extended && nt->enabled && netif_running(nt->np.dev)) {
 851                         /*
 852                          * We nest this inside the for-each-target loop above
 853                          * so that we're able to get as much logging out to
 854                          * at least one target if we die inside here, instead
 855                          * of unnecessarily keeping all targets in lock-step.
 856                          */
 857                         tmp = msg;
 858                         for (left = len; left;) {
 859                                 frag = min(left, MAX_PRINT_CHUNK);
 860                                 netpoll_send_udp(&nt->np, tmp, frag);
 861                                 tmp += frag;
 862                                 left -= frag;
 863                         }
 864                 }
 865         }
 866         spin_unlock_irqrestore(&target_list_lock, flags);
 867 }
 868 
 869 static struct console netconsole_ext = {
 870         .name   = "netcon_ext",
 871         .flags  = CON_EXTENDED, /* starts disabled, registered on first use */
 872         .write  = write_ext_msg,
 873 };
 874 
 875 static struct console netconsole = {
 876         .name   = "netcon",
 877         .flags  = CON_ENABLED,
 878         .write  = write_msg,
 879 };
 880 
 881 static int __init init_netconsole(void)
 882 {
 883         int err;
 884         struct netconsole_target *nt, *tmp;
 885         unsigned long flags;
 886         char *target_config;
 887         char *input = config;
 888 
 889         if (strnlen(input, MAX_PARAM_LENGTH)) {
 890                 while ((target_config = strsep(&input, ";"))) {
 891                         nt = alloc_param_target(target_config);
 892                         if (IS_ERR(nt)) {
 893                                 err = PTR_ERR(nt);
 894                                 goto fail;
 895                         }
 896                         /* Dump existing printks when we register */
 897                         if (nt->extended)
 898                                 netconsole_ext.flags |= CON_PRINTBUFFER |
 899                                                         CON_ENABLED;
 900                         else
 901                                 netconsole.flags |= CON_PRINTBUFFER;
 902 
 903                         spin_lock_irqsave(&target_list_lock, flags);
 904                         list_add(&nt->list, &target_list);
 905                         spin_unlock_irqrestore(&target_list_lock, flags);
 906                 }
 907         }
 908 
 909         err = register_netdevice_notifier(&netconsole_netdev_notifier);
 910         if (err)
 911                 goto fail;
 912 
 913         err = dynamic_netconsole_init();
 914         if (err)
 915                 goto undonotifier;
 916 
 917         if (netconsole_ext.flags & CON_ENABLED)
 918                 register_console(&netconsole_ext);
 919         register_console(&netconsole);
 920         pr_info("network logging started\n");
 921 
 922         return err;
 923 
 924 undonotifier:
 925         unregister_netdevice_notifier(&netconsole_netdev_notifier);
 926 
 927 fail:
 928         pr_err("cleaning up\n");
 929 
 930         /*
 931          * Remove all targets and destroy them (only targets created
 932          * from the boot/module option exist here). Skipping the list
 933          * lock is safe here, and netpoll_cleanup() will sleep.
 934          */
 935         list_for_each_entry_safe(nt, tmp, &target_list, list) {
 936                 list_del(&nt->list);
 937                 free_param_target(nt);
 938         }
 939 
 940         return err;
 941 }
 942 
 943 static void __exit cleanup_netconsole(void)
 944 {
 945         struct netconsole_target *nt, *tmp;
 946 
 947         unregister_console(&netconsole_ext);
 948         unregister_console(&netconsole);
 949         dynamic_netconsole_exit();
 950         unregister_netdevice_notifier(&netconsole_netdev_notifier);
 951 
 952         /*
 953          * Targets created via configfs pin references on our module
 954          * and would first be rmdir(2)'ed from userspace. We reach
 955          * here only when they are already destroyed, and only those
 956          * created from the boot/module option are left, so remove and
 957          * destroy them. Skipping the list lock is safe here, and
 958          * netpoll_cleanup() will sleep.
 959          */
 960         list_for_each_entry_safe(nt, tmp, &target_list, list) {
 961                 list_del(&nt->list);
 962                 free_param_target(nt);
 963         }
 964 }
 965 
 966 /*
 967  * Use late_initcall to ensure netconsole is
 968  * initialized after network device driver if built-in.
 969  *
 970  * late_initcall() and module_init() are identical if built as module.
 971  */
 972 late_initcall(init_netconsole);
 973 module_exit(cleanup_netconsole);

/* [<][>][^][v][top][bottom][index][help] */