Refactor the implementation of n_tty_write() into do_n_tty_write(), and
change n_tty_write() to call do_n_tty_write() after acquiring
tty.termios_rwsem.
This allows the n_tty line dicipline to write to a user tty via
do_n_tty_write() when already holding tty.termios_rwsem.
Signed-off-by: Walt Drummond <[email protected]>
---
drivers/tty/n_tty.c | 76 ++++++++++++++++++++++++++-------------------
1 file changed, 44 insertions(+), 32 deletions(-)
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 5be6d02dc690..6a6e7da80095 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -2231,29 +2231,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
return retval;
}
-/**
- * n_tty_write - write function for tty
- * @tty: tty device
- * @file: file object
- * @buf: userspace buffer pointer
- * @nr: size of I/O
- *
- * Write function of the terminal device. This is serialized with
- * respect to other write callers but not to termios changes, reads
- * and other such events. Since the receive code will echo characters,
- * thus calling driver write methods, the output_lock is used in
- * the output processing functions called here as well as in the
- * echo processing function to protect the column state and space
- * left in the buffer.
- *
- * This code must be sure never to sleep through a hangup.
- *
- * Locking: output_lock to protect column state and space left
- * (note that the process_output*() functions take this
- * lock themselves)
- */
-
-static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
+static ssize_t do_n_tty_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t nr)
{
const unsigned char *b = buf;
@@ -2261,14 +2239,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
int c;
ssize_t retval = 0;
- /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
- if (L_TOSTOP(tty) && file->f_op->write_iter != redirected_tty_write) {
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- }
-
- down_read(&tty->termios_rwsem);
+ lockdep_assert_held_read(&tty->termios_rwsem);
/* Write out any echoed characters that are still pending */
process_echoes(tty);
@@ -2336,10 +2307,51 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
remove_wait_queue(&tty->write_wait, &wait);
if (nr && tty->fasync)
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- up_read(&tty->termios_rwsem);
+
return (b - buf) ? b - buf : retval;
}
+/**
+ * n_tty_write - write function for tty
+ * @tty: tty device
+ * @file: file object
+ * @buf: userspace buffer pointer
+ * @nr: size of I/O
+ *
+ * Write function of the terminal device. This is serialized with
+ * respect to other write callers but not to termios changes, reads
+ * and other such events. Since the receive code will echo characters,
+ * thus calling driver write methods, the output_lock is used in
+ * the output processing functions called here as well as in the
+ * echo processing function to protect the column state and space
+ * left in the buffer.
+ *
+ * This code must be sure never to sleep through a hangup.
+ *
+ * Locking: output_lock to protect column state and space left
+ * (note that the process_output*() functions take this
+ * lock themselves)
+ */
+
+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
+ const unsigned char *buf, size_t nr)
+{
+ ssize_t retval = 0;
+
+ /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
+ if (L_TOSTOP(tty) && file->f_op->write_iter != redirected_tty_write) {
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ }
+
+ down_read(&tty->termios_rwsem);
+ retval = do_n_tty_write(tty, file, buf, nr);
+ up_read(&tty->termios_rwsem);
+
+ return retval;
+}
+
/**
* n_tty_poll - poll method for N_TTY
* @tty: terminal device
--
2.30.2
When triggered by pressing the VSTATUS key or calling the TIOCSTAT
ioctl, the n_tty line discipline will display a message on the user's
tty that provides basic information about the system and an
'interesting' process in the current foreground process group, eg:
load: 0.58 cmd: sleep 744474 [sleeping] 0.36r 0.00u 0.00s 0% 772k
The status message provides:
- System load average
- Command name and process id (from the perspective of the session)
- Scheduler state
- Total wall-clock run time
- User space run time
- System space run time
- Percentage of on-cpu time
- Resident set size
The message is only displayed when the tty has the VSTATUS character
set and the local flag NOKERNINFO disabled; it is always displayed
when TIOCSTAT is called regardless of tty settings.
Signed-off-by: Walt Drummond <[email protected]>
---
drivers/tty/Makefile | 2 +-
drivers/tty/n_tty.c | 37 +++++++++
drivers/tty/n_tty_status.c | 162 +++++++++++++++++++++++++++++++++++++
drivers/tty/tty_io.c | 2 +-
include/linux/tty.h | 123 ++++++++++++++--------------
5 files changed, 265 insertions(+), 61 deletions(-)
create mode 100644 drivers/tty/n_tty_status.c
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 07aca5184a55..84bc99aebcff 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -2,7 +2,7 @@
obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
tty_buffer.o tty_port.o tty_mutex.o \
tty_ldsem.o tty_baudrate.o tty_jobctrl.o \
- n_null.o
+ n_null.o n_tty_status.o
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
obj-$(CONFIG_AUDIT) += tty_audit.o
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 6a6e7da80095..2e9b038e84e0 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -80,6 +80,7 @@
#define ECHO_BLOCK 256
#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
+#define STATUS_LINE_LEN 160 /* tty status line will truncate at this length */
#undef N_TTY_TRACE
#ifdef N_TTY_TRACE
@@ -127,6 +128,8 @@ struct n_tty_data {
struct mutex output_lock;
};
+static int n_tty_status(struct tty_struct *tty);
+
#define MASK(x) ((x) & (N_TTY_BUF_SIZE - 1))
static inline size_t read_cnt(struct n_tty_data *ldata)
@@ -1334,6 +1337,11 @@ static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
commit_echoes(tty);
return;
}
+ if (c == STATUS_CHAR(tty)) {
+ if (!L_NOKERNINFO(tty))
+ n_tty_status(tty);
+ return;
+ }
if (c == '\n') {
if (L_ECHO(tty) || L_ECHONL(tty)) {
echo_char_raw('\n', ldata);
@@ -1763,6 +1771,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
set_bit(EOF_CHAR(tty), ldata->char_map);
set_bit('\n', ldata->char_map);
set_bit(EOL_CHAR(tty), ldata->char_map);
+ set_bit(STATUS_CHAR(tty), ldata->char_map);
if (L_IEXTEN(tty)) {
set_bit(WERASE_CHAR(tty), ldata->char_map);
set_bit(LNEXT_CHAR(tty), ldata->char_map);
@@ -2412,6 +2421,29 @@ static unsigned long inq_canon(struct n_tty_data *ldata)
return nr;
}
+static int n_tty_status(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ char *buf, msg[STATUS_LINE_LEN] = {0};
+ int ret = 0;
+ size_t len = STATUS_LINE_LEN - 1;
+
+ buf = (char *) &msg;
+ ret = n_tty_get_status(tty, buf + 1, &len);
+ if (ret)
+ return ret;
+
+ if (ldata->column != 0) {
+ msg[0] = '\n';
+ len++;
+ } else {
+ buf++;
+ }
+
+ do_n_tty_write(tty, NULL, buf, len);
+ return 0;
+}
+
static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -2429,6 +2461,11 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
retval = read_cnt(ldata);
up_write(&tty->termios_rwsem);
return put_user(retval, (unsigned int __user *) arg);
+ case TIOCSTAT:
+ down_read(&tty->termios_rwsem);
+ retval = n_tty_status(tty);
+ up_read(&tty->termios_rwsem);
+ return retval;
default:
return n_tty_ioctl_helper(tty, cmd, arg);
}
diff --git a/drivers/tty/n_tty_status.c b/drivers/tty/n_tty_status.c
new file mode 100644
index 000000000000..269776db0640
--- /dev/null
+++ b/drivers/tty/n_tty_status.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-1.0+
+/*
+ * n_tty_status.c --- implements VSTATUS and TIOCSTAT from BSD
+ *
+ * Display a basic status message containing information about the
+ * foreground process and system load on the users tty, triggered by
+ * the VSTATUS character or TIOCSTAT. Ex,
+ *
+ * load: 14.11 cmd: tcsh 19623 [running] 185756.62r 88.00u 17.50s 0% 4260k
+ *
+ */
+
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/sched/loadavg.h>
+
+static const char * const task_state_unknown = "unknown";
+static const char * const task_state_array[] = {
+ "running",
+ "sleeping",
+ "disk sleep",
+ "stopped",
+ "tracing stop",
+ "dead",
+ "zombie",
+ "parked",
+ "idle",
+};
+
+static inline unsigned long getRSSk(struct mm_struct *mm)
+{
+ if (mm == NULL)
+ return 0;
+ return get_mm_rss(mm) * PAGE_SIZE / 1024;
+}
+
+static inline long frac_sec(long l)
+{
+ l /= NSEC_PER_MSEC * 10;
+ if (l < 10)
+ l *= 10;
+ return l;
+}
+
+static inline struct task_struct *compare(struct task_struct *new,
+ struct task_struct *old)
+{
+ unsigned int ostate, nstate;
+
+ if (old == NULL)
+ return new;
+
+ ostate = task_state_index(old);
+ nstate = task_state_index(new);
+
+ if (ostate == nstate) {
+ if (old->start_time > new->start_time)
+ return old;
+ return new;
+ }
+
+ if (ostate < nstate)
+ return old;
+
+ return new;
+}
+
+static struct task_struct *pick_process(struct pid *pgrp)
+{
+ struct task_struct *new, *winner = NULL;
+
+ read_lock(&tasklist_lock);
+ do_each_pid_task(pgrp, PIDTYPE_PGID, new) {
+ winner = compare(new, winner);
+ } while_each_pid_task(pgrp, PIDTYPE_PGID, new);
+ read_unlock(&tasklist_lock);
+
+ return winner;
+}
+
+/* We want the pid from the context of session */
+static inline pid_t __get_pid(struct task_struct *tsk, struct tty_struct *tty)
+{
+ return __task_pid_nr_ns(tsk, PIDTYPE_PID, ns_of_pid(tty->ctrl.session));
+}
+
+static inline const char *get_task_state_name(struct task_struct *tsk)
+{
+
+ int index;
+
+ index = task_state_index(tsk);
+ if (index > ARRAY_SIZE(task_state_array))
+ return task_state_unknown;
+ return task_state_array[index];
+}
+
+int n_tty_get_status(struct tty_struct *tty, char *msg, size_t *msglen)
+{
+ unsigned long loadavg[3];
+ uint64_t pcpu, cputime, wallclock;
+ struct task_struct *p;
+ struct rusage rusage;
+ struct timespec64 utime, stime, rtime;
+ char tname[TASK_COMM_LEN];
+ size_t len;
+
+ if (tty == NULL)
+ return -ENOTTY;
+
+ get_avenrun(loadavg, FIXED_1/200, 0);
+ len = scnprintf(msg + len, *msglen - len, "load: %lu.%02lu ",
+ LOAD_INT(loadavg[0]), LOAD_FRAC(loadavg[0]));
+
+ if (tty->ctrl.session == NULL) {
+ len += scnprintf(msg + len, *msglen - len,
+ "not a controlling terminal\n");
+ goto out;
+ }
+
+ if (tty->ctrl.pgrp == NULL) {
+ len += scnprintf(msg + len, *msglen - len,
+ "no foreground process group\n");
+ goto out;
+ }
+
+ p = pick_process(tty->ctrl.pgrp);
+ if (p == NULL) {
+ len += scnprintf(msg + len, *msglen - len,
+ "empty foreground process group\n");
+ goto out;
+ }
+
+ get_task_comm(tname, p);
+ getrusage(p, RUSAGE_BOTH, &rusage);
+ wallclock = ktime_get_ns() - p->start_time;
+
+ utime.tv_sec = rusage.ru_utime.tv_sec;
+ utime.tv_nsec = rusage.ru_utime.tv_usec * NSEC_PER_USEC;
+ stime.tv_sec = rusage.ru_stime.tv_sec;
+ stime.tv_nsec = rusage.ru_stime.tv_usec * NSEC_PER_USEC;
+ rtime = ns_to_timespec64(wallclock);
+
+ cputime = timespec64_to_ns(&utime) + timespec64_to_ns(&stime);
+ pcpu = div64_u64(cputime * 100, wallclock);
+
+ len += scnprintf(msg + len, *msglen - len,
+ /* task, PID, task state */
+ "cmd: %s %d [%s] "
+ /* rtime, utime, stime, %cpu, rss */
+ "%llu.%02lur %llu.%02luu %llu.%02lus %llu%% %luk\n",
+ tname, __get_pid(p, tty),
+ (char *)get_task_state_name(p),
+ rtime.tv_sec, frac_sec(rtime.tv_nsec),
+ utime.tv_sec, frac_sec(utime.tv_nsec),
+ stime.tv_sec, frac_sec(stime.tv_nsec),
+ pcpu, getRSSk(p->mm));
+
+out:
+ *msglen = len;
+ return 0;
+}
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 6616d4a0d41d..f2f4f48ea502 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -125,7 +125,7 @@ struct ktermios tty_std_termios = { /* for the benefit of tty drivers */
.c_oflag = OPOST | ONLCR,
.c_cflag = B38400 | CS8 | CREAD | HUPCL,
.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
- ECHOCTL | ECHOKE | IEXTEN,
+ ECHOCTL | ECHOKE | IEXTEN | NOKERNINFO,
.c_cc = INIT_C_CC,
.c_ispeed = 38400,
.c_ospeed = 38400,
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 5dbd7c5afac7..e6ba6ce2efcb 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -49,71 +49,73 @@
#define WERASE_CHAR(tty) ((tty)->termios.c_cc[VWERASE])
#define LNEXT_CHAR(tty) ((tty)->termios.c_cc[VLNEXT])
#define EOL2_CHAR(tty) ((tty)->termios.c_cc[VEOL2])
+#define STATUS_CHAR(tty) ((tty)->termios.c_cc[VSTATUS])
#define _I_FLAG(tty, f) ((tty)->termios.c_iflag & (f))
#define _O_FLAG(tty, f) ((tty)->termios.c_oflag & (f))
#define _C_FLAG(tty, f) ((tty)->termios.c_cflag & (f))
#define _L_FLAG(tty, f) ((tty)->termios.c_lflag & (f))
-#define I_IGNBRK(tty) _I_FLAG((tty), IGNBRK)
-#define I_BRKINT(tty) _I_FLAG((tty), BRKINT)
-#define I_IGNPAR(tty) _I_FLAG((tty), IGNPAR)
-#define I_PARMRK(tty) _I_FLAG((tty), PARMRK)
-#define I_INPCK(tty) _I_FLAG((tty), INPCK)
-#define I_ISTRIP(tty) _I_FLAG((tty), ISTRIP)
-#define I_INLCR(tty) _I_FLAG((tty), INLCR)
-#define I_IGNCR(tty) _I_FLAG((tty), IGNCR)
-#define I_ICRNL(tty) _I_FLAG((tty), ICRNL)
-#define I_IUCLC(tty) _I_FLAG((tty), IUCLC)
-#define I_IXON(tty) _I_FLAG((tty), IXON)
-#define I_IXANY(tty) _I_FLAG((tty), IXANY)
-#define I_IXOFF(tty) _I_FLAG((tty), IXOFF)
-#define I_IMAXBEL(tty) _I_FLAG((tty), IMAXBEL)
-#define I_IUTF8(tty) _I_FLAG((tty), IUTF8)
-
-#define O_OPOST(tty) _O_FLAG((tty), OPOST)
-#define O_OLCUC(tty) _O_FLAG((tty), OLCUC)
-#define O_ONLCR(tty) _O_FLAG((tty), ONLCR)
-#define O_OCRNL(tty) _O_FLAG((tty), OCRNL)
-#define O_ONOCR(tty) _O_FLAG((tty), ONOCR)
-#define O_ONLRET(tty) _O_FLAG((tty), ONLRET)
-#define O_OFILL(tty) _O_FLAG((tty), OFILL)
-#define O_OFDEL(tty) _O_FLAG((tty), OFDEL)
-#define O_NLDLY(tty) _O_FLAG((tty), NLDLY)
-#define O_CRDLY(tty) _O_FLAG((tty), CRDLY)
-#define O_TABDLY(tty) _O_FLAG((tty), TABDLY)
-#define O_BSDLY(tty) _O_FLAG((tty), BSDLY)
-#define O_VTDLY(tty) _O_FLAG((tty), VTDLY)
-#define O_FFDLY(tty) _O_FLAG((tty), FFDLY)
-
-#define C_BAUD(tty) _C_FLAG((tty), CBAUD)
-#define C_CSIZE(tty) _C_FLAG((tty), CSIZE)
-#define C_CSTOPB(tty) _C_FLAG((tty), CSTOPB)
-#define C_CREAD(tty) _C_FLAG((tty), CREAD)
-#define C_PARENB(tty) _C_FLAG((tty), PARENB)
-#define C_PARODD(tty) _C_FLAG((tty), PARODD)
-#define C_HUPCL(tty) _C_FLAG((tty), HUPCL)
-#define C_CLOCAL(tty) _C_FLAG((tty), CLOCAL)
-#define C_CIBAUD(tty) _C_FLAG((tty), CIBAUD)
-#define C_CRTSCTS(tty) _C_FLAG((tty), CRTSCTS)
-#define C_CMSPAR(tty) _C_FLAG((tty), CMSPAR)
-
-#define L_ISIG(tty) _L_FLAG((tty), ISIG)
-#define L_ICANON(tty) _L_FLAG((tty), ICANON)
-#define L_XCASE(tty) _L_FLAG((tty), XCASE)
-#define L_ECHO(tty) _L_FLAG((tty), ECHO)
-#define L_ECHOE(tty) _L_FLAG((tty), ECHOE)
-#define L_ECHOK(tty) _L_FLAG((tty), ECHOK)
-#define L_ECHONL(tty) _L_FLAG((tty), ECHONL)
-#define L_NOFLSH(tty) _L_FLAG((tty), NOFLSH)
-#define L_TOSTOP(tty) _L_FLAG((tty), TOSTOP)
-#define L_ECHOCTL(tty) _L_FLAG((tty), ECHOCTL)
-#define L_ECHOPRT(tty) _L_FLAG((tty), ECHOPRT)
-#define L_ECHOKE(tty) _L_FLAG((tty), ECHOKE)
-#define L_FLUSHO(tty) _L_FLAG((tty), FLUSHO)
-#define L_PENDIN(tty) _L_FLAG((tty), PENDIN)
-#define L_IEXTEN(tty) _L_FLAG((tty), IEXTEN)
-#define L_EXTPROC(tty) _L_FLAG((tty), EXTPROC)
+#define I_IGNBRK(tty) _I_FLAG((tty), IGNBRK)
+#define I_BRKINT(tty) _I_FLAG((tty), BRKINT)
+#define I_IGNPAR(tty) _I_FLAG((tty), IGNPAR)
+#define I_PARMRK(tty) _I_FLAG((tty), PARMRK)
+#define I_INPCK(tty) _I_FLAG((tty), INPCK)
+#define I_ISTRIP(tty) _I_FLAG((tty), ISTRIP)
+#define I_INLCR(tty) _I_FLAG((tty), INLCR)
+#define I_IGNCR(tty) _I_FLAG((tty), IGNCR)
+#define I_ICRNL(tty) _I_FLAG((tty), ICRNL)
+#define I_IUCLC(tty) _I_FLAG((tty), IUCLC)
+#define I_IXON(tty) _I_FLAG((tty), IXON)
+#define I_IXANY(tty) _I_FLAG((tty), IXANY)
+#define I_IXOFF(tty) _I_FLAG((tty), IXOFF)
+#define I_IMAXBEL(tty) _I_FLAG((tty), IMAXBEL)
+#define I_IUTF8(tty) _I_FLAG((tty), IUTF8)
+
+#define O_OPOST(tty) _O_FLAG((tty), OPOST)
+#define O_OLCUC(tty) _O_FLAG((tty), OLCUC)
+#define O_ONLCR(tty) _O_FLAG((tty), ONLCR)
+#define O_OCRNL(tty) _O_FLAG((tty), OCRNL)
+#define O_ONOCR(tty) _O_FLAG((tty), ONOCR)
+#define O_ONLRET(tty) _O_FLAG((tty), ONLRET)
+#define O_OFILL(tty) _O_FLAG((tty), OFILL)
+#define O_OFDEL(tty) _O_FLAG((tty), OFDEL)
+#define O_NLDLY(tty) _O_FLAG((tty), NLDLY)
+#define O_CRDLY(tty) _O_FLAG((tty), CRDLY)
+#define O_TABDLY(tty) _O_FLAG((tty), TABDLY)
+#define O_BSDLY(tty) _O_FLAG((tty), BSDLY)
+#define O_VTDLY(tty) _O_FLAG((tty), VTDLY)
+#define O_FFDLY(tty) _O_FLAG((tty), FFDLY)
+
+#define C_BAUD(tty) _C_FLAG((tty), CBAUD)
+#define C_CSIZE(tty) _C_FLAG((tty), CSIZE)
+#define C_CSTOPB(tty) _C_FLAG((tty), CSTOPB)
+#define C_CREAD(tty) _C_FLAG((tty), CREAD)
+#define C_PARENB(tty) _C_FLAG((tty), PARENB)
+#define C_PARODD(tty) _C_FLAG((tty), PARODD)
+#define C_HUPCL(tty) _C_FLAG((tty), HUPCL)
+#define C_CLOCAL(tty) _C_FLAG((tty), CLOCAL)
+#define C_CIBAUD(tty) _C_FLAG((tty), CIBAUD)
+#define C_CRTSCTS(tty) _C_FLAG((tty), CRTSCTS)
+#define C_CMSPAR(tty) _C_FLAG((tty), CMSPAR)
+
+#define L_ISIG(tty) _L_FLAG((tty), ISIG)
+#define L_ICANON(tty) _L_FLAG((tty), ICANON)
+#define L_XCASE(tty) _L_FLAG((tty), XCASE)
+#define L_ECHO(tty) _L_FLAG((tty), ECHO)
+#define L_ECHOE(tty) _L_FLAG((tty), ECHOE)
+#define L_ECHOK(tty) _L_FLAG((tty), ECHOK)
+#define L_ECHONL(tty) _L_FLAG((tty), ECHONL)
+#define L_NOFLSH(tty) _L_FLAG((tty), NOFLSH)
+#define L_TOSTOP(tty) _L_FLAG((tty), TOSTOP)
+#define L_ECHOCTL(tty) _L_FLAG((tty), ECHOCTL)
+#define L_ECHOPRT(tty) _L_FLAG((tty), ECHOPRT)
+#define L_ECHOKE(tty) _L_FLAG((tty), ECHOKE)
+#define L_FLUSHO(tty) _L_FLAG((tty), FLUSHO)
+#define L_PENDIN(tty) _L_FLAG((tty), PENDIN)
+#define L_IEXTEN(tty) _L_FLAG((tty), IEXTEN)
+#define L_EXTPROC(tty) _L_FLAG((tty), EXTPROC)
+#define L_NOKERNINFO(tty) _L_FLAG((tty), NOKERNINFO)
struct device;
struct signal_struct;
@@ -388,6 +390,9 @@ void __init n_tty_init(void);
static inline void n_tty_init(void) { }
#endif
+/* n_tty_status.c */
+extern int n_tty_get_status(struct tty_struct *tty, char *msg, size_t *msglen);
+
/* tty_audit.c */
#ifdef CONFIG_AUDIT
void tty_audit_exit(void);
--
2.30.2
Add definitions for the VSTATUS control character, and the NOKERNINFO
local control flag in the termios struct, and add an ioctl number for
the ioctl TIOCSTAT. Also add a default VSTATUS character (Ctrl-T)
default valuses in termios.c_cc. Do this for all architectures.
Signed-off-by: Walt Drummond <[email protected]>
---
arch/alpha/include/asm/termios.h | 4 +--
arch/alpha/include/uapi/asm/ioctls.h | 1 +
arch/alpha/include/uapi/asm/termbits.h | 34 +++++++++++----------
arch/ia64/include/asm/termios.h | 4 +--
arch/ia64/include/uapi/asm/termbits.h | 34 +++++++++++----------
arch/mips/include/asm/termios.h | 4 +--
arch/mips/include/uapi/asm/ioctls.h | 1 +
arch/mips/include/uapi/asm/termbits.h | 36 +++++++++++-----------
arch/parisc/include/asm/termios.h | 4 +--
arch/parisc/include/uapi/asm/ioctls.h | 1 +
arch/parisc/include/uapi/asm/termbits.h | 34 +++++++++++----------
arch/powerpc/include/asm/termios.h | 4 +--
arch/powerpc/include/uapi/asm/ioctls.h | 2 ++
arch/powerpc/include/uapi/asm/termbits.h | 34 +++++++++++----------
arch/s390/include/asm/termios.h | 4 +--
arch/sh/include/uapi/asm/ioctls.h | 1 +
arch/sparc/include/uapi/asm/ioctls.h | 1 +
arch/sparc/include/uapi/asm/termbits.h | 38 +++++++++++++-----------
arch/xtensa/include/uapi/asm/ioctls.h | 1 +
include/asm-generic/termios.h | 4 +--
include/uapi/asm-generic/ioctls.h | 1 +
include/uapi/asm-generic/termbits.h | 34 +++++++++++----------
22 files changed, 152 insertions(+), 129 deletions(-)
diff --git a/arch/alpha/include/asm/termios.h b/arch/alpha/include/asm/termios.h
index b7c77bb1bfd2..d28ddc649286 100644
--- a/arch/alpha/include/asm/termios.h
+++ b/arch/alpha/include/asm/termios.h
@@ -8,9 +8,9 @@
werase=^W kill=^U reprint=^R sxtc=\0
intr=^C quit=^\ susp=^Z <OSF/1 VDSUSP>
start=^Q stop=^S lnext=^V discard=^U
- vmin=\1 vtime=\0
+ vmin=\1 vtime=\0 status=^T
*/
-#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\001\000"
+#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\001\000\024"
/*
* Translate a "termio" structure into a "termios". Ugh.
diff --git a/arch/alpha/include/uapi/asm/ioctls.h b/arch/alpha/include/uapi/asm/ioctls.h
index 971311605288..4a092b917fc1 100644
--- a/arch/alpha/include/uapi/asm/ioctls.h
+++ b/arch/alpha/include/uapi/asm/ioctls.h
@@ -124,5 +124,6 @@
#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TIOCSTAT 0x545E /* display process group stats on tty */
#endif /* _ASM_ALPHA_IOCTLS_H */
diff --git a/arch/alpha/include/uapi/asm/termbits.h b/arch/alpha/include/uapi/asm/termbits.h
index 4575ba34a0ea..c429e60e0b64 100644
--- a/arch/alpha/include/uapi/asm/termbits.h
+++ b/arch/alpha/include/uapi/asm/termbits.h
@@ -70,6 +70,7 @@ struct ktermios {
#define VDISCARD 15
#define VMIN 16
#define VTIME 17
+#define VSTATUS 18
/* c_iflag bits */
#define IGNBRK 0000001
@@ -187,22 +188,23 @@ struct ktermios {
#define IBSHIFT 16
/* c_lflag bits */
-#define ISIG 0x00000080
-#define ICANON 0x00000100
-#define XCASE 0x00004000
-#define ECHO 0x00000008
-#define ECHOE 0x00000002
-#define ECHOK 0x00000004
-#define ECHONL 0x00000010
-#define NOFLSH 0x80000000
-#define TOSTOP 0x00400000
-#define ECHOCTL 0x00000040
-#define ECHOPRT 0x00000020
-#define ECHOKE 0x00000001
-#define FLUSHO 0x00800000
-#define PENDIN 0x20000000
-#define IEXTEN 0x00000400
-#define EXTPROC 0x10000000
+#define ISIG 0x00000080
+#define ICANON 0x00000100
+#define XCASE 0x00004000
+#define ECHO 0x00000008
+#define ECHOE 0x00000002
+#define ECHOK 0x00000004
+#define ECHONL 0x00000010
+#define NOFLSH 0x80000000
+#define TOSTOP 0x00400000
+#define ECHOCTL 0x00000040
+#define ECHOPRT 0x00000020
+#define ECHOKE 0x00000001
+#define FLUSHO 0x00800000
+#define PENDIN 0x20000000
+#define IEXTEN 0x00000400
+#define EXTPROC 0x10000000
+#define NOKERNINFO 0x40000000
/* Values for the ACTION argument to `tcflow'. */
#define TCOOFF 0
diff --git a/arch/ia64/include/asm/termios.h b/arch/ia64/include/asm/termios.h
index 589c026444cc..40e83f9b6ead 100644
--- a/arch/ia64/include/asm/termios.h
+++ b/arch/ia64/include/asm/termios.h
@@ -15,9 +15,9 @@
eof=^D vtime=\0 vmin=\1 sxtc=\0
start=^Q stop=^S susp=^Z eol=\0
reprint=^R discard=^U werase=^W lnext=^V
- eol2=\0
+ eol2=\0 status=^T
*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0\024"
/*
* Translate a "termio" structure into a "termios". Ugh.
diff --git a/arch/ia64/include/uapi/asm/termbits.h b/arch/ia64/include/uapi/asm/termbits.h
index 000a1a297c75..2b6e943a89c6 100644
--- a/arch/ia64/include/uapi/asm/termbits.h
+++ b/arch/ia64/include/uapi/asm/termbits.h
@@ -67,6 +67,7 @@ struct ktermios {
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
+#define VSTATUS 17
/* c_iflag bits */
#define IGNBRK 0000001
@@ -173,22 +174,23 @@ struct ktermios {
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
/* c_lflag bits */
-#define ISIG 0000001
-#define ICANON 0000002
-#define XCASE 0000004
-#define ECHO 0000010
-#define ECHOE 0000020
-#define ECHOK 0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define ECHOCTL 0001000
-#define ECHOPRT 0002000
-#define ECHOKE 0004000
-#define FLUSHO 0010000
-#define PENDIN 0040000
-#define IEXTEN 0100000
-#define EXTPROC 0200000
+#define ISIG 0000001
+#define ICANON 0000002
+#define XCASE 0000004
+#define ECHO 0000010
+#define ECHOE 0000020
+#define ECHOK 0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+#define EXTPROC 0200000
+#define NOKERNINFO 0400000
/* tcflow() and TCXONC use these */
#define TCOOFF 0
diff --git a/arch/mips/include/asm/termios.h b/arch/mips/include/asm/termios.h
index bc29eeacc55a..04729018d882 100644
--- a/arch/mips/include/asm/termios.h
+++ b/arch/mips/include/asm/termios.h
@@ -17,9 +17,9 @@
* vmin=\1 vtime=\0 eol2=\0 swtc=\0
* start=^Q stop=^S susp=^Z vdsusp=
* reprint=^R discard=^U werase=^W lnext=^V
- * eof=^D eol=\0
+ * eof=^D eol=\0 status=^T
*/
-#define INIT_C_CC "\003\034\177\025\1\0\0\0\021\023\032\0\022\017\027\026\004\0"
+#define INIT_C_CC "\003\034\177\025\1\0\0\0\021\023\032\0\022\017\027\026\004\0\024"
#include <linux/string.h>
diff --git a/arch/mips/include/uapi/asm/ioctls.h b/arch/mips/include/uapi/asm/ioctls.h
index 16aa8a766aec..dff4e9a01336 100644
--- a/arch/mips/include/uapi/asm/ioctls.h
+++ b/arch/mips/include/uapi/asm/ioctls.h
@@ -115,5 +115,6 @@
#define TIOCSERSETMULTI 0x5490 /* Set multiport config */
#define TIOCMIWAIT 0x5491 /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x5492 /* read serial port inline interrupt counts */
+#define TIOCSTAT 0x5493 /* display process group stats on tty */
#endif /* __ASM_IOCTLS_H */
diff --git a/arch/mips/include/uapi/asm/termbits.h b/arch/mips/include/uapi/asm/termbits.h
index dfeffba729b7..402d44c2aa9c 100644
--- a/arch/mips/include/uapi/asm/termbits.h
+++ b/arch/mips/include/uapi/asm/termbits.h
@@ -78,6 +78,7 @@ struct ktermios {
#define VLNEXT 15 /* Literal-next character [IEXTEN]. */
#define VEOF 16 /* End-of-file character [ICANON]. */
#define VEOL 17 /* End-of-line character [ICANON]. */
+#define VSTATUS 18
/* c_iflag bits */
#define IGNBRK 0000001 /* Ignore break condition. */
@@ -188,23 +189,24 @@ struct ktermios {
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
/* c_lflag bits */
-#define ISIG 0000001 /* Enable signals. */
-#define ICANON 0000002 /* Do erase and kill processing. */
-#define XCASE 0000004
-#define ECHO 0000010 /* Enable echo. */
-#define ECHOE 0000020 /* Visual erase for ERASE. */
-#define ECHOK 0000040 /* Echo NL after KILL. */
-#define ECHONL 0000100 /* Echo NL even if ECHO is off. */
-#define NOFLSH 0000200 /* Disable flush after interrupt. */
-#define IEXTEN 0000400 /* Enable DISCARD and LNEXT. */
-#define ECHOCTL 0001000 /* Echo control characters as ^X. */
-#define ECHOPRT 0002000 /* Hardcopy visual erase. */
-#define ECHOKE 0004000 /* Visual erase for KILL. */
-#define FLUSHO 0020000
-#define PENDIN 0040000 /* Retype pending input (state). */
-#define TOSTOP 0100000 /* Send SIGTTOU for background output. */
-#define ITOSTOP TOSTOP
-#define EXTPROC 0200000 /* External processing on pty */
+#define ISIG 0000001 /* Enable signals. */
+#define ICANON 0000002 /* Do erase and kill processing. */
+#define XCASE 0000004
+#define ECHO 0000010 /* Enable echo. */
+#define ECHOE 0000020 /* Visual erase for ERASE. */
+#define ECHOK 0000040 /* Echo NL after KILL. */
+#define ECHONL 0000100 /* Echo NL even if ECHO is off. */
+#define NOFLSH 0000200 /* Disable flush after interrupt. */
+#define IEXTEN 0000400 /* Enable DISCARD and LNEXT. */
+#define ECHOCTL 0001000 /* Echo control characters as ^X. */
+#define ECHOPRT 0002000 /* Hardcopy visual erase. */
+#define ECHOKE 0004000 /* Visual erase for KILL. */
+#define FLUSHO 0020000
+#define PENDIN 0040000 /* Retype pending input (state). */
+#define TOSTOP 0100000 /* Send SIGTTOU for background output. */
+#define ITOSTOP TOSTOP
+#define EXTPROC 0200000 /* External processing on pty */
+#define NOKERNINFO 0400000 /* Disable kernel status message */
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
diff --git a/arch/parisc/include/asm/termios.h b/arch/parisc/include/asm/termios.h
index cded9dc90c1b..63c6c7edb0ff 100644
--- a/arch/parisc/include/asm/termios.h
+++ b/arch/parisc/include/asm/termios.h
@@ -9,9 +9,9 @@
eof=^D vtime=\0 vmin=\1 sxtc=\0
start=^Q stop=^S susp=^Z eol=\0
reprint=^R discard=^U werase=^W lnext=^V
- eol2=\0
+ eol2=\0 status=^T
*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0\024"
/*
* Translate a "termio" structure into a "termios". Ugh.
diff --git a/arch/parisc/include/uapi/asm/ioctls.h b/arch/parisc/include/uapi/asm/ioctls.h
index 82d1148c6379..875db5ff080a 100644
--- a/arch/parisc/include/uapi/asm/ioctls.h
+++ b/arch/parisc/include/uapi/asm/ioctls.h
@@ -80,6 +80,7 @@
#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TIOCSTAT 0x545E /* display process group stats on tty */
#define FIOQSIZE 0x5460 /* Get exact space used by quota */
#define TIOCSTART 0x5461
diff --git a/arch/parisc/include/uapi/asm/termbits.h b/arch/parisc/include/uapi/asm/termbits.h
index 40e920f8d683..384df7348b53 100644
--- a/arch/parisc/include/uapi/asm/termbits.h
+++ b/arch/parisc/include/uapi/asm/termbits.h
@@ -58,6 +58,7 @@ struct ktermios {
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
+#define VSTATUS 17
/* c_iflag bits */
@@ -166,22 +167,23 @@ struct ktermios {
/* c_lflag bits */
-#define ISIG 0000001
-#define ICANON 0000002
-#define XCASE 0000004
-#define ECHO 0000010
-#define ECHOE 0000020
-#define ECHOK 0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define ECHOCTL 0001000
-#define ECHOPRT 0002000
-#define ECHOKE 0004000
-#define FLUSHO 0010000
-#define PENDIN 0040000
-#define IEXTEN 0100000
-#define EXTPROC 0200000
+#define ISIG 0000001
+#define ICANON 0000002
+#define XCASE 0000004
+#define ECHO 0000010
+#define ECHOE 0000020
+#define ECHOK 0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+#define EXTPROC 0200000
+#define NOKERNINFO 0400000
/* tcflow() and TCXONC use these */
#define TCOOFF 0
diff --git a/arch/powerpc/include/asm/termios.h b/arch/powerpc/include/asm/termios.h
index 205de8f8a9d3..e5381c8f86f0 100644
--- a/arch/powerpc/include/asm/termios.h
+++ b/arch/powerpc/include/asm/termios.h
@@ -10,8 +10,8 @@
#include <uapi/asm/termios.h>
-/* ^C ^\ del ^U ^D 1 0 0 0 0 ^W ^R ^Z ^Q ^S ^V ^U */
-#define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025"
+/* ^C ^\ del ^U ^D 1 0 0 0 0 ^W ^R ^Z ^Q ^S ^V ^U ^T */
+#define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025\024"
#include <asm-generic/termios-base.h>
diff --git a/arch/powerpc/include/uapi/asm/ioctls.h b/arch/powerpc/include/uapi/asm/ioctls.h
index 2c145da3b774..5fc2449036a7 100644
--- a/arch/powerpc/include/uapi/asm/ioctls.h
+++ b/arch/powerpc/include/uapi/asm/ioctls.h
@@ -120,4 +120,6 @@
#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TIOCSTAT 0x545E /* display process group stats on tty */
+
#endif /* _ASM_POWERPC_IOCTLS_H */
diff --git a/arch/powerpc/include/uapi/asm/termbits.h b/arch/powerpc/include/uapi/asm/termbits.h
index ed18bc61f63d..ffd0e50d680c 100644
--- a/arch/powerpc/include/uapi/asm/termbits.h
+++ b/arch/powerpc/include/uapi/asm/termbits.h
@@ -62,6 +62,7 @@ struct ktermios {
#define VSTOP 14
#define VLNEXT 15
#define VDISCARD 16
+#define VSTATUS 17
/* c_iflag bits */
#define IGNBRK 0000001
@@ -175,22 +176,23 @@ struct ktermios {
#define CRTSCTS 020000000000 /* flow control */
/* c_lflag bits */
-#define ISIG 0x00000080
-#define ICANON 0x00000100
-#define XCASE 0x00004000
-#define ECHO 0x00000008
-#define ECHOE 0x00000002
-#define ECHOK 0x00000004
-#define ECHONL 0x00000010
-#define NOFLSH 0x80000000
-#define TOSTOP 0x00400000
-#define ECHOCTL 0x00000040
-#define ECHOPRT 0x00000020
-#define ECHOKE 0x00000001
-#define FLUSHO 0x00800000
-#define PENDIN 0x20000000
-#define IEXTEN 0x00000400
-#define EXTPROC 0x10000000
+#define ISIG 0x00000080
+#define ICANON 0x00000100
+#define XCASE 0x00004000
+#define ECHO 0x00000008
+#define ECHOE 0x00000002
+#define ECHOK 0x00000004
+#define ECHONL 0x00000010
+#define NOFLSH 0x80000000
+#define TOSTOP 0x00400000
+#define ECHOCTL 0x00000040
+#define ECHOPRT 0x00000020
+#define ECHOKE 0x00000001
+#define FLUSHO 0x00800000
+#define PENDIN 0x20000000
+#define IEXTEN 0x00000400
+#define EXTPROC 0x10000000
+#define NOKERNINFO 0x40000000
/* Values for the ACTION argument to `tcflow'. */
#define TCOOFF 0
diff --git a/arch/s390/include/asm/termios.h b/arch/s390/include/asm/termios.h
index 46fa3020b41e..8d2017f4905d 100644
--- a/arch/s390/include/asm/termios.h
+++ b/arch/s390/include/asm/termios.h
@@ -14,9 +14,9 @@
eof=^D vtime=\0 vmin=\1 sxtc=\0
start=^Q stop=^S susp=^Z eol=\0
reprint=^R discard=^U werase=^W lnext=^V
- eol2=\0
+ eol2=\0 vstatus=^T
*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0\024"
#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
diff --git a/arch/sh/include/uapi/asm/ioctls.h b/arch/sh/include/uapi/asm/ioctls.h
index 11866d4f60e1..a17d6eb802a2 100644
--- a/arch/sh/include/uapi/asm/ioctls.h
+++ b/arch/sh/include/uapi/asm/ioctls.h
@@ -112,5 +112,6 @@
#define TIOCMIWAIT _IO('T', 92) /* 0x545C */ /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TIOCSTAT 0x545F /* display process group stats on tty */
#endif /* __ASM_SH_IOCTLS_H */
diff --git a/arch/sparc/include/uapi/asm/ioctls.h b/arch/sparc/include/uapi/asm/ioctls.h
index 7fd2f5873c9e..2207627ffcd2 100644
--- a/arch/sparc/include/uapi/asm/ioctls.h
+++ b/arch/sparc/include/uapi/asm/ioctls.h
@@ -124,6 +124,7 @@
#define TIOCSERSETMULTI 0x545B /* Set multiport config */
#define TIOCMIWAIT 0x545C /* Wait for change on serial input line(s) */
#define TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */
+#define TIOCSTAT 0x545E /* Display process group stats on tty */
/* Kernel definitions */
diff --git a/arch/sparc/include/uapi/asm/termbits.h b/arch/sparc/include/uapi/asm/termbits.h
index ce5ad5d0f105..ec60e792a125 100644
--- a/arch/sparc/include/uapi/asm/termbits.h
+++ b/arch/sparc/include/uapi/asm/termbits.h
@@ -80,6 +80,7 @@ struct ktermios {
#define VDISCARD 13
#define VWERASE 14
#define VLNEXT 15
+#define VSTATUS 16
/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
* shared with eof/eol
@@ -206,24 +207,25 @@ struct ktermios {
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
-/* c_lflag bits */
-#define ISIG 0x00000001
-#define ICANON 0x00000002
-#define XCASE 0x00000004
-#define ECHO 0x00000008
-#define ECHOE 0x00000010
-#define ECHOK 0x00000020
-#define ECHONL 0x00000040
-#define NOFLSH 0x00000080
-#define TOSTOP 0x00000100
-#define ECHOCTL 0x00000200
-#define ECHOPRT 0x00000400
-#define ECHOKE 0x00000800
-#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */
-#define FLUSHO 0x00002000
-#define PENDIN 0x00004000
-#define IEXTEN 0x00008000
-#define EXTPROC 0x00010000
+/* c_lflag bits */
+#define ISIG 0x00000001
+#define ICANON 0x00000002
+#define XCASE 0x00000004
+#define ECHO 0x00000008
+#define ECHOE 0x00000010
+#define ECHOK 0x00000020
+#define ECHONL 0x00000040
+#define NOFLSH 0x00000080
+#define TOSTOP 0x00000100
+#define ECHOCTL 0x00000200
+#define ECHOPRT 0x00000400
+#define ECHOKE 0x00000800
+#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */
+#define FLUSHO 0x00002000
+#define PENDIN 0x00004000
+#define IEXTEN 0x00008000
+#define EXTPROC 0x00010000
+#define NOKERNINFO 0x00020000
/* modem lines */
#define TIOCM_LE 0x001
diff --git a/arch/xtensa/include/uapi/asm/ioctls.h b/arch/xtensa/include/uapi/asm/ioctls.h
index 6d4a87296c95..7c0198877bcf 100644
--- a/arch/xtensa/include/uapi/asm/ioctls.h
+++ b/arch/xtensa/include/uapi/asm/ioctls.h
@@ -126,5 +126,6 @@
#define TIOCMIWAIT _IO('T', 92) /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TIOCSTAT 0x545E /* display process group stats on tty */
#endif /* _XTENSA_IOCTLS_H */
diff --git a/include/asm-generic/termios.h b/include/asm-generic/termios.h
index b1398d0d4a1d..9b080e1a82d4 100644
--- a/include/asm-generic/termios.h
+++ b/include/asm-generic/termios.h
@@ -10,9 +10,9 @@
eof=^D vtime=\0 vmin=\1 sxtc=\0
start=^Q stop=^S susp=^Z eol=\0
reprint=^R discard=^U werase=^W lnext=^V
- eol2=\0
+ eol2=\0 status=^T
*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0\024"
/*
* Translate a "termio" structure into a "termios". Ugh.
diff --git a/include/uapi/asm-generic/ioctls.h b/include/uapi/asm-generic/ioctls.h
index cdc9f4ca8c27..eafb662d6a0e 100644
--- a/include/uapi/asm-generic/ioctls.h
+++ b/include/uapi/asm-generic/ioctls.h
@@ -97,6 +97,7 @@
#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TIOCSTAT 0x545E /* display process group stats on tty */
/*
* Some arches already define FIOQSIZE due to a historical
diff --git a/include/uapi/asm-generic/termbits.h b/include/uapi/asm-generic/termbits.h
index 2fbaf9ae89dd..cb4e9c6d629f 100644
--- a/include/uapi/asm-generic/termbits.h
+++ b/include/uapi/asm-generic/termbits.h
@@ -58,6 +58,7 @@ struct ktermios {
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
+#define VSTATUS 17
/* c_iflag bits */
#define IGNBRK 0000001
@@ -164,22 +165,23 @@ struct ktermios {
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
/* c_lflag bits */
-#define ISIG 0000001
-#define ICANON 0000002
-#define XCASE 0000004
-#define ECHO 0000010
-#define ECHOE 0000020
-#define ECHOK 0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define ECHOCTL 0001000
-#define ECHOPRT 0002000
-#define ECHOKE 0004000
-#define FLUSHO 0010000
-#define PENDIN 0040000
-#define IEXTEN 0100000
-#define EXTPROC 0200000
+#define ISIG 0000001
+#define ICANON 0000002
+#define XCASE 0000004
+#define ECHO 0000010
+#define ECHOE 0000020
+#define ECHOK 0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+#define EXTPROC 0200000
+#define NOKERNINFO 0400000
/* tcflow() and TCXONC use these */
#define TCOOFF 0
--
2.30.2
On Tue, Jan 18, 2022 at 5:43 AM Walt Drummond <[email protected]> wrote:
> diff --git a/include/uapi/asm-generic/ioctls.h b/include/uapi/asm-generic/ioctls.h
> index cdc9f4ca8c27..eafb662d6a0e 100644
> --- a/include/uapi/asm-generic/ioctls.h
> +++ b/include/uapi/asm-generic/ioctls.h
> @@ -97,6 +97,7 @@
>
> #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
> #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
> +#define TIOCSTAT 0x545E /* display process group stats on tty */
>
> /*
> * Some arches already define FIOQSIZE due to a historical
I don't see any advantage in using the old-style ioctl command definitions
here, and looking through the history of this file, all recent additions used
the now normal _IOWR() style macros, so please use those as well.
Arnd
Cc Oleg, scheduler and mm guys.
Hi,
The processes and their mm handling don't look right to me, but I don't
know that area that well.
Overall, is this really worth the hassle?
BTW I haven't received 2/3.
On 18. 01. 22, 5:43, Walt Drummond wrote:
> When triggered by pressing the VSTATUS key or calling the TIOCSTAT
> ioctl, the n_tty line discipline will display a message on the user's
> tty that provides basic information about the system and an
> 'interesting' process in the current foreground process group, eg:
>
> load: 0.58 cmd: sleep 744474 [sleeping] 0.36r 0.00u 0.00s 0% 772k
>
> The status message provides:
> - System load average
> - Command name and process id (from the perspective of the session)
> - Scheduler state
> - Total wall-clock run time
> - User space run time
> - System space run time
> - Percentage of on-cpu time
> - Resident set size
>
> The message is only displayed when the tty has the VSTATUS character
> set and the local flag NOKERNINFO disabled; it is always displayed
> when TIOCSTAT is called regardless of tty settings.
>
> Signed-off-by: Walt Drummond <[email protected]>
> ---
> drivers/tty/Makefile | 2 +-
> drivers/tty/n_tty.c | 37 +++++++++
> drivers/tty/n_tty_status.c | 162 +++++++++++++++++++++++++++++++++++++
> drivers/tty/tty_io.c | 2 +-
> include/linux/tty.h | 123 ++++++++++++++--------------
> 5 files changed, 265 insertions(+), 61 deletions(-)
> create mode 100644 drivers/tty/n_tty_status.c
>
> diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
> index 07aca5184a55..84bc99aebcff 100644
> --- a/drivers/tty/Makefile
> +++ b/drivers/tty/Makefile
> @@ -2,7 +2,7 @@
> obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
> tty_buffer.o tty_port.o tty_mutex.o \
> tty_ldsem.o tty_baudrate.o tty_jobctrl.o \
> - n_null.o
> + n_null.o n_tty_status.o
> obj-$(CONFIG_LEGACY_PTYS) += pty.o
> obj-$(CONFIG_UNIX98_PTYS) += pty.o
> obj-$(CONFIG_AUDIT) += tty_audit.o
> diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
> index 6a6e7da80095..2e9b038e84e0 100644
> --- a/drivers/tty/n_tty.c
> +++ b/drivers/tty/n_tty.c
> @@ -80,6 +80,7 @@
> #define ECHO_BLOCK 256
> #define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
>
> +#define STATUS_LINE_LEN 160 /* tty status line will truncate at this length */
>
> #undef N_TTY_TRACE
> #ifdef N_TTY_TRACE
> @@ -127,6 +128,8 @@ struct n_tty_data {
> struct mutex output_lock;
> };
>
> +static int n_tty_status(struct tty_struct *tty);
> +
> #define MASK(x) ((x) & (N_TTY_BUF_SIZE - 1))
>
> static inline size_t read_cnt(struct n_tty_data *ldata)
> @@ -1334,6 +1337,11 @@ static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
> commit_echoes(tty);
> return;
> }
> + if (c == STATUS_CHAR(tty)) {
> + if (!L_NOKERNINFO(tty))
> + n_tty_status(tty);
> + return;
> + }
> if (c == '\n') {
> if (L_ECHO(tty) || L_ECHONL(tty)) {
> echo_char_raw('\n', ldata);
> @@ -1763,6 +1771,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
> set_bit(EOF_CHAR(tty), ldata->char_map);
> set_bit('\n', ldata->char_map);
> set_bit(EOL_CHAR(tty), ldata->char_map);
> + set_bit(STATUS_CHAR(tty), ldata->char_map);
> if (L_IEXTEN(tty)) {
> set_bit(WERASE_CHAR(tty), ldata->char_map);
> set_bit(LNEXT_CHAR(tty), ldata->char_map);
> @@ -2412,6 +2421,29 @@ static unsigned long inq_canon(struct n_tty_data *ldata)
> return nr;
> }
>
> +static int n_tty_status(struct tty_struct *tty)
> +{
> + struct n_tty_data *ldata = tty->disc_data;
> + char *buf, msg[STATUS_LINE_LEN] = {0};
160 B on stack?
> + int ret = 0;
> + size_t len = STATUS_LINE_LEN - 1;
> +
> + buf = (char *) &msg;
> + ret = n_tty_get_status(tty, buf + 1, &len);
> + if (ret)
> + return ret;
> +
> + if (ldata->column != 0) {
> + msg[0] = '\n';
> + len++;
It's not clear to me why this is after n_tty_get_status and therefore
you need buf? If you stored \n to msg[0], you could just pass msg (to
rewrite \n) or (msg + 1) to n_tty_get_status() -- depending on
ldata->column, right?
> + } else {
> + buf++;
> + }
> +
> + do_n_tty_write(tty, NULL, buf, len);
> + return 0;
> +}
> +
> static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
> unsigned int cmd, unsigned long arg)
> {
> @@ -2429,6 +2461,11 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
> retval = read_cnt(ldata);
> up_write(&tty->termios_rwsem);
> return put_user(retval, (unsigned int __user *) arg);
> + case TIOCSTAT:
> + down_read(&tty->termios_rwsem);
> + retval = n_tty_status(tty);
> + up_read(&tty->termios_rwsem);
> + return retval;
> default:
> return n_tty_ioctl_helper(tty, cmd, arg);
> }
> diff --git a/drivers/tty/n_tty_status.c b/drivers/tty/n_tty_status.c
> new file mode 100644
> index 000000000000..269776db0640
> --- /dev/null
> +++ b/drivers/tty/n_tty_status.c
> @@ -0,0 +1,162 @@
> +// SPDX-License-Identifier: GPL-1.0+
> +/*
> + * n_tty_status.c --- implements VSTATUS and TIOCSTAT from BSD
> + *
> + * Display a basic status message containing information about the
> + * foreground process and system load on the users tty, triggered by
> + * the VSTATUS character or TIOCSTAT. Ex,
> + *
> + * load: 14.11 cmd: tcsh 19623 [running] 185756.62r 88.00u 17.50s 0% 4260k
> + *
> + */
> +
> +#include <linux/tty.h>
> +#include <linux/mm.h>
> +#include <linux/sched/loadavg.h>
> +
> +static const char * const task_state_unknown = "unknown";
Why do you need a variable for this, actually? Plus why do you need also
a pointer (another 4/8B) to the storage?
> +static const char * const task_state_array[] = {
> + "running",
> + "sleeping",
> + "disk sleep",
> + "stopped",
> + "tracing stop",
> + "dead",
> + "zombie",
> + "parked",
> + "idle",
> +};
> +
> +static inline unsigned long getRSSk(struct mm_struct *mm)
> +{
> + if (mm == NULL)
> + return 0;
> + return get_mm_rss(mm) * PAGE_SIZE / 1024;
> +}
> +
> +static inline long frac_sec(long l)
I don't understand what this does. The name should be more descriptive.
> +{
> + l /= NSEC_PER_MSEC * 10;
> + if (l < 10)
> + l *= 10;
> + return l;
> +}
> +
> +static inline struct task_struct *compare(struct task_struct *new,
> + struct task_struct *old)
> +{
> + unsigned int ostate, nstate;
> +
> + if (old == NULL)
> + return new;
> +
> + ostate = task_state_index(old);
> + nstate = task_state_index(new);
> +
> + if (ostate == nstate) {
> + if (old->start_time > new->start_time)
> + return old;
> + return new;
> + }
> +
> + if (ostate < nstate)
> + return old;
> +
> + return new;
> +}
> +
> +static struct task_struct *pick_process(struct pid *pgrp)
> +{
> + struct task_struct *new, *winner = NULL;
> +
> + read_lock(&tasklist_lock);
> + do_each_pid_task(pgrp, PIDTYPE_PGID, new) {
> + winner = compare(new, winner);
> + } while_each_pid_task(pgrp, PIDTYPE_PGID, new);
Whys is get_task_struct() not needed?
> + read_unlock(&tasklist_lock);
IOW what happens if winner has just died?
> + return winner;
> +}
> +
> +/* We want the pid from the context of session */
> +static inline pid_t __get_pid(struct task_struct *tsk, struct tty_struct *tty)
> +{
> + return __task_pid_nr_ns(tsk, PIDTYPE_PID, ns_of_pid(tty->ctrl.session));
You're holding no locks protecting tty->ctrl.session.
> +}
> +
> +static inline const char *get_task_state_name(struct task_struct *tsk)
This definitely doesn't belong here. How do you ensure it matches the
returned index also in the future. Put it along with
task_index_to_char()? Or simply use task_state_to_char()?
> +{
> +
> + int index;
> +
> + index = task_state_index(tsk);
> + if (index > ARRAY_SIZE(task_state_array))
Should be >=, or?
> + return task_state_unknown;
> + return task_state_array[index];
> +}
> +
> +int n_tty_get_status(struct tty_struct *tty, char *msg, size_t *msglen)
> +{
> + unsigned long loadavg[3];
> + uint64_t pcpu, cputime, wallclock;
> + struct task_struct *p;
> + struct rusage rusage;
> + struct timespec64 utime, stime, rtime;
> + char tname[TASK_COMM_LEN];
How much stack did you consume in sum with its caller n_tty_status()?
> + size_t len;
> +
> + if (tty == NULL)
> + return -ENOTTY;
How can this happen?
> + get_avenrun(loadavg, FIXED_1/200, 0);
> + len = scnprintf(msg + len, *msglen - len, "load: %lu.%02lu ",
> + LOAD_INT(loadavg[0]), LOAD_FRAC(loadavg[0]));
> +
> + if (tty->ctrl.session == NULL) {
> + len += scnprintf(msg + len, *msglen - len,
> + "not a controlling terminal\n");
> + goto out;
> + }
> +
> + if (tty->ctrl.pgrp == NULL) {
> + len += scnprintf(msg + len, *msglen - len,
> + "no foreground process group\n");
> + goto out;
> + }
> +
> + p = pick_process(tty->ctrl.pgrp);
Why is no lock needed?
> + if (p == NULL) {
> + len += scnprintf(msg + len, *msglen - len,
> + "empty foreground process group\n");
> + goto out;
> + }
> +
> + get_task_comm(tname, p);
> + getrusage(p, RUSAGE_BOTH, &rusage);
> + wallclock = ktime_get_ns() - p->start_time;
> +
> + utime.tv_sec = rusage.ru_utime.tv_sec;
> + utime.tv_nsec = rusage.ru_utime.tv_usec * NSEC_PER_USEC;
> + stime.tv_sec = rusage.ru_stime.tv_sec;
> + stime.tv_nsec = rusage.ru_stime.tv_usec * NSEC_PER_USEC;
> + rtime = ns_to_timespec64(wallclock);
> +
> + cputime = timespec64_to_ns(&utime) + timespec64_to_ns(&stime);
> + pcpu = div64_u64(cputime * 100, wallclock);
> +
> + len += scnprintf(msg + len, *msglen - len,
> + /* task, PID, task state */
> + "cmd: %s %d [%s] "
> + /* rtime, utime, stime, %cpu, rss */
> + "%llu.%02lur %llu.%02luu %llu.%02lus %llu%% %luk\n",
> + tname, __get_pid(p, tty),
> + (char *)get_task_state_name(p),
> + rtime.tv_sec, frac_sec(rtime.tv_nsec),
> + utime.tv_sec, frac_sec(utime.tv_nsec),
> + stime.tv_sec, frac_sec(stime.tv_nsec),
> + pcpu, getRSSk(p->mm));
Why do you think p->mm is still alive (even after the getRSSk()'s
check)? So no get_task_mm() needed?
> +out:
> + *msglen = len;
> + return 0;
> +}
> diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
> index 6616d4a0d41d..f2f4f48ea502 100644
> --- a/drivers/tty/tty_io.c
> +++ b/drivers/tty/tty_io.c
> @@ -125,7 +125,7 @@ struct ktermios tty_std_termios = { /* for the benefit of tty drivers */
> .c_oflag = OPOST | ONLCR,
> .c_cflag = B38400 | CS8 | CREAD | HUPCL,
> .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
> - ECHOCTL | ECHOKE | IEXTEN,
> + ECHOCTL | ECHOKE | IEXTEN | NOKERNINFO,
> .c_cc = INIT_C_CC,
> .c_ispeed = 38400,
> .c_ospeed = 38400,
> diff --git a/include/linux/tty.h b/include/linux/tty.h
> index 5dbd7c5afac7..e6ba6ce2efcb 100644
> --- a/include/linux/tty.h
> +++ b/include/linux/tty.h
> @@ -49,71 +49,73 @@
> #define WERASE_CHAR(tty) ((tty)->termios.c_cc[VWERASE])
> #define LNEXT_CHAR(tty) ((tty)->termios.c_cc[VLNEXT])
> #define EOL2_CHAR(tty) ((tty)->termios.c_cc[VEOL2])
> +#define STATUS_CHAR(tty) ((tty)->termios.c_cc[VSTATUS])
>
> #define _I_FLAG(tty, f) ((tty)->termios.c_iflag & (f))
> #define _O_FLAG(tty, f) ((tty)->termios.c_oflag & (f))
> #define _C_FLAG(tty, f) ((tty)->termios.c_cflag & (f))
> #define _L_FLAG(tty, f) ((tty)->termios.c_lflag & (f))
>
> -#define I_IGNBRK(tty) _I_FLAG((tty), IGNBRK)
> -#define I_BRKINT(tty) _I_FLAG((tty), BRKINT)
> -#define I_IGNPAR(tty) _I_FLAG((tty), IGNPAR)
> -#define I_PARMRK(tty) _I_FLAG((tty), PARMRK)
> -#define I_INPCK(tty) _I_FLAG((tty), INPCK)
> -#define I_ISTRIP(tty) _I_FLAG((tty), ISTRIP)
> -#define I_INLCR(tty) _I_FLAG((tty), INLCR)
> -#define I_IGNCR(tty) _I_FLAG((tty), IGNCR)
> -#define I_ICRNL(tty) _I_FLAG((tty), ICRNL)
> -#define I_IUCLC(tty) _I_FLAG((tty), IUCLC)
> -#define I_IXON(tty) _I_FLAG((tty), IXON)
> -#define I_IXANY(tty) _I_FLAG((tty), IXANY)
> -#define I_IXOFF(tty) _I_FLAG((tty), IXOFF)
> -#define I_IMAXBEL(tty) _I_FLAG((tty), IMAXBEL)
> -#define I_IUTF8(tty) _I_FLAG((tty), IUTF8)
> -
> -#define O_OPOST(tty) _O_FLAG((tty), OPOST)
> -#define O_OLCUC(tty) _O_FLAG((tty), OLCUC)
> -#define O_ONLCR(tty) _O_FLAG((tty), ONLCR)
> -#define O_OCRNL(tty) _O_FLAG((tty), OCRNL)
> -#define O_ONOCR(tty) _O_FLAG((tty), ONOCR)
> -#define O_ONLRET(tty) _O_FLAG((tty), ONLRET)
> -#define O_OFILL(tty) _O_FLAG((tty), OFILL)
> -#define O_OFDEL(tty) _O_FLAG((tty), OFDEL)
> -#define O_NLDLY(tty) _O_FLAG((tty), NLDLY)
> -#define O_CRDLY(tty) _O_FLAG((tty), CRDLY)
> -#define O_TABDLY(tty) _O_FLAG((tty), TABDLY)
> -#define O_BSDLY(tty) _O_FLAG((tty), BSDLY)
> -#define O_VTDLY(tty) _O_FLAG((tty), VTDLY)
> -#define O_FFDLY(tty) _O_FLAG((tty), FFDLY)
> -
> -#define C_BAUD(tty) _C_FLAG((tty), CBAUD)
> -#define C_CSIZE(tty) _C_FLAG((tty), CSIZE)
> -#define C_CSTOPB(tty) _C_FLAG((tty), CSTOPB)
> -#define C_CREAD(tty) _C_FLAG((tty), CREAD)
> -#define C_PARENB(tty) _C_FLAG((tty), PARENB)
> -#define C_PARODD(tty) _C_FLAG((tty), PARODD)
> -#define C_HUPCL(tty) _C_FLAG((tty), HUPCL)
> -#define C_CLOCAL(tty) _C_FLAG((tty), CLOCAL)
> -#define C_CIBAUD(tty) _C_FLAG((tty), CIBAUD)
> -#define C_CRTSCTS(tty) _C_FLAG((tty), CRTSCTS)
> -#define C_CMSPAR(tty) _C_FLAG((tty), CMSPAR)
> -
> -#define L_ISIG(tty) _L_FLAG((tty), ISIG)
> -#define L_ICANON(tty) _L_FLAG((tty), ICANON)
> -#define L_XCASE(tty) _L_FLAG((tty), XCASE)
> -#define L_ECHO(tty) _L_FLAG((tty), ECHO)
> -#define L_ECHOE(tty) _L_FLAG((tty), ECHOE)
> -#define L_ECHOK(tty) _L_FLAG((tty), ECHOK)
> -#define L_ECHONL(tty) _L_FLAG((tty), ECHONL)
> -#define L_NOFLSH(tty) _L_FLAG((tty), NOFLSH)
> -#define L_TOSTOP(tty) _L_FLAG((tty), TOSTOP)
> -#define L_ECHOCTL(tty) _L_FLAG((tty), ECHOCTL)
> -#define L_ECHOPRT(tty) _L_FLAG((tty), ECHOPRT)
> -#define L_ECHOKE(tty) _L_FLAG((tty), ECHOKE)
> -#define L_FLUSHO(tty) _L_FLAG((tty), FLUSHO)
> -#define L_PENDIN(tty) _L_FLAG((tty), PENDIN)
> -#define L_IEXTEN(tty) _L_FLAG((tty), IEXTEN)
> -#define L_EXTPROC(tty) _L_FLAG((tty), EXTPROC)
> +#define I_IGNBRK(tty) _I_FLAG((tty), IGNBRK)
> +#define I_BRKINT(tty) _I_FLAG((tty), BRKINT)
> +#define I_IGNPAR(tty) _I_FLAG((tty), IGNPAR)
> +#define I_PARMRK(tty) _I_FLAG((tty), PARMRK)
> +#define I_INPCK(tty) _I_FLAG((tty), INPCK)
> +#define I_ISTRIP(tty) _I_FLAG((tty), ISTRIP)
> +#define I_INLCR(tty) _I_FLAG((tty), INLCR)
> +#define I_IGNCR(tty) _I_FLAG((tty), IGNCR)
> +#define I_ICRNL(tty) _I_FLAG((tty), ICRNL)
> +#define I_IUCLC(tty) _I_FLAG((tty), IUCLC)
> +#define I_IXON(tty) _I_FLAG((tty), IXON)
> +#define I_IXANY(tty) _I_FLAG((tty), IXANY)
> +#define I_IXOFF(tty) _I_FLAG((tty), IXOFF)
> +#define I_IMAXBEL(tty) _I_FLAG((tty), IMAXBEL)
> +#define I_IUTF8(tty) _I_FLAG((tty), IUTF8)
> +
> +#define O_OPOST(tty) _O_FLAG((tty), OPOST)
> +#define O_OLCUC(tty) _O_FLAG((tty), OLCUC)
> +#define O_ONLCR(tty) _O_FLAG((tty), ONLCR)
> +#define O_OCRNL(tty) _O_FLAG((tty), OCRNL)
> +#define O_ONOCR(tty) _O_FLAG((tty), ONOCR)
> +#define O_ONLRET(tty) _O_FLAG((tty), ONLRET)
> +#define O_OFILL(tty) _O_FLAG((tty), OFILL)
> +#define O_OFDEL(tty) _O_FLAG((tty), OFDEL)
> +#define O_NLDLY(tty) _O_FLAG((tty), NLDLY)
> +#define O_CRDLY(tty) _O_FLAG((tty), CRDLY)
> +#define O_TABDLY(tty) _O_FLAG((tty), TABDLY)
> +#define O_BSDLY(tty) _O_FLAG((tty), BSDLY)
> +#define O_VTDLY(tty) _O_FLAG((tty), VTDLY)
> +#define O_FFDLY(tty) _O_FLAG((tty), FFDLY)
> +
> +#define C_BAUD(tty) _C_FLAG((tty), CBAUD)
> +#define C_CSIZE(tty) _C_FLAG((tty), CSIZE)
> +#define C_CSTOPB(tty) _C_FLAG((tty), CSTOPB)
> +#define C_CREAD(tty) _C_FLAG((tty), CREAD)
> +#define C_PARENB(tty) _C_FLAG((tty), PARENB)
> +#define C_PARODD(tty) _C_FLAG((tty), PARODD)
> +#define C_HUPCL(tty) _C_FLAG((tty), HUPCL)
> +#define C_CLOCAL(tty) _C_FLAG((tty), CLOCAL)
> +#define C_CIBAUD(tty) _C_FLAG((tty), CIBAUD)
> +#define C_CRTSCTS(tty) _C_FLAG((tty), CRTSCTS)
> +#define C_CMSPAR(tty) _C_FLAG((tty), CMSPAR)
> +
> +#define L_ISIG(tty) _L_FLAG((tty), ISIG)
> +#define L_ICANON(tty) _L_FLAG((tty), ICANON)
> +#define L_XCASE(tty) _L_FLAG((tty), XCASE)
> +#define L_ECHO(tty) _L_FLAG((tty), ECHO)
> +#define L_ECHOE(tty) _L_FLAG((tty), ECHOE)
> +#define L_ECHOK(tty) _L_FLAG((tty), ECHOK)
> +#define L_ECHONL(tty) _L_FLAG((tty), ECHONL)
> +#define L_NOFLSH(tty) _L_FLAG((tty), NOFLSH)
> +#define L_TOSTOP(tty) _L_FLAG((tty), TOSTOP)
> +#define L_ECHOCTL(tty) _L_FLAG((tty), ECHOCTL)
> +#define L_ECHOPRT(tty) _L_FLAG((tty), ECHOPRT)
> +#define L_ECHOKE(tty) _L_FLAG((tty), ECHOKE)
> +#define L_FLUSHO(tty) _L_FLAG((tty), FLUSHO)
> +#define L_PENDIN(tty) _L_FLAG((tty), PENDIN)
> +#define L_IEXTEN(tty) _L_FLAG((tty), IEXTEN)
> +#define L_EXTPROC(tty) _L_FLAG((tty), EXTPROC)
> +#define L_NOKERNINFO(tty) _L_FLAG((tty), NOKERNINFO)
Huh, no. Don't do this in this patch. It's unclear what you are actually
doing here -- it's lost in all those whitespace or whatnot changes.
> struct device;
> struct signal_struct;
> @@ -388,6 +390,9 @@ void __init n_tty_init(void);
> static inline void n_tty_init(void) { }
> #endif
>
> +/* n_tty_status.c */
> +extern int n_tty_get_status(struct tty_struct *tty, char *msg, size_t *msglen);
Don't put any externs here to be consistent with the rest of the file.
> /* tty_audit.c */
> #ifdef CONFIG_AUDIT
> void tty_audit_exit(void);
thanks,
--
js
suse labs
On Tue, Jan 18, 2022 at 11:29:54AM +0100, Jiri Slaby wrote:
> > +static const char * const task_state_array[] = {
> > + "running",
> > + "sleeping",
> > + "disk sleep",
> > + "stopped",
> > + "tracing stop",
> > + "dead",
> > + "zombie",
> > + "parked",
> > + "idle",
> > +};
Please no; don't add yet another one of these things. Can't you use the
one in fs/proc/array.c ?
> > +static inline struct task_struct *compare(struct task_struct *new,
> > + struct task_struct *old)
> > +{
> > + unsigned int ostate, nstate;
> > +
> > + if (old == NULL)
> > + return new;
> > +
> > + ostate = task_state_index(old);
> > + nstate = task_state_index(new);
> > +
> > + if (ostate == nstate) {
That's not an ordered set, please don't do that.
> > + if (old->start_time > new->start_time)
> > + return old;
> > + return new;
> > + }
> > +
> > + if (ostate < nstate)
> > + return old;
> > +
> > + return new;
> > +}
> > +static inline const char *get_task_state_name(struct task_struct *tsk)
>
> This definitely doesn't belong here. How do you ensure it matches the
> returned index also in the future. Put it along with task_index_to_char()?
> Or simply use task_state_to_char()?
>
> > +{
> > +
> > + int index;
> > +
> > + index = task_state_index(tsk);
> > + if (index > ARRAY_SIZE(task_state_array))
>
> Should be >=, or?
>
> > + return task_state_unknown;
> > + return task_state_array[index];
> > +}
*groan*.. that's very bad copy paste from fs/proc/array.c. There at east
there's a BUILD_BUG_ON() to make sure things are good.
> > +
> > +int n_tty_get_status(struct tty_struct *tty, char *msg, size_t *msglen)
> > +{
> > + unsigned long loadavg[3];
> > + uint64_t pcpu, cputime, wallclock;
> > + struct task_struct *p;
> > + struct rusage rusage;
> > + struct timespec64 utime, stime, rtime;
> > + char tname[TASK_COMM_LEN];
>
> How much stack did you consume in sum with its caller n_tty_status()?
>
> > + size_t len;
> > +
> > + if (tty == NULL)
> > + return -ENOTTY;
>
> How can this happen?
>
> > + get_avenrun(loadavg, FIXED_1/200, 0);
> > + len = scnprintf(msg + len, *msglen - len, "load: %lu.%02lu ",
> > + LOAD_INT(loadavg[0]), LOAD_FRAC(loadavg[0]));
> > +
> > + if (tty->ctrl.session == NULL) {
> > + len += scnprintf(msg + len, *msglen - len,
> > + "not a controlling terminal\n");
> > + goto out;
> > + }
> > +
> > + if (tty->ctrl.pgrp == NULL) {
> > + len += scnprintf(msg + len, *msglen - len,
> > + "no foreground process group\n");
> > + goto out;
> > + }
> > +
> > + p = pick_process(tty->ctrl.pgrp);
>
> Why is no lock needed?
>
> > + if (p == NULL) {
> > + len += scnprintf(msg + len, *msglen - len,
> > + "empty foreground process group\n");
> > + goto out;
> > + }
> > +
> > + get_task_comm(tname, p);
> > + getrusage(p, RUSAGE_BOTH, &rusage);
> > + wallclock = ktime_get_ns() - p->start_time;
> > +
> > + utime.tv_sec = rusage.ru_utime.tv_sec;
> > + utime.tv_nsec = rusage.ru_utime.tv_usec * NSEC_PER_USEC;
> > + stime.tv_sec = rusage.ru_stime.tv_sec;
> > + stime.tv_nsec = rusage.ru_stime.tv_usec * NSEC_PER_USEC;
> > + rtime = ns_to_timespec64(wallclock);
> > +
> > + cputime = timespec64_to_ns(&utime) + timespec64_to_ns(&stime);
> > + pcpu = div64_u64(cputime * 100, wallclock);
How is this number useful?
> > +
> > + len += scnprintf(msg + len, *msglen - len,
> > + /* task, PID, task state */
> > + "cmd: %s %d [%s] "
> > + /* rtime, utime, stime, %cpu, rss */
> > + "%llu.%02lur %llu.%02luu %llu.%02lus %llu%% %luk\n",
> > + tname, __get_pid(p, tty),
> > + (char *)get_task_state_name(p),
> > + rtime.tv_sec, frac_sec(rtime.tv_nsec),
> > + utime.tv_sec, frac_sec(utime.tv_nsec),
> > + stime.tv_sec, frac_sec(stime.tv_nsec),
> > + pcpu, getRSSk(p->mm));
>
> Why do you think p->mm is still alive (even after the getRSSk()'s check)? So
> no get_task_mm() needed?
>
> > +out:
> > + *msglen = len;
> > + return 0;
> > +}
Re lack of refcounting and locking, perhaps he's attemting a root hole?
On Tue, Jan 18, 2022 at 12:37:03PM +0100, Peter Zijlstra wrote:
> > > +static inline struct task_struct *compare(struct task_struct *new,
> > > + struct task_struct *old)
> > > +{
> > > + unsigned int ostate, nstate;
> > > +
> > > + if (old == NULL)
> > > + return new;
> > > +
> > > + ostate = task_state_index(old);
> > > + nstate = task_state_index(new);
> > > +
> > > + if (ostate == nstate) {
>
> That's not an ordered set, please don't do that.
*sigh*.. sorry about that, I can't read, for some reason I thought you
did: ostate < nstate...
> > > + if (old->start_time > new->start_time)
> > > + return old;
> > > + return new;
> > > + }
> > > +
> > > + if (ostate < nstate)
> > > + return old;
> > > +
> > > + return new;
> > > +}