netconsole.c

来自「linux 内核源代码」· C语言 代码 · 共 816 行 · 第 1/2 页

C
816
字号
				 const char *buf,				 size_t count){	long remote_port;#define __U16_MAX	((__u16) ~0U)	if (nt->enabled) {		printk(KERN_ERR "netconsole: target (%s) is enabled, "				"disable to update parameters\n",				config_item_name(&nt->item));		return -EINVAL;	}	remote_port = strtol10_check_range(buf, 0, __U16_MAX);	if (remote_port < 0)		return remote_port;	nt->np.remote_port = remote_port;	return strnlen(buf, count);}static ssize_t store_local_ip(struct netconsole_target *nt,			      const char *buf,			      size_t count){	if (nt->enabled) {		printk(KERN_ERR "netconsole: target (%s) is enabled, "				"disable to update parameters\n",				config_item_name(&nt->item));		return -EINVAL;	}	nt->np.local_ip = ntohl(in_aton(buf));	return strnlen(buf, count);}static ssize_t store_remote_ip(struct netconsole_target *nt,			       const char *buf,			       size_t count){	if (nt->enabled) {		printk(KERN_ERR "netconsole: target (%s) is enabled, "				"disable to update parameters\n",				config_item_name(&nt->item));		return -EINVAL;	}	nt->np.remote_ip = ntohl(in_aton(buf));	return strnlen(buf, count);}static ssize_t store_remote_mac(struct netconsole_target *nt,				const char *buf,				size_t count){	u8 remote_mac[ETH_ALEN];	char *p = (char *) buf;	int i;	if (nt->enabled) {		printk(KERN_ERR "netconsole: target (%s) is enabled, "				"disable to update parameters\n",				config_item_name(&nt->item));		return -EINVAL;	}	for (i = 0; i < ETH_ALEN - 1; i++) {		remote_mac[i] = simple_strtoul(p, &p, 16);		if (*p != ':')			goto invalid;		p++;	}	remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16);	if (*p && (*p != '\n'))		goto invalid;	memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);	return strnlen(buf, count);invalid:	printk(KERN_ERR "netconsole: invalid input\n");	return -EINVAL;}/* * Attribute definitions for netconsole_target. */#define NETCONSOLE_TARGET_ATTR_RO(_name)				\static struct netconsole_target_attr netconsole_target_##_name =	\	__CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL)#define NETCONSOLE_TARGET_ATTR_RW(_name)				\static struct netconsole_target_attr netconsole_target_##_name =	\	__CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name)NETCONSOLE_TARGET_ATTR_RW(enabled);NETCONSOLE_TARGET_ATTR_RW(dev_name);NETCONSOLE_TARGET_ATTR_RW(local_port);NETCONSOLE_TARGET_ATTR_RW(remote_port);NETCONSOLE_TARGET_ATTR_RW(local_ip);NETCONSOLE_TARGET_ATTR_RW(remote_ip);NETCONSOLE_TARGET_ATTR_RO(local_mac);NETCONSOLE_TARGET_ATTR_RW(remote_mac);static struct configfs_attribute *netconsole_target_attrs[] = {	&netconsole_target_enabled.attr,	&netconsole_target_dev_name.attr,	&netconsole_target_local_port.attr,	&netconsole_target_remote_port.attr,	&netconsole_target_local_ip.attr,	&netconsole_target_remote_ip.attr,	&netconsole_target_local_mac.attr,	&netconsole_target_remote_mac.attr,	NULL,};/* * Item operations and type for netconsole_target. */static void netconsole_target_release(struct config_item *item){	kfree(to_target(item));}static ssize_t netconsole_target_attr_show(struct config_item *item,					   struct configfs_attribute *attr,					   char *buf){	ssize_t ret = -EINVAL;	struct netconsole_target *nt = to_target(item);	struct netconsole_target_attr *na =		container_of(attr, struct netconsole_target_attr, attr);	if (na->show)		ret = na->show(nt, buf);	return ret;}static ssize_t netconsole_target_attr_store(struct config_item *item,					    struct configfs_attribute *attr,					    const char *buf,					    size_t count){	ssize_t ret = -EINVAL;	struct netconsole_target *nt = to_target(item);	struct netconsole_target_attr *na =		container_of(attr, struct netconsole_target_attr, attr);	if (na->store)		ret = na->store(nt, buf, count);	return ret;}static struct configfs_item_operations netconsole_target_item_ops = {	.release		= netconsole_target_release,	.show_attribute		= netconsole_target_attr_show,	.store_attribute	= netconsole_target_attr_store,};static struct config_item_type netconsole_target_type = {	.ct_attrs		= netconsole_target_attrs,	.ct_item_ops		= &netconsole_target_item_ops,	.ct_owner		= THIS_MODULE,};/* * Group operations and type for netconsole_subsys. */static struct config_item *make_netconsole_target(struct config_group *group,						  const char *name){	unsigned long flags;	struct netconsole_target *nt;	/*	 * Allocate and initialize with defaults.	 * Target is disabled at creation (enabled == 0).	 */	nt = kzalloc(sizeof(*nt), GFP_KERNEL);	if (!nt) {		printk(KERN_ERR "netconsole: failed to allocate memory\n");		return NULL;	}	nt->np.name = "netconsole";	strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);	nt->np.local_port = 6665;	nt->np.remote_port = 6666;	memset(nt->np.remote_mac, 0xff, ETH_ALEN);	/* Initialize the config_item member */	config_item_init_type_name(&nt->item, name, &netconsole_target_type);	/* Adding, but it is disabled */	spin_lock_irqsave(&target_list_lock, flags);	list_add(&nt->list, &target_list);	spin_unlock_irqrestore(&target_list_lock, flags);	return &nt->item;}static void drop_netconsole_target(struct config_group *group,				   struct config_item *item){	unsigned long flags;	struct netconsole_target *nt = to_target(item);	spin_lock_irqsave(&target_list_lock, flags);	list_del(&nt->list);	spin_unlock_irqrestore(&target_list_lock, flags);	/*	 * The target may have never been enabled, or was manually disabled	 * before being removed so netpoll may have already been cleaned up.	 */	if (nt->enabled)		netpoll_cleanup(&nt->np);	config_item_put(&nt->item);}static struct configfs_group_operations netconsole_subsys_group_ops = {	.make_item	= make_netconsole_target,	.drop_item	= drop_netconsole_target,};static struct config_item_type netconsole_subsys_type = {	.ct_group_ops	= &netconsole_subsys_group_ops,	.ct_owner	= THIS_MODULE,};/* The netconsole configfs subsystem */static struct configfs_subsystem netconsole_subsys = {	.su_group	= {		.cg_item	= {			.ci_namebuf	= "netconsole",			.ci_type	= &netconsole_subsys_type,		},	},};#endif	/* CONFIG_NETCONSOLE_DYNAMIC *//* Handle network interface device notifications */static int netconsole_netdev_event(struct notifier_block *this,				   unsigned long event,				   void *ptr){	unsigned long flags;	struct netconsole_target *nt;	struct net_device *dev = ptr;	if (!(event == NETDEV_CHANGEADDR || event == NETDEV_CHANGENAME))		goto done;	spin_lock_irqsave(&target_list_lock, flags);	list_for_each_entry(nt, &target_list, list) {		netconsole_target_get(nt);		if (nt->np.dev == dev) {			switch (event) {			case NETDEV_CHANGEADDR:				memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN);				break;			case NETDEV_CHANGENAME:				strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);				break;			}		}		netconsole_target_put(nt);	}	spin_unlock_irqrestore(&target_list_lock, flags);done:	return NOTIFY_DONE;}static struct notifier_block netconsole_netdev_notifier = {	.notifier_call  = netconsole_netdev_event,};static void write_msg(struct console *con, const char *msg, unsigned int len){	int frag, left;	unsigned long flags;	struct netconsole_target *nt;	const char *tmp;	/* Avoid taking lock and disabling interrupts unnecessarily */	if (list_empty(&target_list))		return;	spin_lock_irqsave(&target_list_lock, flags);	list_for_each_entry(nt, &target_list, list) {		netconsole_target_get(nt);		if (nt->enabled && netif_running(nt->np.dev)) {			/*			 * We nest this inside the for-each-target loop above			 * so that we're able to get as much logging out to			 * at least one target if we die inside here, instead			 * of unnecessarily keeping all targets in lock-step.			 */			tmp = msg;			for (left = len; left;) {				frag = min(left, MAX_PRINT_CHUNK);				netpoll_send_udp(&nt->np, tmp, frag);				tmp += frag;				left -= frag;			}		}		netconsole_target_put(nt);	}	spin_unlock_irqrestore(&target_list_lock, flags);}static struct console netconsole = {	.name	= "netcon",	.flags	= CON_ENABLED | CON_PRINTBUFFER,	.write	= write_msg,};static int __init init_netconsole(void){	int err;	struct netconsole_target *nt, *tmp;	unsigned long flags;	char *target_config;	char *input = config;	if (strnlen(input, MAX_PARAM_LENGTH)) {		while ((target_config = strsep(&input, ";"))) {			nt = alloc_param_target(target_config);			if (IS_ERR(nt)) {				err = PTR_ERR(nt);				goto fail;			}			spin_lock_irqsave(&target_list_lock, flags);			list_add(&nt->list, &target_list);			spin_unlock_irqrestore(&target_list_lock, flags);		}	}	err = register_netdevice_notifier(&netconsole_netdev_notifier);	if (err)		goto fail;	err = dynamic_netconsole_init();	if (err)		goto undonotifier;	register_console(&netconsole);	printk(KERN_INFO "netconsole: network logging started\n");	return err;undonotifier:	unregister_netdevice_notifier(&netconsole_netdev_notifier);fail:	printk(KERN_ERR "netconsole: cleaning up\n");	/*	 * Remove all targets and destroy them (only targets created	 * from the boot/module option exist here). Skipping the list	 * lock is safe here, and netpoll_cleanup() will sleep.	 */	list_for_each_entry_safe(nt, tmp, &target_list, list) {		list_del(&nt->list);		free_param_target(nt);	}	return err;}static void __exit cleanup_netconsole(void){	struct netconsole_target *nt, *tmp;	unregister_console(&netconsole);	dynamic_netconsole_exit();	unregister_netdevice_notifier(&netconsole_netdev_notifier);	/*	 * Targets created via configfs pin references on our module	 * and would first be rmdir(2)'ed from userspace. We reach	 * here only when they are already destroyed, and only those	 * created from the boot/module option are left, so remove and	 * destroy them. Skipping the list lock is safe here, and	 * netpoll_cleanup() will sleep.	 */	list_for_each_entry_safe(nt, tmp, &target_list, list) {		list_del(&nt->list);		free_param_target(nt);	}}module_init(init_netconsole);module_exit(cleanup_netconsole);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?