mconsole_kern.c

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

C
937
字号
static int mem_id(char **str, int *start_out, int *end_out){	*start_out = 0;	*end_out = 0;	return 0;}static int mem_remove(int n, char **error_out){	*error_out = "Memory doesn't support the remove operation";	return -EBUSY;}static struct mc_device mem_mc = {	.list		= LIST_HEAD_INIT(mem_mc.list),	.name		= "mem",	.config		= mem_config,	.get_config	= mem_get_config,	.id		= mem_id,	.remove		= mem_remove,};static int __init mem_mc_init(void){	if (can_drop_memory())		mconsole_register_dev(&mem_mc);	else printk(KERN_ERR "Can't release memory to the host - memory "		    "hotplug won't be supported\n");	return 0;}__initcall(mem_mc_init);#define CONFIG_BUF_SIZE 64static void mconsole_get_config(int (*get_config)(char *, char *, int,						  char **),				struct mc_request *req, char *name){	char default_buf[CONFIG_BUF_SIZE], *error, *buf;	int n, size;	if (get_config == NULL) {		mconsole_reply(req, "No get_config routine defined", 1, 0);		return;	}	error = NULL;	size = ARRAY_SIZE(default_buf);	buf = default_buf;	while (1) {		n = (*get_config)(name, buf, size, &error);		if (error != NULL) {			mconsole_reply(req, error, 1, 0);			goto out;		}		if (n <= size) {			mconsole_reply(req, buf, 0, 0);			goto out;		}		if (buf != default_buf)			kfree(buf);		size = n;		buf = kmalloc(size, GFP_KERNEL);		if (buf == NULL) {			mconsole_reply(req, "Failed to allocate buffer", 1, 0);			return;		}	} out:	if (buf != default_buf)		kfree(buf);}void mconsole_config(struct mc_request *req){	struct mc_device *dev;	char *ptr = req->request.data, *name, *error_string = "";	int err;	ptr += strlen("config");	while (isspace(*ptr))		ptr++;	dev = mconsole_find_dev(ptr);	if (dev == NULL) {		mconsole_reply(req, "Bad configuration option", 1, 0);		return;	}	name = &ptr[strlen(dev->name)];	ptr = name;	while ((*ptr != '=') && (*ptr != '\0'))		ptr++;	if (*ptr == '=') {		err = (*dev->config)(name, &error_string);		mconsole_reply(req, error_string, err, 0);	}	else mconsole_get_config(dev->get_config, req, name);}void mconsole_remove(struct mc_request *req){	struct mc_device *dev;	char *ptr = req->request.data, *err_msg = "";	char error[256];	int err, start, end, n;	ptr += strlen("remove");	while (isspace(*ptr)) ptr++;	dev = mconsole_find_dev(ptr);	if (dev == NULL) {		mconsole_reply(req, "Bad remove option", 1, 0);		return;	}	ptr = &ptr[strlen(dev->name)];	err = 1;	n = (*dev->id)(&ptr, &start, &end);	if (n < 0) {		err_msg = "Couldn't parse device number";		goto out;	}	else if ((n < start) || (n > end)) {		sprintf(error, "Invalid device number - must be between "			"%d and %d", start, end);		err_msg = error;		goto out;	}	err_msg = NULL;	err = (*dev->remove)(n, &err_msg);	switch(err) {	case 0:		err_msg = "";		break;	case -ENODEV:		if (err_msg == NULL)			err_msg = "Device doesn't exist";		break;	case -EBUSY:		if (err_msg == NULL)			err_msg = "Device is currently open";		break;	default:		break;	}out:	mconsole_reply(req, err_msg, err, 0);}struct mconsole_output {	struct list_head list;	struct mc_request *req;};static DEFINE_SPINLOCK(client_lock);static LIST_HEAD(clients);static char console_buf[MCONSOLE_MAX_DATA];static void console_write(struct console *console, const char *string,			  unsigned int len){	struct list_head *ele;	int n;	if (list_empty(&clients))		return;	while (len > 0) {		n = min((size_t) len, ARRAY_SIZE(console_buf));		strncpy(console_buf, string, n);		string += n;		len -= n;		list_for_each(ele, &clients) {			struct mconsole_output *entry;			entry = list_entry(ele, struct mconsole_output, list);			mconsole_reply_len(entry->req, console_buf, n, 0, 1);		}	}}static struct console mc_console = { .name	= "mc",				     .write	= console_write,				     .flags	= CON_ENABLED,				     .index	= -1 };static int mc_add_console(void){	register_console(&mc_console);	return 0;}late_initcall(mc_add_console);static void with_console(struct mc_request *req, void (*proc)(void *),			 void *arg){	struct mconsole_output entry;	unsigned long flags;	entry.req = req;	spin_lock_irqsave(&client_lock, flags);	list_add(&entry.list, &clients);	spin_unlock_irqrestore(&client_lock, flags);	(*proc)(arg);	mconsole_reply_len(req, "", 0, 0, 0);	spin_lock_irqsave(&client_lock, flags);	list_del(&entry.list);	spin_unlock_irqrestore(&client_lock, flags);}#ifdef CONFIG_MAGIC_SYSRQ#include <linux/sysrq.h>static void sysrq_proc(void *arg){	char *op = arg;	handle_sysrq(*op, NULL);}void mconsole_sysrq(struct mc_request *req){	char *ptr = req->request.data;	ptr += strlen("sysrq");	while (isspace(*ptr)) ptr++;	/*	 * With 'b', the system will shut down without a chance to reply,	 * so in this case, we reply first.	 */	if (*ptr == 'b')		mconsole_reply(req, "", 0, 0);	with_console(req, sysrq_proc, ptr);}#elsevoid mconsole_sysrq(struct mc_request *req){	mconsole_reply(req, "Sysrq not compiled in", 1, 0);}#endifstatic void stack_proc(void *arg){	struct task_struct *from = current, *to = arg;	to->thread.saved_task = from;	switch_to(from, to, from);}/* * Mconsole stack trace *  Added by Allan Graves, Jeff Dike *  Dumps a stacks registers to the linux console. *  Usage stack <pid>. */void mconsole_stack(struct mc_request *req){	char *ptr = req->request.data;	int pid_requested= -1;	struct task_struct *from = NULL;	struct task_struct *to = NULL;	/*	 * Would be nice:	 * 1) Send showregs output to mconsole.	 * 2) Add a way to stack dump all pids.	 */	ptr += strlen("stack");	while (isspace(*ptr))		ptr++;	/*	 * Should really check for multiple pids or reject bad args here	 */	/* What do the arguments in mconsole_reply mean? */	if (sscanf(ptr, "%d", &pid_requested) == 0) {		mconsole_reply(req, "Please specify a pid", 1, 0);		return;	}	from = current;	to = find_task_by_pid(pid_requested);	if ((to == NULL) || (pid_requested == 0)) {		mconsole_reply(req, "Couldn't find that pid", 1, 0);		return;	}	with_console(req, stack_proc, to);}/* * Changed by mconsole_setup, which is __setup, and called before SMP is * active. */static char *notify_socket = NULL;static int __init mconsole_init(void){	/* long to avoid size mismatch warnings from gcc */	long sock;	int err;	char file[256];	if (umid_file_name("mconsole", file, sizeof(file)))		return -1;	snprintf(mconsole_socket_name, sizeof(file), "%s", file);	sock = os_create_unix_socket(file, sizeof(file), 1);	if (sock < 0) {		printk(KERN_ERR "Failed to initialize management console\n");		return 1;	}	register_reboot_notifier(&reboot_notifier);	err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,			     IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,			     "mconsole", (void *)sock);	if (err) {		printk(KERN_ERR "Failed to get IRQ for management console\n");		return 1;	}	if (notify_socket != NULL) {		notify_socket = kstrdup(notify_socket, GFP_KERNEL);		if (notify_socket != NULL)			mconsole_notify(notify_socket, MCONSOLE_SOCKET,					mconsole_socket_name,					strlen(mconsole_socket_name) + 1);		else printk(KERN_ERR "mconsole_setup failed to strdup "			    "string\n");	}	printk(KERN_INFO "mconsole (version %d) initialized on %s\n",	       MCONSOLE_VERSION, mconsole_socket_name);	return 0;}__initcall(mconsole_init);static int write_proc_mconsole(struct file *file, const char __user *buffer,			       unsigned long count, void *data){	char *buf;	buf = kmalloc(count + 1, GFP_KERNEL);	if (buf == NULL)		return -ENOMEM;	if (copy_from_user(buf, buffer, count)) {		count = -EFAULT;		goto out;	}	buf[count] = '\0';	mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count); out:	kfree(buf);	return count;}static int create_proc_mconsole(void){	struct proc_dir_entry *ent;	if (notify_socket == NULL)		return 0;	ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);	if (ent == NULL) {		printk(KERN_INFO "create_proc_mconsole : create_proc_entry "		       "failed\n");		return 0;	}	ent->read_proc = NULL;	ent->write_proc = write_proc_mconsole;	return 0;}static DEFINE_SPINLOCK(notify_spinlock);void lock_notify(void){	spin_lock(&notify_spinlock);}void unlock_notify(void){	spin_unlock(&notify_spinlock);}__initcall(create_proc_mconsole);#define NOTIFY "notify:"static int mconsole_setup(char *str){	if (!strncmp(str, NOTIFY, strlen(NOTIFY))) {		str += strlen(NOTIFY);		notify_socket = str;	}	else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);	return 1;}__setup("mconsole=", mconsole_setup);__uml_help(mconsole_setup,"mconsole=notify:<socket>\n""    Requests that the mconsole driver send a message to the named Unix\n""    socket containing the name of the mconsole socket.  This also serves\n""    to notify outside processes when UML has booted far enough to respond\n""    to mconsole requests.\n\n");static int notify_panic(struct notifier_block *self, unsigned long unused1,			void *ptr){	char *message = ptr;	if (notify_socket == NULL)		return 0;	mconsole_notify(notify_socket, MCONSOLE_PANIC, message,			strlen(message) + 1);	return 0;}static struct notifier_block panic_exit_notifier = {	.notifier_call 		= notify_panic,	.next 			= NULL,	.priority 		= 1};static int add_notifier(void){	atomic_notifier_chain_register(&panic_notifier_list,			&panic_exit_notifier);	return 0;}__initcall(add_notifier);char *mconsole_notify_socket(void){	return notify_socket;}EXPORT_SYMBOL(mconsole_notify_socket);

⌨️ 快捷键说明

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