linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH 3/3] status: Display an informational message when the VSTATUS character is pressed or TIOCSTAT ioctl is called.
       [not found] ` <20220118044323.765038-3-walt@drummond.us>
@ 2022-01-18 10:29   ` Jiri Slaby
  2022-01-18 11:37     ` Peter Zijlstra
  0 siblings, 1 reply; 3+ messages in thread
From: Jiri Slaby @ 2022-01-18 10:29 UTC (permalink / raw)
  To: Walt Drummond, Greg Kroah-Hartman
  Cc: ar, linux-kernel, Oleg Nesterov, mm, Ingo Molnar, Peter Zijlstra

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 <walt@drummond.us>
> ---
>   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


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 3/3] status: Display an informational message when the VSTATUS character is pressed or TIOCSTAT ioctl is called.
  2022-01-18 10:29   ` [PATCH 3/3] status: Display an informational message when the VSTATUS character is pressed or TIOCSTAT ioctl is called Jiri Slaby
@ 2022-01-18 11:37     ` Peter Zijlstra
  2022-01-18 14:29       ` Peter Zijlstra
  0 siblings, 1 reply; 3+ messages in thread
From: Peter Zijlstra @ 2022-01-18 11:37 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Walt Drummond, Greg Kroah-Hartman, ar, linux-kernel,
	Oleg Nesterov, mm, Ingo Molnar

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?



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 3/3] status: Display an informational message when the VSTATUS character is pressed or TIOCSTAT ioctl is called.
  2022-01-18 11:37     ` Peter Zijlstra
@ 2022-01-18 14:29       ` Peter Zijlstra
  0 siblings, 0 replies; 3+ messages in thread
From: Peter Zijlstra @ 2022-01-18 14:29 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Walt Drummond, Greg Kroah-Hartman, ar, linux-kernel,
	Oleg Nesterov, mm, Ingo Molnar

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;
> > > +}


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-01-18 14:29 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20220118044323.765038-1-walt@drummond.us>
     [not found] ` <20220118044323.765038-3-walt@drummond.us>
2022-01-18 10:29   ` [PATCH 3/3] status: Display an informational message when the VSTATUS character is pressed or TIOCSTAT ioctl is called Jiri Slaby
2022-01-18 11:37     ` Peter Zijlstra
2022-01-18 14:29       ` Peter Zijlstra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox