* Re: [PATCH] detour TTY driver - now ttyprintk
From: Alan Cox @ 2010-06-27 13:35 UTC (permalink / raw)
To: Samo Pogacnik; +Cc: linux-embedded, linux kernel
In-Reply-To: <1277516912.29797.411.camel@itpsd6lap>
> I thought that this would automatically reduce processor load, which is
> obviously not the case. Sorry for the delay, but i am trying to figure
> out how to slow down write method when under pressure.
Ok I played with this a bit. Much to my surprise until I thought about it
in detail it all works fine without any of the ratelimiting at all. There
is a problem if you manage to redirect the console *in kernel* to the
printk driver, but that needs stopping anyway and rate limit won't fix it
(you blow the stack before it kicks in)
In the case where userspace loads it hard and its a graphical console
then we use a lot of CPU power drawing stuff on screen, but killing the
process does as is expected.
With a serial console the printk itself blocks which blocks the line
discipline which in turn slows stuff down.
The only two bad things I can see how to cause are
- Slowing down output by stuffing lots of extra data into the port (which
I can do anyway just fine) so isn't worse than before.
- Filling up the dmesg log easily and hiding important messages. Not
really a problem in this case bcause the whole point of this is
embedded and capturing those messages as if they were system ones.
So much to my surprise the flow control is a red herring and best left
out.
Alan
^ permalink raw reply
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Samo Pogacnik @ 2010-06-26 15:12 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-embedded, linux kernel
In-Reply-To: <20100625120329.1303aa61@lxorguk.ukuu.org.uk>
> > +static int tpk_write_room(struct tty_struct *tty)
> > +{
> > + int ret = tpk_space;
> > +
> > + /* allow char by char under max pressure */
> > + if (tpk_space == 0)
> > + tpk_space = 1;
>
> That won't do what you think, the ldisc will keep seeing progress and
> generate millions of 1 byte I/Os in a loop !
>
Somewhat changed to slowly increase delay in write, if ratelimiting
doesn't end.
> Otherwise looks excellent.
>
Thanks to you.
>
> > + switch (cmd) {
> > + /* Stop TIOCCONS */
> > + case TIOCCONS:
> > + return -EOPNOTSUPP;
>
> And I'll fix this bit up to work properly in the core code.
>
>
> With my devices.txt owner hat on I'll allocate the minor as you suggest
> (and double check this causes no problems), with my tty hat on can you
> send it to GregKH for merging into the tree.
I am not sure if i understand. Should i exclude devices.txt from patch
before sending it to GregKH?
Samo
---
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
0 = /dev/tty Current TTY device
1 = /dev/console System console
2 = /dev/ptmx PTY master multiplex
+ 3 = /dev/ttyprintk User messages via printk TTY device
64 = /dev/cua0 Callout device for ttyS0
...
255 = /dev/cua191 Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
When not in use, each legacy PTY occupies 12 bytes on 32-bit
architectures and 24 bytes on 64-bit architectures.
+config TTY_PRINTK
+ bool "TTY driver to output user messages via printk"
+ default n
+ ---help---
+ If you say Y here, the support for writing user messages (i.e.
+ console messages) via printk is available.
+
+ The feature is useful to inline user messages with kernel
+ messages.
+ In order to use this feature, you should output user messages
+ to /dev/ttyprintk or redirect console to this TTY.
+
+ If unsure, say N.
+
config BRIQ_PANEL
tristate 'Total Impact briQ front panel driver'
depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
+obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o
obj-y += misc.o
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o
obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..2fefa93
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,297 @@
+/*
+ * linux/drivers/char/ttyprintk.c
+ *
+ * Copyright (C) 2010 Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/ratelimit.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+ struct tty_port port;
+ struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+#define TTY_PRINTK_STR_SIZE 508
+static int tpk_space = TTY_PRINTK_STR_SIZE;
+static const char *tpk_tag = "[U] "; /* U for User */
+
+/*
+ * Ratelimiting support to handle to much output to this device,
+ * because of explicit writes or because of unintentional loop
+ * setup (caught printks again sent to this device).
+ */
+static struct ratelimit_state ttyprintk_rs = {
+ .interval = DEFAULT_RATELIMIT_INTERVAL,
+ .burst = DEFAULT_RATELIMIT_BURST,
+};
+
+static int tpk_ratelimiting;
+
+#define ttyprintk_printk(fmt, ...) \
+{ \
+ printk(KERN_INFO fmt, ##__VA_ARGS__); \
+}
+
+/*
+ * Our private ratelimit function, to suppress its printk warnings about
+ * missed callbacks, which are irrelevant in a flow control mechanism.
+ */
+static void ttyprintk_ratelimit(struct ratelimit_state *rs, int count)
+{
+ /* clear ratelimit missed callbacks counter */
+ rs->missed = 0;
+ if (__ratelimit(rs)) {
+ tpk_ratelimiting = 0;
+ tpk_space = TTY_PRINTK_STR_SIZE;
+ rs->burst = DEFAULT_RATELIMIT_BURST;
+ } else {
+ tpk_ratelimiting = 1;
+ if (TTY_PRINTK_STR_SIZE > count)
+ tpk_space = TTY_PRINTK_STR_SIZE - count;
+ else
+ tpk_space = 0;
+ }
+}
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ */
+static int tpk_printk(const unsigned char *buf, int count)
+{
+ static char tmp[TTY_PRINTK_STR_SIZE + 4];
+ static int curr;
+ int i = curr;
+
+ if (buf == NULL) {
+ /* flush tmp[] */
+ if (curr > 0) {
+ /* non nl or cr terminated message - add nl */
+ tmp[curr + 0] = '\n';
+ tmp[curr + 1] = '\0';
+ ttyprintk_printk("%s%s", tpk_tag, tmp);
+ curr = 0;
+ }
+ return i;
+ }
+
+ for (i = 0; i < count; i++) {
+ tmp[curr] = buf[i];
+ if (curr < TTY_PRINTK_STR_SIZE) {
+ switch (buf[i]) {
+ case '\r':
+ /* replace cr with nl */
+ tmp[curr + 0] = '\n';
+ tmp[curr + 1] = '\0';
+ ttyprintk_printk("%s%s", tpk_tag, tmp);
+ curr = 0;
+ if (buf[i + 1] == '\n')
+ i++;
+ break;
+ case '\n':
+ tmp[curr + 1] = '\0';
+ ttyprintk_printk("%s%s", tpk_tag, tmp);
+ curr = 0;
+ break;
+ default:
+ curr++;
+ }
+ } else {
+ /* end of tmp buffer reached: cut the message in two */
+ tmp[curr + 1] = '\\';
+ tmp[curr + 2] = '\n';
+ tmp[curr + 3] = '\0';
+ ttyprintk_printk("%s%s", tpk_tag, tmp);
+ curr = 0;
+ }
+ }
+ if ((tpk_ratelimiting == 0) && (curr > 0)) {
+ /* non nl or cr terminated message - add nl */
+ tmp[curr + 0] = '\n';
+ tmp[curr + 1] = '\0';
+ ttyprintk_printk("%s%s", tpk_tag, tmp);
+ curr = 0;
+ }
+
+ return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+ tty->driver_data = &tpk_port;
+
+ return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+ struct ttyprintk_port *tpkp = tty->driver_data;
+
+ mutex_lock(&tpkp->port_write_mutex);
+ /* flush tpk_printk buffer */
+ tpk_printk(NULL, 0);
+ tpk_space = TTY_PRINTK_STR_SIZE;
+ tpk_ratelimiting = 0;
+ mutex_unlock(&tpkp->port_write_mutex);
+
+ tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+ const unsigned char *buf, int count)
+{
+ static unsigned int tpk_write_delay;
+ struct ttyprintk_port *tpkp = tty->driver_data;
+ int ret;
+
+
+ /* exclusive use of tpk_printk within this tty */
+ mutex_lock(&tpkp->port_write_mutex);
+ ttyprintk_ratelimit(&ttyprintk_rs, count);
+ if (tpk_ratelimiting == 0) {
+ tpk_write_delay = 0;
+ } else {
+ /* increase delay under pressure upto 10 secs */
+ if (tpk_write_delay < 1000000)
+ tpk_write_delay++;
+ msleep_interruptible(tpk_write_delay / 100);
+
+ /* eliminate delay in ratelimiting */
+ ttyprintk_rs.burst = 1;
+ ttyprintk_rs.begin = 0;
+ __ratelimit(&ttyprintk_rs);
+ }
+
+ ret = tpk_printk(buf, count);
+ mutex_unlock(&tpkp->port_write_mutex);
+
+ return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+ int ret = tpk_space;
+
+ /* just in case we reach zero space, let one char available */
+ if (tpk_space == 0)
+ tpk_space = 1;
+
+ return ret;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ttyprintk_port *port;
+
+ port = tty->driver_data;
+
+ if (!port)
+ return -EINVAL;
+
+ switch (cmd) {
+ /* Stop TIOCCONS */
+ case TIOCCONS:
+ return -EOPNOTSUPP;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+ .open = tpk_open,
+ .close = tpk_close,
+ .write = tpk_write,
+ .write_room = tpk_write_room,
+ .ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+ int ret = -ENOMEM;
+ void *rp;
+
+ ttyprintk_driver = alloc_tty_driver(1);
+ if (!ttyprintk_driver)
+ return ret;
+
+ ttyprintk_driver->owner = THIS_MODULE;
+ ttyprintk_driver->driver_name = "ttyprintk";
+ ttyprintk_driver->name = "ttyprintk";
+ ttyprintk_driver->major = TTYAUX_MAJOR;
+ ttyprintk_driver->minor_start = 3;
+ ttyprintk_driver->num = 1;
+ ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+ ttyprintk_driver->init_termios = tty_std_termios;
+ ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+ ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+ ret = tty_register_driver(ttyprintk_driver);
+ if (ret < 0) {
+ printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+ goto error;
+ }
+
+ /* create our unnumbered device */
+ rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+ ttyprintk_driver->name);
+ if (IS_ERR(rp)) {
+ printk(KERN_ERR "Couldn't create ttyprintk device\n");
+ ret = PTR_ERR(rp);
+ goto error;
+ }
+
+ tty_port_init(&tpk_port.port);
+ tpk_port.port.ops = &null_ops;
+ mutex_init(&tpk_port.port_write_mutex);
+
+ return 0;
+
+error:
+ put_tty_driver(ttyprintk_driver);
+ ttyprintk_driver = NULL;
+ return ret;
+}
+module_init(ttyprintk_init);
^ permalink raw reply related
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Samo Pogacnik @ 2010-06-26 1:48 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-embedded, linux kernel
In-Reply-To: <20100625120329.1303aa61@lxorguk.ukuu.org.uk>
> > +static int tpk_write_room(struct tty_struct *tty)
> > +{
> > + int ret = tpk_space;
> > +
> > + /* allow char by char under max pressure */
> > + if (tpk_space == 0)
> > + tpk_space = 1;
>
> That won't do what you think, the ldisc will keep seeing progress and
> generate millions of 1 byte I/Os in a loop !
I thought that this would automatically reduce processor load, which is
obviously not the case. Sorry for the delay, but i am trying to figure
out how to slow down write method when under pressure.
And that setting tpk_space to 1 would then be just in case we reach 0 to
enable further processing.
Samo
^ permalink raw reply
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Alan Cox @ 2010-06-25 11:03 UTC (permalink / raw)
To: Samo Pogacnik; +Cc: linux-embedded, linux kernel
In-Reply-To: <1277462596.2143.101.camel@itpsd6lap>
> +static int tpk_write_room(struct tty_struct *tty)
> +{
> + int ret = tpk_space;
> +
> + /* allow char by char under max pressure */
> + if (tpk_space == 0)
> + tpk_space = 1;
That won't do what you think, the ldisc will keep seeing progress and
generate millions of 1 byte I/Os in a loop !
Otherwise looks excellent.
> + switch (cmd) {
> + /* Stop TIOCCONS */
> + case TIOCCONS:
> + return -EOPNOTSUPP;
And I'll fix this bit up to work properly in the core code.
With my devices.txt owner hat on I'll allocate the minor as you suggest
(and double check this causes no problems), with my tty hat on can you
send it to GregKH for merging into the tree.
^ permalink raw reply
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Samo Pogacnik @ 2010-06-25 10:43 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-embedded, linux kernel
In-Reply-To: <20100622232108.26752ff8@lxorguk.ukuu.org.uk>
> > in some logical manner. And the other would be to use ratelimit support
> > to switch between max and zero in write_room answer and remove other
> > retelimit response?
>
> Yes - except that a driver isn't permitted to reduce the write room space
> by more than bytes written. That is if you offer 512 bytes you can't
> offer 0 until 512 bytes have been written - hence the design of the pseudo
> code I posted in the previous message.
Now flow control is provided in a way that each write ratelimit false
detection shrinks available space for its output lenth. On the other
hand write returns available space back to maximum on true ratelimit
detection result. Additionaly each next write_room returns at least one
character space under high load, if zero space is reached.
Additionally a private ttyprintk_ratelimit function is provided to
suppress "missed callbacks" printks, because we do not really miss
anything.
regards, Samo
----
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
0 = /dev/tty Current TTY device
1 = /dev/console System console
2 = /dev/ptmx PTY master multiplex
+ 3 = /dev/ttyprintk User messages via printk TTY device
64 = /dev/cua0 Callout device for ttyS0
...
255 = /dev/cua191 Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
When not in use, each legacy PTY occupies 12 bytes on 32-bit
architectures and 24 bytes on 64-bit architectures.
+config TTY_PRINTK
+ bool "TTY driver to output user messages via printk"
+ default n
+ ---help---
+ If you say Y here, the support for writing user messages (i.e.
+ console messages) via printk is available.
+
+ The feature is useful to inline user messages with kernel
+ messages.
+ In order to use this feature, you should output user messages
+ to /dev/ttyprintk or redirect console to this TTY.
+
+ If unsure, say N.
+
config BRIQ_PANEL
tristate 'Total Impact briQ front panel driver'
depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
+obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o
obj-y += misc.o
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o
obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..344f2d3
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,264 @@
+/*
+ * linux/drivers/char/ttyprintk.c
+ *
+ * Copyright (C) 2010 Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+ struct tty_port port;
+ struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * Ratelimiting support to handle to much output to this device,
+ * because of explicit writes or because of unintentional loop
+ * setup (caught printks again sent to this device).
+ */
+static struct ratelimit_state ttyprintk_rs = {
+ .interval = DEFAULT_RATELIMIT_INTERVAL,
+ .burst = DEFAULT_RATELIMIT_BURST,
+};
+
+#define ttyprintk_printk(fmt, ...) \
+{ \
+ printk(KERN_INFO fmt, ##__VA_ARGS__); \
+}
+
+/*
+ * Our private ratelimit function, to suppress its printk warnings about
+ * missed callbacks, which are irrelevant in a flow control mechanism.
+ */
+static int ttyprintk_ratelimit(struct ratelimit_state *rs,
+ struct ttyprintk_port *tpkp)
+{
+ int ret;
+
+ /* exclusive call of ttyprintk_ratelimit within this tty */
+ mutex_lock(&tpkp->port_write_mutex);
+ /* clear ratelimit missed callbacks counter */
+ rs->missed = 0;
+ ret = __ratelimit(rs);
+ mutex_unlock(&tpkp->port_write_mutex);
+ return ret;
+}
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ */
+#define TTY_PRINTK_STR_SIZE 508
+static int tpk_space = TTY_PRINTK_STR_SIZE;
+static const char *tpk_tag = "[U] "; /* U for User */
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+ static char tmp[TTY_PRINTK_STR_SIZE + 4];
+ static int curr;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ tmp[curr] = buf[i];
+ if (curr < TTY_PRINTK_STR_SIZE) {
+ switch (buf[i]) {
+ case '\r':
+ /* replace cr with nl */
+ tmp[curr + 0] = '\n';
+ tmp[curr + 1] = '\0';
+ ttyprintk_printk("%s%s", tpk_tag, tmp);
+ curr = 0;
+ if (buf[i + 1] == '\n')
+ i++;
+ break;
+ case '\n':
+ tmp[curr + 1] = '\0';
+ ttyprintk_printk("%s%s", tpk_tag, tmp);
+ curr = 0;
+ break;
+ default:
+ curr++;
+ }
+ } else {
+ /* end of tmp buffer reached: cut the message in two */
+ tmp[curr + 1] = '\\';
+ tmp[curr + 2] = '\n';
+ tmp[curr + 3] = '\0';
+ ttyprintk_printk("%s%s", tpk_tag, tmp);
+ curr = 0;
+ }
+ }
+ if ((tpk_space == TTY_PRINTK_STR_SIZE) && (curr > 0)) {
+ /* non nl or cr terminated message - add nl */
+ tmp[curr + 0] = '\n';
+ tmp[curr + 1] = '\0';
+ ttyprintk_printk("%s%s", tpk_tag, tmp);
+ curr = 0;
+ }
+
+ return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+ tty->driver_data = &tpk_port;
+
+ return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+ struct ttyprintk_port *tpkp = tty->driver_data;
+
+ tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+ const unsigned char *buf, int count)
+{
+ struct ttyprintk_port *tpkp = tty->driver_data;
+ int ret;
+
+ if (ttyprintk_ratelimit(&ttyprintk_rs, tpkp))
+ tpk_space = TTY_PRINTK_STR_SIZE;
+ else {
+ if (tpk_space > count)
+ tpk_space -= count;
+ else
+ tpk_space = 0;
+ }
+
+ /* exclusive use of tpk_printk within this tty */
+ mutex_lock(&tpkp->port_write_mutex);
+ ret = tpk_printk(buf, count);
+ mutex_unlock(&tpkp->port_write_mutex);
+
+ return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+ int ret = tpk_space;
+
+ /* allow char by char under max pressure */
+ if (tpk_space == 0)
+ tpk_space = 1;
+
+ return ret;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ttyprintk_port *port;
+
+ port = tty->driver_data;
+
+ if (!port)
+ return -EINVAL;
+
+ switch (cmd) {
+ /* Stop TIOCCONS */
+ case TIOCCONS:
+ return -EOPNOTSUPP;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+ .open = tpk_open,
+ .close = tpk_close,
+ .write = tpk_write,
+ .write_room = tpk_write_room,
+ .ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+ int ret = -ENOMEM;
+ void *rp;
+
+ ttyprintk_driver = alloc_tty_driver(1);
+ if (!ttyprintk_driver)
+ return ret;
+
+ ttyprintk_driver->owner = THIS_MODULE;
+ ttyprintk_driver->driver_name = "ttyprintk";
+ ttyprintk_driver->name = "ttyprintk";
+ ttyprintk_driver->major = TTYAUX_MAJOR;
+ ttyprintk_driver->minor_start = 3;
+ ttyprintk_driver->num = 1;
+ ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+ ttyprintk_driver->init_termios = tty_std_termios;
+ ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+ ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+ ret = tty_register_driver(ttyprintk_driver);
+ if (ret < 0) {
+ printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+ goto error;
+ }
+
+ /* create our unnumbered device */
+ rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+ ttyprintk_driver->name);
+ if (IS_ERR(rp)) {
+ printk(KERN_ERR "Couldn't create ttyprintk device\n");
+ ret = PTR_ERR(rp);
+ goto error;
+ }
+
+ tty_port_init(&tpk_port.port);
+ tpk_port.port.ops = &null_ops;
+ mutex_init(&tpk_port.port_write_mutex);
+
+ return 0;
+
+error:
+ put_tty_driver(ttyprintk_driver);
+ ttyprintk_driver = NULL;
+ return ret;
+}
+module_init(ttyprintk_init);
^ permalink raw reply related
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Alan Cox @ 2010-06-22 22:21 UTC (permalink / raw)
To: Samo Pogacnik; +Cc: linux-embedded, linux kernel
In-Reply-To: <1277244410.2195.47.camel@itpsd6lap>
> For correct flow control, i suppose current empty space of the real
> (final) printk buffer is needed. On the other hand my intermediate
Console drivers have their own buffering so that doesn't really work. If
you want to just avoid explosions then you don't need to be quite so
clever
> in some logical manner. And the other would be to use ratelimit support
> to switch between max and zero in write_room answer and remove other
> retelimit response?
Yes - except that a driver isn't permitted to reduce the write room space
by more than bytes written. That is if you offer 512 bytes you can't
offer 0 until 512 bytes have been written - hence the design of the pseudo
code I posted in the previous message.
^ permalink raw reply
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Samo Pogacnik @ 2010-06-22 22:06 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-embedded, linux kernel
In-Reply-To: <20100621153858.444695c0@lxorguk.ukuu.org.uk>
On 21.06.2010 (Mon) at 15:38 +0100 Alan Cox wrote:
> > I'm thinking to leave the ratelimit support in for the time being. I had
> > in mind cases, when someone does
> > "cat /proc/kmsg > dev/ttyprintk" or
> > suppose the console is redirected to ttyprintk (which i would like to be
> > able to do from user program)
>
> Console as in the printk sense would then loop.
>
> If you are going to do the flow control you should probably do something
> like
>
>
> write_room()
> {
> if (!flow_controlled)
> space = 8192;
> return space;
> }
>
> write()
> {
> space -= len;
> }
>
> then your flow control will behave properly and slow down users rather
> than losing data (except stuff sent without blocking)
>
For correct flow control, i suppose current empty space of the real
(final) printk buffer is needed. On the other hand my intermediate
pre-formatting buffer is only "one line" long, but serialized on access
in a way that it is always completely available (except for the time of
tpk_printk() function running). As such intermediate buffer only defines
maximum write_room space.
Now there are two ideas. The first one is to dig out current real printk
buffer space (smells like hacking?) and adapt write_room to that space
in some logical manner. And the other would be to use ratelimit support
to switch between max and zero in write_room answer and remove other
retelimit response?
What do you suggest, do i miss something?
regards, Samo
^ permalink raw reply
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Alan Cox @ 2010-06-21 14:38 UTC (permalink / raw)
To: Samo Pogacnik; +Cc: linux-embedded, linux kernel
In-Reply-To: <1276291932.2154.45.camel@itpsd6lap>
> I'm thinking to leave the ratelimit support in for the time being. I had
> in mind cases, when someone does
> "cat /proc/kmsg > dev/ttyprintk" or
> suppose the console is redirected to ttyprintk (which i would like to be
> able to do from user program)
Console as in the printk sense would then loop.
If you are going to do the flow control you should probably do something
like
write_room()
{
if (!flow_controlled)
space = 8192;
return space;
}
write()
{
space -= len;
}
then your flow control will behave properly and slow down users rather
than losing data (except stuff sent without blocking)
^ permalink raw reply
* Re: Information on XIP
From: Wolfgang Denk @ 2010-06-17 15:56 UTC (permalink / raw)
To: Mike Frysinger; +Cc: Tim Bird, linux-embedded
In-Reply-To: <AANLkTinhDRRh0FhREV_YDPiPxPhGxfpo6ckRRag4vwQk@mail.gmail.com>
Dear Mike Frysinger,
In message <AANLkTinhDRRh0FhREV_YDPiPxPhGxfpo6ckRRag4vwQk@mail.gmail.com> you wrote:
>
> > I'm interested in putting together a basic tutorial about
> > XIP, and doing some benchmarking on an ARM platform.
>
> i believe the denk guys have done some benchmarking on ppc, so you
> might want to poke them if they arent on this list
We are here, of course, but I feel we have nothing to contribute. All
our work in this area dates back several years and is probably not
applicable to current software versions any more.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
"Beware of programmers carrying screwdrivers." - Chip Salzenberg
^ permalink raw reply
* Re: Information on XIP
From: Tim Bird @ 2010-06-16 22:33 UTC (permalink / raw)
To: Mike Frysinger; +Cc: linux-embedded
In-Reply-To: <AANLkTinhDRRh0FhREV_YDPiPxPhGxfpo6ckRRag4vwQk@mail.gmail.com>
On 06/16/2010 03:23 PM, Mike Frysinger wrote:
> On Wed, Jun 16, 2010 at 18:19, Tim Bird wrote:
>> I'd like to start collecting information about XIP on the
>> eLinux wiki. If you've done XIP for the kernel or for
>> user-space (application XIP), or know a good source of
>> information about this, please let me know.
>
> Blackfin linux + userspace XIP:
> http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:xip
Thanks!
-- Tim
=============================
Tim Bird
Architecture Group Chair, CE Linux Forum
Senior Staff Engineer, Sony Network Entertainment
=============================
^ permalink raw reply
* Re: Information on XIP
From: Mike Frysinger @ 2010-06-16 22:23 UTC (permalink / raw)
To: Tim Bird; +Cc: linux-embedded
In-Reply-To: <4C194DF0.60307@am.sony.com>
On Wed, Jun 16, 2010 at 18:19, Tim Bird wrote:
> I'd like to start collecting information about XIP on the
> eLinux wiki. Â If you've done XIP for the kernel or for
> user-space (application XIP), or know a good source of
> information about this, please let me know.
Blackfin linux + userspace XIP:
http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:xip
> I'm interested in putting together a basic tutorial about
> XIP, and doing some benchmarking on an ARM platform.
i believe the denk guys have done some benchmarking on ppc, so you
might want to poke them if they arent on this list
-mike
^ permalink raw reply
* Information on XIP
From: Tim Bird @ 2010-06-16 22:19 UTC (permalink / raw)
To: linux-embedded
Hi all,
I'm starting to look at XIP issues with Linux. I know this
sounds strange, but has anyone done anything with XIP
for kernel loadable modules? If so, please let me know.
I'd be interested in hearing about what you've done.
I'd like to start collecting information about XIP on the
eLinux wiki. If you've done XIP for the kernel or for
user-space (application XIP), or know a good source of
information about this, please let me know.
I'm interested in putting together a basic tutorial about
XIP, and doing some benchmarking on an ARM platform.
Thanks,
-- Tim
^ permalink raw reply
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Samo Pogacnik @ 2010-06-11 23:31 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-embedded, linux kernel
In-Reply-To: <20100611134455.3fa7d563@lxorguk.ukuu.org.uk>
> > +/*
> > + * TTY operations open function.
> > + */
> > +static int tpk_open(struct tty_struct *tty, struct file *filp)
> > +{
> > + struct ttyprintk_port *port = &tpk_port;
>
> You can replace the rest with
>
> return tty_port_open(port, tty, filp);
> }
>
fixed
> > + * TTY operations close function.
> > + */
> > +static void tpk_close(struct tty_struct *tty, struct file *filp)
> > +{
> > + struct ttyprintk_port *port = tty->driver_data;
>
> and
> tty_port_close(port, tty, filp);
>
> > +}
>
> which saves a lot of work
>
yeah right, done
> > +
> > +/*
> > + * TTY operations write function.
> > + */
> > +int tpk_write(struct tty_struct *tty,
> > + const unsigned char *buf, int count)
> > +{
> > + struct ttyprintk_port *port;
> > + int ret;
> > +
> > + port = tty->driver_data;
> > +
> > + if (!port)
> > + return 0;
> > +
> > + if (!(port->port.flags & ASYNC_INITIALIZED))
> > + return 0;
>
> These two can't happen if you use tty_port_* so it is better to blow up.
> If you think you may be seeing it occur then use WARN_ON() or similar
>
the two checks were removed
> > +
> > + /* exclusive use of tpk_printk within this tty */
> > + mutex_lock(&port->port_write_mutex);
> > + ret = tpk_printk(buf, count);
> > + mutex_unlock(&port->port_write_mutex);
>
> And this is serialized by the caller (not that having your own lock is
> any harm)
>
own lock peserved just in case
>
> > +#define TPKRLEV (('e'<<8) | 0) /* Wait for ttyprintk ratelimiting event*/
> > +static int tpk_ioctl(struct tty_struct *tty, struct file *file,
> > + unsigned int cmd, unsigned long arg)
> > +{
> > + struct ttyprintk_port *port;
> > +
> > + port = tty->driver_data;
> > +
> > + if (!port)
> > + return -EINVAL;
> > +
> > + switch (cmd) {
> > + case TPKRLEV:
> > + wait_event_interruptible(ttyprintk_ratelimit_wq,
> > + (ttyprintk_ratelimit_event != 0));
>
> Ok that wasn't quite what I had in mind.
ratelimiting remained present
>
> What I was thinking was needed was this
>
> /* Stop TIOCCONS */
> case TIOCCONS:
> return -EOPNOTSUPP;
>
added
> only it won't work that way. I'll sort that out in tty_io.c once the
> driver is happy. That way anything trying to mis-redirect the console
> will get stopped early which is probably more reliable than a ratelimit ?
>
> > + memset(&tpk_port, 0, sizeof(tpk_port));
>
memset removed
> It's static so that isn't needed
>
> > + tty_port_init(&tpk_port.port);
> > + spin_lock_init(&tpk_port.lock);
>
> The one other bit you will need to use the helpers is
>
> struct tty_port_operations null_ops = { };
>
> tpk_port.port->ops = &null_ops;
>
> Alan
Also added, with many thanks,
Samo
----
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
0 = /dev/tty Current TTY device
1 = /dev/console System console
2 = /dev/ptmx PTY master multiplex
+ 3 = /dev/ttyprintk User messages via printk TTY device
64 = /dev/cua0 Callout device for ttyS0
...
255 = /dev/cua191 Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
When not in use, each legacy PTY occupies 12 bytes on 32-bit
architectures and 24 bytes on 64-bit architectures.
+config TTY_PRINTK
+ bool "TTY driver to output user messages via printk"
+ default n
+ ---help---
+ If you say Y here, the support for writing user messages (i.e.
+ console messages) via printk is available.
+
+ The feature is useful to inline user messages with kernel
+ messages.
+ In order to use this feature, you should output user messages
+ to /dev/ttyprintk or redirect console to this TTY.
+
+ If unsure, say N.
+
config BRIQ_PANEL
tristate 'Total Impact briQ front panel driver'
depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
+obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o
obj-y += misc.o
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o
obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..333490d
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,248 @@
+/*
+ * linux/drivers/char/ttyprintk.c
+ *
+ * Copyright (C) 2010 Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+/*
+ * Ratelimiting support to handle to much output to this device,
+ * because of explicit writes or because of unintentional recursive
+ * setup (caught printks again sent to this device).
+ */
+static struct ratelimit_state ttyprintk_rs = {
+ .interval = DEFAULT_RATELIMIT_INTERVAL,
+ .burst = DEFAULT_RATELIMIT_BURST,
+};
+
+/*
+ * Ratelimiting action and notification support
+ */
+static DECLARE_WAIT_QUEUE_HEAD(ttyprintk_ratelimit_wq);
+static int ttyprintk_ratelimit_event;
+
+#define ttyprintk_ratelimited(fmt, ...) \
+{ \
+ if (__ratelimit(&ttyprintk_rs)) { \
+ ttyprintk_ratelimit_event = 0; \
+ printk(KERN_INFO fmt, ##__VA_ARGS__); \
+ } else { \
+ ttyprintk_ratelimit_event = 1; \
+ wake_up_all(&ttyprintk_ratelimit_wq); \
+ } \
+}
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ */
+static const char *tpk_tag = "[U] "; /* U for User */
+#define TTY_PRINTK_STR_SIZE 508
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+ static char tmp[TTY_PRINTK_STR_SIZE + 4];
+ static int curr;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ tmp[curr] = buf[i];
+ if (curr < TTY_PRINTK_STR_SIZE) {
+ switch (buf[i]) {
+ case '\r':
+ /* replace cr with nl */
+ tmp[curr + 0] = '\n';
+ tmp[curr + 1] = '\0';
+ ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+ curr = 0;
+ if (buf[i + 1] == '\n')
+ i++;
+ break;
+ case '\n':
+ tmp[curr + 1] = '\0';
+ ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+ curr = 0;
+ break;
+ default:
+ curr++;
+ }
+ } else {
+ /* end of tmp buffer reached: cut the message in two */
+ tmp[curr + 1] = '\\';
+ tmp[curr + 2] = '\n';
+ tmp[curr + 3] = '\0';
+ ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+ curr = 0;
+ }
+ }
+ if (curr > 0) {
+ /* non nl or cr terminated message - add nl */
+ tmp[curr + 0] = '\n';
+ tmp[curr + 1] = '\0';
+ ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+ curr = 0;
+ }
+
+ return count;
+}
+
+struct ttyprintk_port {
+ struct tty_port port;
+ struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+ tty->driver_data = &tpk_port;
+
+ return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+ struct ttyprintk_port *tpkp = tty->driver_data;
+
+ tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+int tpk_write(struct tty_struct *tty,
+ const unsigned char *buf, int count)
+{
+ struct ttyprintk_port *tpkp = tty->driver_data;
+ int ret;
+
+ /* exclusive use of tpk_printk within this tty */
+ mutex_lock(&tpkp->port_write_mutex);
+ ret = tpk_printk(buf, count);
+ mutex_unlock(&tpkp->port_write_mutex);
+
+ return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+int tpk_write_room(struct tty_struct *tty)
+{
+ return TTY_PRINTK_STR_SIZE;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+#define TPKRLEV (('e'<<8) | 0) /* Wait for ttyprintk ratelimiting event*/
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ttyprintk_port *port;
+
+ port = tty->driver_data;
+
+ if (!port)
+ return -EINVAL;
+
+ switch (cmd) {
+ /* Catch ratelimiting activation */
+ case TPKRLEV:
+ wait_event_interruptible(ttyprintk_ratelimit_wq,
+ (ttyprintk_ratelimit_event != 0));
+ break;
+ /* Stop TIOCCONS */
+ case TIOCCONS:
+ return -EOPNOTSUPP;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+ .open = tpk_open,
+ .close = tpk_close,
+ .write = tpk_write,
+ .write_room = tpk_write_room,
+ .ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+ int ret = -ENOMEM;
+ void *rp;
+
+ ttyprintk_driver = alloc_tty_driver(1);
+ if (!ttyprintk_driver)
+ return ret;
+
+ ttyprintk_driver->owner = THIS_MODULE;
+ ttyprintk_driver->driver_name = "ttyprintk";
+ ttyprintk_driver->name = "ttyprintk";
+ ttyprintk_driver->major = TTYAUX_MAJOR;
+ ttyprintk_driver->minor_start = 3;
+ ttyprintk_driver->num = 1;
+ ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+ ttyprintk_driver->init_termios = tty_std_termios;
+ ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+ ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+ ret = tty_register_driver(ttyprintk_driver);
+ if (ret < 0) {
+ printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+ goto error;
+ }
+
+ /* create our unnumbered device */
+ rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+ ttyprintk_driver->name);
+ if (IS_ERR(rp)) {
+ printk(KERN_ERR "Couldn't create ttyprintk device\n");
+ ret = PTR_ERR(rp);
+ goto error;
+ }
+
+ tty_port_init(&tpk_port.port);
+ tpk_port.port.ops = &null_ops;
+ mutex_init(&tpk_port.port_write_mutex);
+
+ return 0;
+
+error:
+ put_tty_driver(ttyprintk_driver);
+ ttyprintk_driver = NULL;
+ return ret;
+}
+module_init(ttyprintk_init);
^ permalink raw reply related
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Samo Pogacnik @ 2010-06-11 21:32 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-embedded, linux kernel
In-Reply-To: <20100611134455.3fa7d563@lxorguk.ukuu.org.uk>
> > +#define TPKRLEV (('e'<<8) | 0) /* Wait for ttyprintk ratelimiting event*/
> > +static int tpk_ioctl(struct tty_struct *tty, struct file *file,
> > + unsigned int cmd, unsigned long arg)
> > +{
> > + struct ttyprintk_port *port;
> > +
> > + port = tty->driver_data;
> > +
> > + if (!port)
> > + return -EINVAL;
> > +
> > + switch (cmd) {
> > + case TPKRLEV:
> > + wait_event_interruptible(ttyprintk_ratelimit_wq,
> > + (ttyprintk_ratelimit_event != 0));
>
> Ok that wasn't quite what I had in mind.
>
> What I was thinking was needed was this
>
> /* Stop TIOCCONS */
> case TIOCCONS:
> return -EOPNOTSUPP;
>
> only it won't work that way. I'll sort that out in tty_io.c once the
> driver is happy. That way anything trying to mis-redirect the console
> will get stopped early which is probably more reliable than a ratelimit ?
>
I'm thinking to leave the ratelimit support in for the time being. I had
in mind cases, when someone does
"cat /proc/kmsg > dev/ttyprintk" or
suppose the console is redirected to ttyprintk (which i would like to be
able to do from user program) and then someone does:
"cat /proc/kmsg > /dev/console"... or
if console is redirected after this command ?
Were you thinking of some other mis-redirection case?
Samo
^ permalink raw reply
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Alan Cox @ 2010-06-11 12:44 UTC (permalink / raw)
To: Samo Pogacnik; +Cc: linux-embedded, linux kernel
In-Reply-To: <1276123020.16010.97.camel@itpsd6lap>
> +/*
> + * TTY operations open function.
> + */
> +static int tpk_open(struct tty_struct *tty, struct file *filp)
> +{
> + struct ttyprintk_port *port = &tpk_port;
You can replace the rest with
return tty_port_open(port, tty, filp);
}
> + * TTY operations close function.
> + */
> +static void tpk_close(struct tty_struct *tty, struct file *filp)
> +{
> + struct ttyprintk_port *port = tty->driver_data;
and
tty_port_close(port, tty, filp);
> +}
which saves a lot of work
> +
> +/*
> + * TTY operations write function.
> + */
> +int tpk_write(struct tty_struct *tty,
> + const unsigned char *buf, int count)
> +{
> + struct ttyprintk_port *port;
> + int ret;
> +
> + port = tty->driver_data;
> +
> + if (!port)
> + return 0;
> +
> + if (!(port->port.flags & ASYNC_INITIALIZED))
> + return 0;
These two can't happen if you use tty_port_* so it is better to blow up.
If you think you may be seeing it occur then use WARN_ON() or similar
> +
> + /* exclusive use of tpk_printk within this tty */
> + mutex_lock(&port->port_write_mutex);
> + ret = tpk_printk(buf, count);
> + mutex_unlock(&port->port_write_mutex);
And this is serialized by the caller (not that having your own lock is
any harm)
> +#define TPKRLEV (('e'<<8) | 0) /* Wait for ttyprintk ratelimiting event*/
> +static int tpk_ioctl(struct tty_struct *tty, struct file *file,
> + unsigned int cmd, unsigned long arg)
> +{
> + struct ttyprintk_port *port;
> +
> + port = tty->driver_data;
> +
> + if (!port)
> + return -EINVAL;
> +
> + switch (cmd) {
> + case TPKRLEV:
> + wait_event_interruptible(ttyprintk_ratelimit_wq,
> + (ttyprintk_ratelimit_event != 0));
Ok that wasn't quite what I had in mind.
What I was thinking was needed was this
/* Stop TIOCCONS */
case TIOCCONS:
return -EOPNOTSUPP;
only it won't work that way. I'll sort that out in tty_io.c once the
driver is happy. That way anything trying to mis-redirect the console
will get stopped early which is probably more reliable than a ratelimit ?
> + memset(&tpk_port, 0, sizeof(tpk_port));
It's static so that isn't needed
> + tty_port_init(&tpk_port.port);
> + spin_lock_init(&tpk_port.lock);
The one other bit you will need to use the helpers is
struct tty_port_operations null_ops = { };
tpk_port.port->ops = &null_ops;
Alan
^ permalink raw reply
* Re: [PATCH] detour TTY driver - now ttyprintk
From: Samo Pogacnik @ 2010-06-09 22:37 UTC (permalink / raw)
To: linux-embedded; +Cc: linux kernel, Alan Cox
In-Reply-To: <1275175983.2122.42.camel@itpsd6lap>
Hi,
This is another version of former detour TTY driver, trying to follow
Alan's suggestions:
- renamed from detour to ttyprintk
- removed possibility for initial internal redirection of console to
this tty
- providing hopefully more proper open/close tty operations
- fixed initial termios settings
- added primitive write_room operation
- added ratelimting support (recursion check) and an ioctl trap to catch
ratelimiting being activated. i'd appreciate a suggestion on this ioctl
command naming/value and on location of its definition?
- additional error checking
I also have a question about the tioccons() function from the tty_io.c.
Should this function also check, if the redirection tty has been opened
for writing, since there are going to be implicit writes to this tty for
each console message? This would prevent users without write permissions
to successfully perform TIOCCONS ioctl. This would also prevent writing
capable users to successfully perform TIOCCONS with read-only opened
tty, but failing to write console messages to the redirection tty
afterwards. This seems to happen because the mode of opened tty at the
time of issuing TIOCCONS ioctl is remembered.
Alan, could you please give the patch bellow another look?
thanks, Samo
---
Signed-off-by: Samo Pogacnik <samo_pogacnik@t-2.net>
diff --git a_linux/Documentation/devices.txt b_linux/Documentation/devices.txt
index 53d64d3..71aef33 100644
--- a_linux/Documentation/devices.txt
+++ b_linux/Documentation/devices.txt
@@ -239,6 +239,7 @@ Your cooperation is appreciated.
0 = /dev/tty Current TTY device
1 = /dev/console System console
2 = /dev/ptmx PTY master multiplex
+ 3 = /dev/ttyprintk User messages via printk TTY device
64 = /dev/cua0 Callout device for ttyS0
...
255 = /dev/cua191 Callout device for ttyS191
diff --git a_linux/drivers/char/Kconfig b_linux/drivers/char/Kconfig
index 3141dd3..5c38a06 100644
--- a_linux/drivers/char/Kconfig
+++ b_linux/drivers/char/Kconfig
@@ -485,6 +485,20 @@ config LEGACY_PTY_COUNT
When not in use, each legacy PTY occupies 12 bytes on 32-bit
architectures and 24 bytes on 64-bit architectures.
+config TTY_PRINTK
+ bool "TTY driver to output user messages via printk"
+ default n
+ ---help---
+ If you say Y here, the support for writing user messages (i.e.
+ console messages) via printk is available.
+
+ The feature is useful to inline user messages with kernel
+ messages.
+ In order to use this feature, you should output user messages
+ to /dev/ttyprintk or redirect console to this TTY.
+
+ If unsure, say N.
+
config BRIQ_PANEL
tristate 'Total Impact briQ front panel driver'
depends on PPC_CHRP
diff --git a_linux/drivers/char/Makefile b_linux/drivers/char/Makefile
index f957edf..ed60f45 100644
--- a_linux/drivers/char/Makefile
+++ b_linux/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
+obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o
obj-y += misc.o
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o
obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o
diff --git a_linux/drivers/char/ttyprintk.c b_linux/drivers/char/ttyprintk.c
new file mode 100644
index 0000000..5e569e4
--- /dev/null
+++ b_linux/drivers/char/ttyprintk.c
@@ -0,0 +1,305 @@
+/*
+ * linux/drivers/char/ttyprintk.c
+ *
+ * Copyright (C) 2010 Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+/*
+ * Ratelimiting support to handle to much output to this device,
+ * because of explicit writes or because of unintentional recursive
+ * setup (caught printks again sent to this device).
+ */
+static struct ratelimit_state ttyprintk_rs = {
+ .interval = DEFAULT_RATELIMIT_INTERVAL,
+ .burst = DEFAULT_RATELIMIT_BURST,
+};
+
+/*
+ * Ratelimiting action and notification support
+ */
+static DECLARE_WAIT_QUEUE_HEAD(ttyprintk_ratelimit_wq);
+static int ttyprintk_ratelimit_event;
+
+#define ttyprintk_ratelimited(fmt, ...) \
+{ \
+ if (__ratelimit(&ttyprintk_rs)) { \
+ ttyprintk_ratelimit_event = 0; \
+ printk(KERN_INFO fmt, ##__VA_ARGS__); \
+ } else { \
+ ttyprintk_ratelimit_event = 1; \
+ wake_up_all(&ttyprintk_ratelimit_wq); \
+ } \
+}
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ */
+static const char *tpk_tag = "[U] "; /* U for User */
+#define TTY_PRINTK_STR_SIZE 508
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+ static char tmp[TTY_PRINTK_STR_SIZE + 4];
+ static int curr;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ tmp[curr] = buf[i];
+ if (curr < TTY_PRINTK_STR_SIZE) {
+ switch (buf[i]) {
+ case '\r':
+ /* replace cr with nl */
+ tmp[curr + 0] = '\n';
+ tmp[curr + 1] = '\0';
+ ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+ curr = 0;
+ if (buf[i + 1] == '\n')
+ i++;
+ break;
+ case '\n':
+ tmp[curr + 1] = '\0';
+ ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+ curr = 0;
+ break;
+ default:
+ curr++;
+ }
+ } else {
+ /* end of tmp buffer reached: cut the message in two */
+ tmp[curr + 1] = '\\';
+ tmp[curr + 2] = '\n';
+ tmp[curr + 3] = '\0';
+ ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+ curr = 0;
+ }
+ }
+ if (curr > 0) {
+ /* non nl or cr terminated message - add nl */
+ tmp[curr + 0] = '\n';
+ tmp[curr + 1] = '\0';
+ ttyprintk_ratelimited("%s%s", tpk_tag, tmp);
+ curr = 0;
+ }
+
+ return count;
+}
+
+struct ttyprintk_port {
+ struct tty_port port;
+ struct mutex port_write_mutex;
+ spinlock_t lock;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+ struct ttyprintk_port *port = &tpk_port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ port->port.count++;
+ tty->driver_data = port;
+ port->port.tty = tty;
+ clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+ mutex_init(&port->port_write_mutex);
+ port->port.flags |= ASYNC_INITIALIZED;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return 0;
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+ struct ttyprintk_port *port = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (tty_hung_up_p(filp)) {
+ spin_unlock_irqrestore(&port->lock, flags);
+ return;
+ }
+
+ if (tty->count == 1 && port->port.count != 1) {
+ printk(KERN_ERR "tpk_close: bad port count;"
+ " tty->count is 1, port count is %d\n",
+ port->port.count);
+ port->port.count = 1;
+ }
+
+ if (port->port.count > 1) {
+ port->port.count--;
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return;
+ }
+ port->port.flags |= ASYNC_CLOSING;
+ /*
+ * We have no HW to wait for its buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ spin_unlock_irqrestore(&port->lock, flags);
+ /*
+ * We have no HW to handle to stop accepting input.
+ */
+ if (--port->port.count < 0) {
+ printk(KERN_ERR
+ "tpk_close: bad port usage count for ttyprintk: %d\n",
+ port->port.count);
+ port->port.count = 0;
+ }
+
+ tty_ldisc_flush(tty);
+ spin_lock_irqsave(&port->lock, flags);
+ tty->closing = 0;
+ port->port.tty = NULL;
+ spin_unlock_irqrestore(&port->lock, flags);
+ port->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+}
+
+/*
+ * TTY operations write function.
+ */
+int tpk_write(struct tty_struct *tty,
+ const unsigned char *buf, int count)
+{
+ struct ttyprintk_port *port;
+ int ret;
+
+ port = tty->driver_data;
+
+ if (!port)
+ return 0;
+
+ if (!(port->port.flags & ASYNC_INITIALIZED))
+ return 0;
+
+ /* exclusive use of tpk_printk within this tty */
+ mutex_lock(&port->port_write_mutex);
+ ret = tpk_printk(buf, count);
+ mutex_unlock(&port->port_write_mutex);
+
+ return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+int tpk_write_room(struct tty_struct *tty)
+{
+ return TTY_PRINTK_STR_SIZE;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+#define TPKRLEV (('e'<<8) | 0) /* Wait for ttyprintk ratelimiting event*/
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ttyprintk_port *port;
+
+ port = tty->driver_data;
+
+ if (!port)
+ return -EINVAL;
+
+ switch (cmd) {
+ case TPKRLEV:
+ wait_event_interruptible(ttyprintk_ratelimit_wq,
+ (ttyprintk_ratelimit_event != 0));
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+ .open = tpk_open,
+ .close = tpk_close,
+ .write = tpk_write,
+ .write_room = tpk_write_room,
+ .ioctl = tpk_ioctl,
+};
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+ int ret = -ENOMEM;
+ void *rp;
+
+ ttyprintk_driver = alloc_tty_driver(1);
+ if (!ttyprintk_driver)
+ return ret;
+
+ ttyprintk_driver->owner = THIS_MODULE;
+ ttyprintk_driver->driver_name = "ttyprintk";
+ ttyprintk_driver->name = "ttyprintk";
+ ttyprintk_driver->major = TTYAUX_MAJOR;
+ ttyprintk_driver->minor_start = 3;
+ ttyprintk_driver->num = 1;
+ ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+ ttyprintk_driver->init_termios = tty_std_termios;
+ ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+ ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+ ret = tty_register_driver(ttyprintk_driver);
+ if (ret < 0) {
+ printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+ goto error;
+ }
+
+ /* create our unnumbered device */
+ rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+ ttyprintk_driver->name);
+ if (IS_ERR(rp)) {
+ printk(KERN_ERR "Couldn't create ttyprintk device\n");
+ ret = PTR_ERR(rp);
+ goto error;
+ }
+
+ memset(&tpk_port, 0, sizeof(tpk_port));
+ tty_port_init(&tpk_port.port);
+ spin_lock_init(&tpk_port.lock);
+
+ return 0;
+
+error:
+ put_tty_driver(ttyprintk_driver);
+ ttyprintk_driver = NULL;
+ return ret;
+}
+module_init(ttyprintk_init);
^ permalink raw reply related
* Re: omap udc driver problem with beagle board
From: Felipe Balbi @ 2010-05-31 7:29 UTC (permalink / raw)
To: ext Marco Stornelli
Cc: me-uiRdBs8odbtmTBlB0Cgj/Q@public.gmane.org,
Balbi Felipe (Nokia-D/Helsinki),
dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org,
linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Linux Embedded, tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org
In-Reply-To: <AANLkTine39Za56t8UQRJVeoH94dOuoFAysGPq_cXYhEe-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Mon, May 31, 2010 at 09:06:35AM +0200, ext Marco Stornelli wrote:
>Oops, my fault. I see the error in the configuration. Thank you very
>much for your response. I'll try again.
no problem.
--
balbi
DefectiveByDesign.org
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: omap udc driver problem with beagle board
From: Marco Stornelli @ 2010-05-31 7:06 UTC (permalink / raw)
To: me; +Cc: felipe.balbi, dbrownell, linux-usb, linux-omap, Linux Embedded,
tony
In-Reply-To: <20100530160047.GA7704@gandalf>
2010/5/30 Felipe Balbi <me@felipebalbi.com>:
> On Sun, May 30, 2010 at 11:53:49AM +0200, Marco Stornelli wrote:
> beagle board uses musb. You shouldn't be relying on the udc controller.
> Your Kconfig is just wrong.
>
> --
> balbi
>
Oops, my fault. I see the error in the configuration. Thank you very
much for your response. I'll try again.
Regards,
Marco
^ permalink raw reply
* Re: omap udc driver problem with beagle board
From: Marco Stornelli @ 2010-05-31 6:30 UTC (permalink / raw)
To: me; +Cc: felipe.balbi, dbrownell, linux-usb, linux-omap, Linux Embedded,
tony
In-Reply-To: <20100530160047.GA7704@gandalf>
2010/5/30 Felipe Balbi <me@felipebalbi.com>:
> On Sun, May 30, 2010 at 11:53:49AM +0200, Marco Stornelli wrote:
>
> beagle board uses musb. You shouldn't be relying on the udc controller.
> Your Kconfig is just wrong.
>
> --
> balbi
>
Mmm....does it mean that it's not possible to use g_ether driver? I
read in several docs/wiki that it's possible.
Marco
^ permalink raw reply
* Re: omap udc driver problem with beagle board
From: Felipe Balbi @ 2010-05-30 16:00 UTC (permalink / raw)
To: Marco Stornelli
Cc: felipe.balbi, dbrownell, linux-usb, linux-omap, Linux Embedded,
tony
In-Reply-To: <4C0235AD.70008@gmail.com>
On Sun, May 30, 2010 at 11:53:49AM +0200, Marco Stornelli wrote:
> Hi,
>
> I'm using the kernel 2.6.34 with the beagle board rev. c4. I have got
> some problems with the ethernet gadget to use nfs over usb. The problem
> is with the usb. When the g_ether driver register itself, the omap udc
> driver returns ENODEV because the kernel didn't call the probe for
> this driver. Looking at the code, it seems the problem is in board
> specific management of the usb. There isn't the registration of the
> platform device to match the omap udc platform driver. It should be done
> in the omap_usb_init() but in case of beagle board this function is
> never called, so omap udc driver cannot work. Is it a regression? Is
> there any workaround?
beagle board uses musb. You shouldn't be relying on the udc controller.
Your Kconfig is just wrong.
--
balbi
^ permalink raw reply
* omap nand driver problem with beagle board
From: Marco Stornelli @ 2010-05-30 9:54 UTC (permalink / raw)
To: tony, linux-omap; +Cc: Linux Embedded
Hi,
I'm using the kernel 2.6.34 with beagle board rev. c4. The omap nand
driver fails the probe because the field phys_base in the
omap_nand_platform_data struct is never set in the board specific code.
Indeed, the driver fails because the read address is 0x0. Is it a
regression? Has someone the same problem? What is phys address of nand
in this board to fix the problem?
Thanks.
Regards,
Marco
^ permalink raw reply
* omap udc driver problem with beagle board
From: Marco Stornelli @ 2010-05-30 9:53 UTC (permalink / raw)
To: felipe.balbi-xNZwKgViW5gAvxtiuMwx3w,
dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
linux-usb-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Linux Embedded,
tony-4v6yS6AI5VpBDgjK7y7TUQ
Hi,
I'm using the kernel 2.6.34 with the beagle board rev. c4. I have got
some problems with the ethernet gadget to use nfs over usb. The problem
is with the usb. When the g_ether driver register itself, the omap udc
driver returns ENODEV because the kernel didn't call the probe for
this driver. Looking at the code, it seems the problem is in board
specific management of the usb. There isn't the registration of the
platform device to match the omap udc platform driver. It should be done
in the omap_usb_init() but in case of beagle board this function is
never called, so omap udc driver cannot work. Is it a regression? Is
there any workaround?
Thanks.
Regards,
Marco
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] detour TTY driver
From: Samo Pogacnik @ 2010-05-29 23:33 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-embedded, linux kernel, Randy Dunlap, Al Viro
In-Reply-To: <20100529235402.296406d9@lxorguk.ukuu.org.uk>
> > +static void initial_console_redirect(void)
> > +{
> > + long ret;
> > +
> > + /* re-register our fops write function */
> > + detour_fops.write = detour_write;
> > +
> > + detour_file.f_dentry = &detour_dentry;
> > + detour_file.f_dentry->d_inode = &detour_inode;
> > + detour_file.f_op = &detour_fops;
> > + detour_file.f_mode |= FMODE_WRITE;
> > + security_file_alloc(&detour_file);
> > + INIT_LIST_HEAD(&detour_file.f_u.fu_list);
> > +
> > + detour_inode.i_rdev = MKDEV(TTYAUX_MAJOR, 3);
> > + security_inode_alloc(&detour_inode);
> > + INIT_LIST_HEAD(&detour_inode.inotify_watches);
> > +
> > + ret = detour_fops.open(&detour_inode, &detour_file);
> > + printk(KERN_INFO "detour_fops.open() returned %ld\n", ret);
> > + ret = detour_fops.unlocked_ioctl(&detour_file, TIOCCONS, 0);
> > + printk(KERN_INFO "detour_fops.ioctl() returned %ld\n", ret);
> > +}
>
> Bletch.. I'm really opposed to this kind of hackery. Fix your userspace a
> tiny bit.
>
> So
> - Write only tty that uses printk: Looks good to me, implementation
> quibbles only
> - Magic kernel hacks to shuffle things around in the initial console
> logic - hideous. I still really think you need to fix your userspace
>
Thank you for all comments. I'll try to follow them (might take some
time) and i'll remove the internal console redirection magic for sure.
regards, Samo
^ permalink raw reply
* Re: [PATCH] detour TTY driver
From: Al Viro @ 2010-05-29 22:59 UTC (permalink / raw)
To: Alan Cox; +Cc: Samo Pogacnik, linux-embedded, linux kernel, Randy Dunlap
In-Reply-To: <20100529235402.296406d9@lxorguk.ukuu.org.uk>
On Sat, May 29, 2010 at 11:54:02PM +0100, Alan Cox wrote:
> > + /* re-register our fops write function */
> > + detour_fops.write = detour_write;
> > +
> > + detour_file.f_dentry = &detour_dentry;
> > + detour_file.f_dentry->d_inode = &detour_inode;
> > + detour_file.f_op = &detour_fops;
> > + detour_file.f_mode |= FMODE_WRITE;
> > + security_file_alloc(&detour_file);
> > + INIT_LIST_HEAD(&detour_file.f_u.fu_list);
> > +
> > + detour_inode.i_rdev = MKDEV(TTYAUX_MAJOR, 3);
> > + security_inode_alloc(&detour_inode);
> > + INIT_LIST_HEAD(&detour_inode.inotify_watches);
> > +
> > + ret = detour_fops.open(&detour_inode, &detour_file);
> > + printk(KERN_INFO "detour_fops.open() returned %ld\n", ret);
> > + ret = detour_fops.unlocked_ioctl(&detour_file, TIOCCONS, 0);
> > + printk(KERN_INFO "detour_fops.ioctl() returned %ld\n", ret);
That alone is enough for a NAK. Do Not Do That. Fake struct file/dentry/inode
and their uses are not acceptable. Neither is modifying file_operations,
while we are at it.
^ permalink raw reply
* Re: [PATCH] detour TTY driver
From: Alan Cox @ 2010-05-29 22:54 UTC (permalink / raw)
To: Samo Pogacnik; +Cc: linux-embedded, linux kernel, Randy Dunlap
In-Reply-To: <1275171436.2122.29.camel@itpsd6lap>
> Randy, Alan: Would you be so kind to comment on usability and
> acceptability of this tty driver approach? Thanks.
Not sure the naming is ideal (detour what where, simply calling it
'/dev/ttyprintk' might be clearer - but this is detail
> +void set_console_detour(void)
> +{
> + console_detour = 1;
> +}
> +EXPORT_SYMBOL(set_console_detour);
module parameters can be set compiled in with modulename.option=foo so
there are easier ways to do that.
> + * Our simple preformatting:
> + * - every cr is replaced by '^'nl combination
> + * - every non cr or nl ended write is padded with '\'nl combination
> + * - adds a detour source tag in front of each line
This seems to make it more ambiguous
> +/*
> + * Dummy tty ops open for succesfull terminal device open.
> + */
> +static int dty_open(struct tty_struct *tty, struct file *filp)
> +{
> + return 0;
The kernel really expects posix behaviour but I'm not sure how much it
really matters in this case. Fixing that isn't hard though (use tty_port
helpers and basically no supporting functions)
> + /* register our fops write function */
> + tty_default_fops(&detour_fops);
> + detour_fops.write = detour_write;
No. The behaviour of a tty is very precisely defined by the standards and
stomping over things you shouldn't is not good at all. Remember your tty
sets its own initial termios settings so you can set those to give the
initial behaviour you want. You need the tty layer here in your case
anyway as you don't have sufficient locking otherwise !
Also I'd provide a write_room method which always answers 'lots'
Do you need a recursion check. Suppose I open this device and capture
printk console messages to it ? Alternatively maybe you need an ioctl
handler to trap that case and reject it as a stupidity filter (or both ?)
> + cdev_init(&dty_driver->cdev, &detour_fops);
> +
> + /* create our unnumbered device */
> + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
> + dty_driver->name);
These need to check for failures.
> +static void initial_console_redirect(void)
> +{
> + long ret;
> +
> + /* re-register our fops write function */
> + detour_fops.write = detour_write;
> +
> + detour_file.f_dentry = &detour_dentry;
> + detour_file.f_dentry->d_inode = &detour_inode;
> + detour_file.f_op = &detour_fops;
> + detour_file.f_mode |= FMODE_WRITE;
> + security_file_alloc(&detour_file);
> + INIT_LIST_HEAD(&detour_file.f_u.fu_list);
> +
> + detour_inode.i_rdev = MKDEV(TTYAUX_MAJOR, 3);
> + security_inode_alloc(&detour_inode);
> + INIT_LIST_HEAD(&detour_inode.inotify_watches);
> +
> + ret = detour_fops.open(&detour_inode, &detour_file);
> + printk(KERN_INFO "detour_fops.open() returned %ld\n", ret);
> + ret = detour_fops.unlocked_ioctl(&detour_file, TIOCCONS, 0);
> + printk(KERN_INFO "detour_fops.ioctl() returned %ld\n", ret);
> +}
Bletch.. I'm really opposed to this kind of hackery. Fix your userspace a
tiny bit.
So
- Write only tty that uses printk: Looks good to me, implementation
quibbles only
- Magic kernel hacks to shuffle things around in the initial console
logic - hideous. I still really think you need to fix your userspace
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox