Skip to contentSkip to conversation

implement tty driver for netconsole

PATCH In review Hollis Blanchard 4 participants 9 messages Nov 27, 2008 – Nov 30, 2008

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 implement tty driver for netconsole

I have a Kuro Box (a small NAS device running Linux), and it has no serial console (nor any other console for that matter). The most convenient way to get boot output is via the netconsole driver, which is what most Kuro owners do. (The u-boot firmware even supports interactive netconsole allowing us to edit boot configuration.)

However, once past kernel boot, userspace currently has no way of outputting data over netconsole. These patches enable that, which is really useful for seeing init script output and debugging ramdisks before they've brought up sshd.

-Hollis

#1 lore raw

PATCH 1/1 netconsole: add write-only tty driver

This allows userspace to output to netconsole via the /dev/console device, which is very useful to see initscript output, for example. There is only one netconsole TTY device, and TTY output goes to all receivers specified for console output.

Input via /dev/console is still not implemented, however.

drivers/net/netconsole.c +62 -0
@@ -43,6 +43,7 @@
 #include <linux/netpoll.h>
 #include <linux/inet.h>
 #include <linux/configfs.h>
+#include <linux/tty.h>
 
 MODULE_AUTHOR("Maintainer: Matt Mackall <[email protected]>");
 MODULE_DESCRIPTION("Console driver for network interfaces");
@@ -98,6 +99,8 @@ struct netconsole_target {
 	int			enabled;
 	struct netpoll		np;
 };
+
+static struct tty_driver *netconsole_tty_driver;
 
 #ifdef	CONFIG_NETCONSOLE_DYNAMIC
 
@@ -728,15 +731,74 @@ static void netconsole_write_msg(const c
 	spin_unlock_irqrestore(&target_list_lock, flags);
 }
 
+static int netconsole_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	return 0;
+}
+
+static void netconsole_tty_close(struct tty_struct *tty, struct file *filp)
+{
+}
+
+static int netconsole_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	netconsole_write_msg(buf, count);
+	return count;
+}
+
+static int netconsole_tty_write_room(struct tty_struct *tty)
+{
+	return MAX_PRINT_CHUNK;
+}
+
+static const struct tty_operations netconsole_tty_ops = {
+	.open = netconsole_tty_open,
+	.close = netconsole_tty_close,
+	.write = netconsole_tty_write,
+	.write_room = netconsole_tty_write_room,
+};
+
+static int __init netconsole_tty_init(void)
+{
+	netconsole_tty_driver = alloc_tty_driver(1);
+	if (!netconsole_tty_driver)
+		return -ENOMEM;
+
+	netconsole_tty_driver->owner = THIS_MODULE;
+	netconsole_tty_driver->driver_name = "netcon";
+	netconsole_tty_driver->name = "netcon";
+	netconsole_tty_driver->minor_start = 0;
+	netconsole_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+	netconsole_tty_driver->init_termios = tty_std_termios;
+	netconsole_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+	netconsole_tty_driver->init_termios.c_ispeed = 9600;
+	netconsole_tty_driver->init_termios.c_ospeed = 9600;
+	netconsole_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+	tty_set_operations(netconsole_tty_driver, &netconsole_tty_ops);
+
+	if (tty_register_driver(netconsole_tty_driver))
+		printk(KERN_ERR "Couldn't register netconsole tty driver\n");
+
+	return 0;
+}
+device_initcall(netconsole_tty_init);
+
 static void netconsole_console_write(struct console *con, const char *msg, unsigned int len)
 {
 	netconsole_write_msg(msg, len);
+}
+
+static struct tty_driver *netconsole_console_device(struct console *console, int *index)
+{
+	*index = console->index;
+	return netconsole_tty_driver;
 }
 
 static struct console netconsole = {
 	.name	= "netcon",
 	.flags	= CON_ENABLED,
 	.write	= netconsole_console_write,
+	.device = netconsole_console_device,
 };
 
 static int __init init_netconsole(void)
#2 lore raw

Re: [PATCH 2 of 2] netconsole: add write-only tty driver

Hi.

Looks good. A short note below.

Quoted 14 lines · Hollis Blanchard
drivers/net/netconsole.c +14 -0
+static int __init netconsole_tty_init(void)
+{
+	netconsole_tty_driver = alloc_tty_driver(1);
+	if (!netconsole_tty_driver)
+		return -ENOMEM;
+
+	netconsole_tty_driver->owner = THIS_MODULE;
+	netconsole_tty_driver->driver_name = "netcon";
+	netconsole_tty_driver->name = "netcon";
+	netconsole_tty_driver->minor_start = 0;
+	netconsole_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+	netconsole_tty_driver->init_termios = tty_std_termios;
+	netconsole_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+	netconsole_tty_driver->init_termios.c_ispeed = 9600;

drivers/net/netconsole.c static void netconsole_write_msg(const c · line 784

Quoted 10 lines
drivers/net/netconsole.c +10 -0
+	netconsole_tty_driver->init_termios.c_ospeed = 9600;
+	netconsole_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+	tty_set_operations(netconsole_tty_driver, &netconsole_tty_ops);
+
+	if (tty_register_driver(netconsole_tty_driver))
+		printk(KERN_ERR "Couldn't register netconsole tty driver\n");
+
+	return 0;
+}
+device_initcall(netconsole_tty_init);

Would it be better called from init_netconsole()?

Signature · 1 line
	Evgeniy Polyakov
#3 lore raw

Re: [PATCH 2 of 2] netconsole: add write-only tty driver

Quoted 5 lines · On Thursday 27 November 2008 15:47:01 Evgeniy Polyakov wrote:

Hi.

Looks good. A short note below.

On Thu, Nov 27, 2008 at 03:11:02PM -0600, Hollis Blanchard

Quoted 5 lines · ([email protected]) wrote:
Quoted 5 lines
drivers/net/netconsole.c +5 -0
+static int __init netconsole_tty_init(void)
+{
+	netconsole_tty_driver = alloc_tty_driver(1);
+	if (!netconsole_tty_driver)
+		return -ENOMEM;
Quoted 8 lines

drivers/net/netconsole.c static void netconsole_write_msg(const c

Quoted 8 lines
drivers/net/netconsole.c +8 -0
+
+	netconsole_tty_driver->owner = THIS_MODULE;
+	netconsole_tty_driver->driver_name = "netcon";
+	netconsole_tty_driver->name = "netcon";
+	netconsole_tty_driver->minor_start = 0;
+	netconsole_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+	netconsole_tty_driver->init_termios = tty_std_termios;
+	netconsole_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | 

HUPCL;

Quoted 5 lines
Quoted 5 lines
drivers/net/netconsole.c +5 -0
+	netconsole_tty_driver->init_termios.c_ispeed = 9600;
+	netconsole_tty_driver->init_termios.c_ospeed = 9600;
+	netconsole_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+	tty_set_operations(netconsole_tty_driver, &netconsole_tty_ops);
+
Quoted 8 lines

drivers/net/netconsole.c static void netconsole_write_msg(const c · line 784

Quoted 6 lines
drivers/net/netconsole.c +6 -0
+	if (tty_register_driver(netconsole_tty_driver))
+		printk(KERN_ERR "Couldn't register netconsole tty driver\n");
+
+	return 0;
+}
+device_initcall(netconsole_tty_init);

Would it be better called from init_netconsole()?

Hmm, I don't remember what the ordering is here. "console_initcall", used with most other console-providing drivers, is done before alloc_tty_driver() can work. However, since init_netconsole() is a "module_initcall", I guess that should work. Well, it must, since init_netconsole() calls kzalloc() already...

Signature · 2 lines
Hollis Blanchard
IBM Linux Technology Center
#4 lore raw

Re: [PATCH 2 of 2] netconsole: add write-only tty driver

In reply to Hollis Blanchard
Quoted 74 lines · Hollis Blanchard

This allows userspace to output to netconsole via the /dev/console device, which is very useful to see initscript output, for example. There is only one netconsole TTY device, and TTY output goes to all receivers specified for console output.

Input via /dev/console is still not implemented, however.

drivers/net/netconsole.c +44 -0
@@ -43,6 +43,7 @@
 #include <linux/netpoll.h>
 #include <linux/inet.h>
 #include <linux/configfs.h>
+#include <linux/tty.h>
 
 MODULE_AUTHOR("Maintainer: Matt Mackall <[email protected]>");
 MODULE_DESCRIPTION("Console driver for network interfaces");
@@ -98,6 +99,8 @@ struct netconsole_target {
 	int			enabled;
 	struct netpoll		np;
 };
+
+static struct tty_driver *netconsole_tty_driver;
 
 #ifdef	CONFIG_NETCONSOLE_DYNAMIC
 
@@ -728,15 +731,74 @@ static void netconsole_write_msg(const c
 	spin_unlock_irqrestore(&target_list_lock, flags);
 }
 
+static int netconsole_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	return 0;
+}
+
+static void netconsole_tty_close(struct tty_struct *tty, struct file *filp)
+{
+}
+
+static int netconsole_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	netconsole_write_msg(buf, count);
+	return count;
+}
+
+static int netconsole_tty_write_room(struct tty_struct *tty)
+{
+	return MAX_PRINT_CHUNK;
+}
+
+static const struct tty_operations netconsole_tty_ops = {
+	.open = netconsole_tty_open,
+	.close = netconsole_tty_close,
+	.write = netconsole_tty_write,
+	.write_room = netconsole_tty_write_room,
+};
+
+static int __init netconsole_tty_init(void)
+{
+	netconsole_tty_driver = alloc_tty_driver(1);
+	if (!netconsole_tty_driver)
+		return -ENOMEM;
+
+	netconsole_tty_driver->owner = THIS_MODULE;
+	netconsole_tty_driver->driver_name = "netcon";
+	netconsole_tty_driver->name = "netcon";
+	netconsole_tty_driver->minor_start = 0;
+	netconsole_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+	netconsole_tty_driver->init_termios = tty_std_termios;
+	netconsole_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+	netconsole_tty_driver->init_termios.c_ispeed = 9600;

drivers/net/netconsole.c static void netconsole_write_msg(const c · line 784

Quoted 10 lines
drivers/net/netconsole.c +10 -0
+	netconsole_tty_driver->init_termios.c_ospeed = 9600;
+	netconsole_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+	tty_set_operations(netconsole_tty_driver, &netconsole_tty_ops);
+
+	if (tty_register_driver(netconsole_tty_driver))
+		printk(KERN_ERR "Couldn't register netconsole tty driver\n");
+
+	return 0;
+}
+device_initcall(netconsole_tty_init);

I agree with Evgeniy that this should be merged into the existing init function. Otherwise there's reader ambiguity about the ordering. Otherwise this looks good.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.
#5 lore raw

PATCH 1/1 netconsole: don't require struct console to send data

In reply to Hollis Blanchard

This will allow callers not on the console path to use write_msg().

drivers/net/netconsole.c +8 -3
@@ -67,7 +67,7 @@ __setup("netconsole=", option_setup);
 /* Linked list of all configured targets */
 static LIST_HEAD(target_list);
 
-/* This needs to be a spinlock because write_msg() cannot sleep */
+/* This needs to be a spinlock because netconsole_write_msg() cannot sleep */
 static DEFINE_SPINLOCK(target_list_lock);
 
 /**
@@ -694,7 +694,7 @@ static struct notifier_block netconsole_
 	.notifier_call  = netconsole_netdev_event,
 };
 
-static void write_msg(struct console *con, const char *msg, unsigned int len)
+static void netconsole_write_msg(const char *msg, unsigned int len)
 {
 	int frag, left;
 	unsigned long flags;
@@ -728,10 +728,15 @@ static void write_msg(struct console *co
 	spin_unlock_irqrestore(&target_list_lock, flags);
 }
 
+static void netconsole_console_write(struct console *con, const char *msg, unsigned int len)
+{
+	netconsole_write_msg(msg, len);
+}
+
 static struct console netconsole = {
 	.name	= "netcon",
 	.flags	= CON_ENABLED,
-	.write	= write_msg,
+	.write	= netconsole_console_write,
 };
 
 static int __init init_netconsole(void)
#6 lore raw

Re: [PATCH 1 of 2] netconsole: don't require struct console to send data

Quoted 30 lines · Hollis Blanchard

This will allow callers not on the console path to use write_msg().

drivers/net/netconsole.c +3 -2
@@ -67,7 +67,7 @@ __setup("netconsole=", option_setup);
 /* Linked list of all configured targets */
 static LIST_HEAD(target_list);
 
-/* This needs to be a spinlock because write_msg() cannot sleep */
+/* This needs to be a spinlock because netconsole_write_msg() cannot sleep */
 static DEFINE_SPINLOCK(target_list_lock);
 
 /**
@@ -694,7 +694,7 @@ static struct notifier_block netconsole_
 	.notifier_call  = netconsole_netdev_event,
 };
 
-static void write_msg(struct console *con, const char *msg, unsigned int len)
+static void netconsole_write_msg(const char *msg, unsigned int len)
 {
 	int frag, left;
 	unsigned long flags;
@@ -728,10 +728,15 @@ static void write_msg(struct console *co
 	spin_unlock_irqrestore(&target_list_lock, flags);
 }
 
+static void netconsole_console_write(struct console *con, const char *msg, unsigned int len)

drivers/net/netconsole.c static void write_msg(struct console *co · line 740

Quoted 10 lines
drivers/net/netconsole.c +5 -1
+{
+	netconsole_write_msg(msg, len);
+}
+
 static struct console netconsole = {
 	.name	= "netcon",
 	.flags	= CON_ENABLED,
-	.write	= write_msg,
+	.write	= netconsole_console_write,
 };

This looks fine functionally, but the name change strikes me as gratuitous.

Quoted 1 line
drivers/net/netconsole.c +0 -0
 static int __init init_netconsole(void)
Signature · 1 line
Mathematics is the supreme nostalgia of our time.
#7 lore raw
In reply to Hollis Blanchard
Quoted 8 lines · Hollis Blanchard

I have a Kuro Box (a small NAS device running Linux), and it has no serial console (nor any other console for that matter). The most convenient way to get boot output is via the netconsole driver, which is what most Kuro owners do. (The u-boot firmware even supports interactive netconsole allowing us to edit boot configuration.)

However, once past kernel boot, userspace currently has no way of outputting data over netconsole. These patches enable that, which is really useful for seeing init script output and debugging ramdisks before they've brought up sshd.

Awesome! I've been meaning to wire this up for ages. I'll try to look at it over the weekend.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.
maintainer
#8 lore raw

From: Matt Mackall <[email protected]>
Date: Thu, 27 Nov 2008 17:09:45 -0600

Quoted 6 lines · Hollis Blanchard
Quoted 5 lines

I have a Kuro Box (a small NAS device running Linux), and it has no serial console (nor any other console for that matter). The most convenient way to get boot output is via the netconsole driver, which is what most Kuro owners do. (The u-boot firmware even supports interactive netconsole allowing us to edit boot configuration.)

Quoted 6 lines
Quoted 3 lines

However, once past kernel boot, userspace currently has no way of outputting data over netconsole. These patches enable that, which is really useful for seeing init script output and debugging ramdisks before they've brought up sshd.

Awesome! I've been meaning to wire this up for ages. I'll try to look at it over the weekend.

Matt if your review goes OK please ACK this and I'll toss these patches into net-next-2.6

Thanks