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