LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] powerpc: Fix xmon ml command to work with 64 bit values.
From: Christophe Leroy @ 2022-02-04  9:48 UTC (permalink / raw)
  To: Rashmica Gupta, linuxppc-dev; +Cc: jwboyer
In-Reply-To: <1448406993-7888-1-git-send-email-rashmicy@gmail.com>



Le 25/11/2015 à 00:16, Rashmica Gupta a écrit :
> The ml command in xmon currently only works for 32-bit values and so fails
> to find 64-bit values on a ppc64 machine. So change to work for 64-bit
> values.
> 
> This is based off a patch by Josh Boyer.
> 
> Signed-off-by: Rashmica Gupta <rashmicy@gmail.com>
> ---
> 
> Based off this patch: http://patchwork.ozlabs.org/patch/90309/
> 
>   arch/powerpc/xmon/xmon.c | 23 +++++++++++++++--------
>   1 file changed, 15 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
> index 786bf01691c9..df05bd2fca07 100644
> --- a/arch/powerpc/xmon/xmon.c
> +++ b/arch/powerpc/xmon/xmon.c
> @@ -184,6 +184,12 @@ extern void xmon_leave(void);
>   #define GETWORD(v)	(((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
>   #endif
>   
> +#if BITS_PER_LONG == 64
> +#define GETLONG(v)	(((unsigned long) GETWORD(v)) << 32 | GETWORD(v+4))
> +#else
> +#define GETLONG(v)	GETWORD(v)
> +#endif
> +

memlocate() is the only place when GETWORD() is used. Shouldn't we just 
replace GETWORD() by GETLONG() instead of doing a GETLONG() with GETWORD() ?

Also, can we use CONFIG_PPC64 instead of BITS_PER_LONG == 64 ?

>   static char *help_string = "\
>   Commands:\n\
>     b	show breakpoints\n\
> @@ -2447,14 +2453,15 @@ memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
>   		printf("Total of %d differences\n", prt);
>   }
>   
> -static unsigned mend;
> -static unsigned mask;
> +static unsigned long mend;
> +static unsigned long mask;
>   
>   static void
>   memlocate(void)
>   {
> -	unsigned a, n;
> -	unsigned char val[4];
> +	unsigned long a, n;
> +	int size = sizeof(unsigned long);
> +	unsigned char val[size];
>   
>   	last_cmd = "ml";
>   	scanhex((void *)&mdest);
> @@ -2470,10 +2477,10 @@ memlocate(void)
>   		}
>   	}
>   	n = 0;
> -	for (a = mdest; a < mend; a += 4) {
> -		if (mread(a, val, 4) == 4
> -			&& ((GETWORD(val) ^ mval) & mask) == 0) {
> -			printf("%.16x:  %.16x\n", a, GETWORD(val));
> +	for (a = mdest; a < mend; a += size) {
> +		if (mread(a, val, size) == size
> +			&& ((GETLONG(val) ^ mval) & mask) == 0){
> +			printf("%.16lx:  %.16lx\n", a, GETLONG(val));
>   			if (++n >= 10)
>   				break;
>   		}

^ permalink raw reply

* Re: [PATCH 1/2] powerpc/signal: Fix handling of SA_RESTORER sigaction flag
From: Michael Ellerman @ 2022-02-04 10:22 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: Tulio Magno Quites Machado Filho, linuxppc-dev, linux-kernel
In-Reply-To: <afe50d1db63a10fde9547ea08fe1fa68b0638aba.1624618157.git.christophe.leroy@csgroup.eu>

Christophe Leroy <christophe.leroy@csgroup.eu> writes:
> powerpc advertises support of SA_RESTORER sigaction flag.
>
> Make it the truth.
>
> Cc: stable@vger.kernel.org
> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
> ---
>  arch/powerpc/kernel/signal_32.c | 8 ++++++--
>  arch/powerpc/kernel/signal_64.c | 4 +++-
>  2 files changed, 9 insertions(+), 3 deletions(-)

Hi Christophe,

I dug into the history a bit on this.

The 32-bit port originally did not define SA_RESTORER in
include/asm-ppc/signal.h, but it was added in 2.1.79.

  https://github.com/mpe/linux-fullhistory/commit/4e7e9c0d54ff5725a73d2210a950f8bc0f225073

That commit added SA_RESTORER to the header, added code to get/set it in
sys_sigaction(), but didn't add any code to use it for signal delivery.


The 64-bit port was merged with SA_RESTORER already defined in
include/asm-ppc64/signal.h:

  https://github.com/mpe/linux-fullhistory/commit/c3aa9878533e724f639852c3d951e6a169e04081
  
Similarly there was code to set/get it in sys_sigaction(), but no code
to use it for signal delivery.


Later the two ports were merged, and the headers were moved and
disintegrated into uapi, so we end up today with SA_RESTORER defined in
arch/powerpc/include/uapi/asm/signal.h, but no code to use it.

So essentially we've had SA_RESTORER defined since ancient kernels, but
never actually supported using it for anything.


One problem with enabling it now is there's no way for userspace to
determine if it's on a fixed kernel or not. That makes it unusable for
userspace, unless it does version checks, or is happy to break on all
old kernels (not likely). We could solve that by defining
SA_RESTORER_FIXED or something, but that's slightly gross.

It's also described in the man page as "Not intended for application
use", ie. it's intended for use by libc. I'm not sure there's any value
in adding support for it to the kernel unless we know there's interest
from glibc/musl in using it.

So my inclination is that we should *not* add support for it, rather we
should leave it unimplemented and remove SA_RESTORER from the header.
There's precedent in riscv for not supporting it at all.

cheers



> diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
> index 0608581967f0..cf3da1386595 100644
> --- a/arch/powerpc/kernel/signal_32.c
> +++ b/arch/powerpc/kernel/signal_32.c
> @@ -769,7 +769,9 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
>  	}
>  
>  	/* Save user registers on the stack */
> -	if (tsk->mm->context.vdso) {
> +	if (ksig->ka.sa.sa_flags & SA_RESTORER) {
> +		tramp = (unsigned long)ksig->ka.sa.sa_restorer;
> +	} else if (tsk->mm->context.vdso) {
>  		tramp = VDSO32_SYMBOL(tsk->mm->context.vdso, sigtramp_rt32);
>  	} else {
>  		tramp = (unsigned long)mctx->mc_pad;
> @@ -865,7 +867,9 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
>  	else
>  		unsafe_save_user_regs(regs, mctx, tm_mctx, 1, failed);
>  
> -	if (tsk->mm->context.vdso) {
> +	if (ksig->ka.sa.sa_flags & SA_RESTORER) {
> +		tramp = (unsigned long)ksig->ka.sa.sa_restorer;
> +	} else if (tsk->mm->context.vdso) {
>  		tramp = VDSO32_SYMBOL(tsk->mm->context.vdso, sigtramp32);
>  	} else {
>  		tramp = (unsigned long)mctx->mc_pad;
> diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
> index 1831bba0582e..fb31a334aca6 100644
> --- a/arch/powerpc/kernel/signal_64.c
> +++ b/arch/powerpc/kernel/signal_64.c
> @@ -910,7 +910,9 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
>  	tsk->thread.fp_state.fpscr = 0;
>  
>  	/* Set up to return from userspace. */
> -	if (tsk->mm->context.vdso) {
> +	if (ksig->ka.sa.sa_flags & SA_RESTORER) {
> +		regs_set_return_ip(regs, (unsigned long)ksig->ka.sa.sa_restorer);
> +	} else if (tsk->mm->context.vdso) {
>  		regs_set_return_ip(regs, VDSO64_SYMBOL(tsk->mm->context.vdso, sigtramp_rt64));
>  	} else {
>  		err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
> -- 
> 2.25.0

^ permalink raw reply

* Re: [PATCH 1/2] powerpc/signal: Fix handling of SA_RESTORER sigaction flag
From: Christophe Leroy @ 2022-02-04 11:00 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: Tulio Magno Quites Machado Filho, linuxppc-dev@lists.ozlabs.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <87a6f7lynn.fsf@mpe.ellerman.id.au>



Le 04/02/2022 à 11:22, Michael Ellerman a écrit :
> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
>> powerpc advertises support of SA_RESTORER sigaction flag.
>>
>> Make it the truth.
>>
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>> ---
>>   arch/powerpc/kernel/signal_32.c | 8 ++++++--
>>   arch/powerpc/kernel/signal_64.c | 4 +++-
>>   2 files changed, 9 insertions(+), 3 deletions(-)
> 
> Hi Christophe,
> 
> I dug into the history a bit on this.
> 
> The 32-bit port originally did not define SA_RESTORER in
> include/asm-ppc/signal.h, but it was added in 2.1.79.
> 
>    https://github.com/mpe/linux-fullhistory/commit/4e7e9c0d54ff5725a73d2210a950f8bc0f225073
> 
> That commit added SA_RESTORER to the header, added code to get/set it in
> sys_sigaction(), but didn't add any code to use it for signal delivery.
> 
> 
> The 64-bit port was merged with SA_RESTORER already defined in
> include/asm-ppc64/signal.h:
> 
>    https://github.com/mpe/linux-fullhistory/commit/c3aa9878533e724f639852c3d951e6a169e04081
>    
> Similarly there was code to set/get it in sys_sigaction(), but no code
> to use it for signal delivery.
> 
> 
> Later the two ports were merged, and the headers were moved and
> disintegrated into uapi, so we end up today with SA_RESTORER defined in
> arch/powerpc/include/uapi/asm/signal.h, but no code to use it.
> 
> So essentially we've had SA_RESTORER defined since ancient kernels, but
> never actually supported using it for anything.
> 
> 
> One problem with enabling it now is there's no way for userspace to
> determine if it's on a fixed kernel or not. That makes it unusable for
> userspace, unless it does version checks, or is happy to break on all
> old kernels (not likely). We could solve that by defining
> SA_RESTORER_FIXED or something, but that's slightly gross.
> 
> It's also described in the man page as "Not intended for application
> use", ie. it's intended for use by libc. I'm not sure there's any value
> in adding support for it to the kernel unless we know there's interest
> from glibc/musl in using it.
> 
> So my inclination is that we should *not* add support for it, rather we
> should leave it unimplemented and remove SA_RESTORER from the header.
> There's precedent in riscv for not supporting it at all.
> 

Nowadays, stacks are mapped noexec, so the fallback stack trampoline 
cannot work anymore. If a process doesn't want exec stack and doesn't 
want to map the VDSO, the SA_RESTORER is the only alternative to get 
signal working.

On several architectures including arm64 and s390 only VDSO and 
SA_RESTORER are supported, on stack signal trampoline is not supported 
anymore.

So my idea was to first implement SA_RESTORER and then as a second step 
to retire the on stack signal trampoline which has become useless with 
noexec stacks.

See 
https://elixir.bootlin.com/linux/v5.17-rc1/source/arch/arm64/kernel/signal.c#L761

or 
https://elixir.bootlin.com/linux/v5.17-rc1/source/arch/s390/kernel/signal.c#L337

Christophe

^ permalink raw reply

* [PATCH] powerpc/mm: Update default hugetlb size early
From: Aneesh Kumar K.V @ 2022-02-04 12:30 UTC (permalink / raw)
  To: linuxppc-dev, mpe; +Cc: linux-mm, Aneesh Kumar K.V

We use the default hugetlb page size to calculate pageblock order.
set_pageblock_order happens early in the boot and we need to make sure
we set the default hugetlb page size before that to compute the right
pageblock_order value.

arch_initcalls get called later in the boot as shown below

[c000000007383b10] [c000000001289328] hugetlbpage_init+0x2b8/0x2f8
[c000000007383bc0] [c0000000012749e4] do_one_initcall+0x14c/0x320
[c000000007383c90] [c00000000127505c] kernel_init_freeable+0x410/0x4e8
[c000000007383da0] [c000000000012664] kernel_init+0x30/0x15c
[c000000007383e10] [c00000000000cf14] ret_from_kernel_thread+0x5c/0x64

and we do the pageblock_order initialization early during the boot.

[c0000000018bfc80] [c0000000012ae120] set_pageblock_order+0x50/0x64
[c0000000018bfca0] [c0000000012b3d94] sparse_init+0x188/0x268
[c0000000018bfd60] [c000000001288bfc] initmem_init+0x28c/0x328
[c0000000018bfe50] [c00000000127b370] setup_arch+0x410/0x480
[c0000000018bfed0] [c00000000127401c] start_kernel+0xb8/0x934
[c0000000018bff90] [c00000000000d984] start_here_common+0x1c/0x98

IIUC we always had this issue. But it was not a problem for hash because
MAX_ORDER - 1  was the same as HUGETLB_PAGE_ORDER (8) in the case of hash (16MB).
With radix, HUGETLB_PAGE_ORDER will be 5 (2M size) and hence we would
want pageblock_order to be 5 instead of 8.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
 arch/powerpc/include/asm/hugetlb.h     | 5 ++++-
 arch/powerpc/mm/book3s64/hugetlbpage.c | 2 +-
 arch/powerpc/mm/hugetlbpage.c          | 5 +----
 arch/powerpc/mm/init_64.c              | 4 ++++
 4 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h
index 962708fa1017..6a1a1ac5743b 100644
--- a/arch/powerpc/include/asm/hugetlb.h
+++ b/arch/powerpc/include/asm/hugetlb.h
@@ -15,7 +15,7 @@
 
 extern bool hugetlb_disabled;
 
-void __init hugetlbpage_init_default(void);
+void __init hugetlbpage_init_defaultsize(void);
 
 int slice_is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
 			   unsigned long len);
@@ -76,6 +76,9 @@ static inline void __init gigantic_hugetlb_cma_reserve(void)
 {
 }
 
+static inline void __init hugetlbpage_init_defaultsize(void)
+{
+}
 #endif /* CONFIG_HUGETLB_PAGE */
 
 #endif /* _ASM_POWERPC_HUGETLB_H */
diff --git a/arch/powerpc/mm/book3s64/hugetlbpage.c b/arch/powerpc/mm/book3s64/hugetlbpage.c
index ea8f83afb0ae..3bc0eb21b2a0 100644
--- a/arch/powerpc/mm/book3s64/hugetlbpage.c
+++ b/arch/powerpc/mm/book3s64/hugetlbpage.c
@@ -150,7 +150,7 @@ void huge_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr
 	set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
 }
 
-void __init hugetlbpage_init_default(void)
+void __init hugetlbpage_init_defaultsize(void)
 {
 	/* Set default large page size. Currently, we pick 16M or 1M
 	 * depending on what is available
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index ddead41e2194..b642a5a8668f 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -664,10 +664,7 @@ static int __init hugetlbpage_init(void)
 		configured = true;
 	}
 
-	if (configured) {
-		if (IS_ENABLED(CONFIG_HUGETLB_PAGE_SIZE_VARIABLE))
-			hugetlbpage_init_default();
-	} else
+	if (!configured)
 		pr_info("Failed to initialize. Disabling HugeTLB");
 
 	return 0;
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 35f46bf54281..83c0ee9fbf05 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -59,6 +59,7 @@
 #include <asm/sections.h>
 #include <asm/iommu.h>
 #include <asm/vdso.h>
+#include <asm/hugetlb.h>
 
 #include <mm/mmu_decl.h>
 
@@ -513,6 +514,9 @@ void __init mmu_early_init_devtree(void)
 	} else
 		hash__early_init_devtree();
 
+	if (IS_ENABLED(CONFIG_HUGETLB_PAGE_SIZE_VARIABLE))
+		hugetlbpage_init_defaultsize();
+
 	if (!(cur_cpu_spec->mmu_features & MMU_FTR_HPTE_TABLE) &&
 	    !(cur_cpu_spec->mmu_features & MMU_FTR_TYPE_RADIX))
 		panic("kernel does not support any MMU type offered by platform");
-- 
2.34.1


^ permalink raw reply related

* [Bug 215567] New: build failure when PPC_64S_HASH_MMU=n is selected in kernel .config
From: bugzilla-daemon @ 2022-02-04 13:00 UTC (permalink / raw)
  To: linuxppc-dev

https://bugzilla.kernel.org/show_bug.cgi?id=215567

            Bug ID: 215567
           Summary: build failure when PPC_64S_HASH_MMU=n is selected in
                    kernel .config
           Product: Platform Specific/Hardware
           Version: 2.5
    Kernel Version: 5.17-rc2
          Hardware: PPC-64
                OS: Linux
              Tree: Mainline
            Status: NEW
          Severity: normal
          Priority: P1
         Component: PPC-64
          Assignee: platform_ppc-64@kernel-bugs.osdl.org
          Reporter: erhard_f@mailbox.org
        Regression: No

Created attachment 300391
  --> https://bugzilla.kernel.org/attachment.cgi?id=300391&action=edit
kernel .config (kernel 5.17-rc2, Talos II)

[...]
  CC      arch/powerpc/kernel/stacktrace.o
  CC      arch/powerpc/kernel/setup_64.o
arch/powerpc/kernel/setup_64.c: In function 'setup_per_cpu_areas':
arch/powerpc/kernel/setup_64.c:811:21: error: 'mmu_linear_psize' undeclared
(first use in this function); did you mean 'mmu_virtual_psize'?
  811 |                 if (mmu_linear_psize == MMU_PAGE_4K)
      |                     ^~~~~~~~~~~~~~~~
      |                     mmu_virtual_psize
arch/powerpc/kernel/setup_64.c:811:21: note: each undeclared identifier is
reported only once for each function it appears in
make[2]: *** [scripts/Makefile.build:288: arch/powerpc/kernel/setup_64.o]
Fehler 1

Got this with PPC_64S_HASH_MMU=n on my Talos II. When PPC_64S_HASH_MMU is
enabled the kernel builds ok.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are watching the assignee of the bug.

^ permalink raw reply

* [Bug 214867] UBSAN: shift-out-of-bounds in drivers/of/unittest.c:1933:36
From: bugzilla-daemon @ 2022-02-04 13:20 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <bug-214867-206035@https.bugzilla.kernel.org/>

https://bugzilla.kernel.org/show_bug.cgi?id=214867

Erhard F. (erhard_f@mailbox.org) changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |CODE_FIX

--- Comment #4 from Erhard F. (erhard_f@mailbox.org) ---
Fix landed in mainline meanwhile. At least I can replicate this no longer on
v5.17-rc2.

Thanks!

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are watching the assignee of the bug.

^ permalink raw reply

* Re: [PATCH v4 4/7] mm: make alloc_contig_range work at pageblock granularity
From: Oscar Salvador @ 2022-02-04 13:56 UTC (permalink / raw)
  To: Zi Yan
  Cc: Mel Gorman, David Hildenbrand, linuxppc-dev, linux-kernel,
	virtualization, linux-mm, iommu, Eric Ren, Robin Murphy,
	Christoph Hellwig, Vlastimil Babka, Marek Szyprowski
In-Reply-To: <20220119190623.1029355-5-zi.yan@sent.com>

On Wed, Jan 19, 2022 at 02:06:20PM -0500, Zi Yan wrote:
> From: Zi Yan <ziy@nvidia.com>
> 
> alloc_contig_range() worked at MAX_ORDER-1 granularity to avoid merging
> pageblocks with different migratetypes. It might unnecessarily convert
> extra pageblocks at the beginning and at the end of the range. Change
> alloc_contig_range() to work at pageblock granularity.
> 
> It is done by restoring pageblock types and split >pageblock_order free
> pages after isolating at MAX_ORDER-1 granularity and migrating pages
> away at pageblock granularity. The reason for this process is that
> during isolation, some pages, either free or in-use, might have >pageblock
> sizes and isolating part of them can cause free accounting issues.
> Restoring the migratetypes of the pageblocks not in the interesting
> range later is much easier.

Hi Zi Yan,

Due to time constraints I only glanced over, so some comments below
about stuff that caught my eye:

> +static inline void split_free_page_into_pageblocks(struct page *free_page,
> +				int order, struct zone *zone)
> +{
> +	unsigned long pfn;
> +
> +	spin_lock(&zone->lock);
> +	del_page_from_free_list(free_page, zone, order);
> +	for (pfn = page_to_pfn(free_page);
> +	     pfn < page_to_pfn(free_page) + (1UL << order);

It migt make sense to have a end_pfn variable so that does not have to
be constantly evaluated. Or maybe the compiler is clever enough to only
evualuate it once.

> +	     pfn += pageblock_nr_pages) {
> +		int mt = get_pfnblock_migratetype(pfn_to_page(pfn), pfn);
> +
> +		__free_one_page(pfn_to_page(pfn), pfn, zone, pageblock_order,
> +				mt, FPI_NONE);
> +	}
> +	spin_unlock(&zone->lock);

It is possible that free_page's order is already pageblock_order, so I
would add a one-liner upfront to catch that case and return, otherwise
we do the delete_from_freelist-and-free_it_again dance.

> +	/* Save the migratepages of the pageblocks before start and after end */
> +	num_pageblock_to_save = (alloc_start - isolate_start) / pageblock_nr_pages
> +				+ (isolate_end - alloc_end) / pageblock_nr_pages;
> +	saved_mt =
> +		kmalloc_array(num_pageblock_to_save,
> +			      sizeof(unsigned char), GFP_KERNEL);
> +	if (!saved_mt)
> +		return -ENOMEM;
> +
> +	num = save_migratetypes(saved_mt, isolate_start, alloc_start);
> +
> +	num = save_migratetypes(&saved_mt[num], alloc_end, isolate_end);

I really hope we can put all this magic within start_isolate_page_range,
and the counterparts in undo_isolate_page_range.

Also, I kinda dislike the &saved_mt thing. I thought about some other
approaches but nothing that wasn't too specific for this case, and I
guess we want that function to be as generic as possible.

> +	/*
> +	 * Split free page spanning [alloc_end, isolate_end) and put the
> +	 * pageblocks in the right migratetype list
> +	 */
> +	for (outer_end = alloc_end; outer_end < isolate_end;) {
> +		unsigned long begin_pfn = outer_end;
> +
> +		order = 0;
> +		while (!PageBuddy(pfn_to_page(outer_end))) {
> +			if (++order >= MAX_ORDER) {
> +				outer_end = begin_pfn;
> +				break;
> +			}
> +			outer_end &= ~0UL << order;
> +		}
> +
> +		if (outer_end != begin_pfn) {
> +			order = buddy_order(pfn_to_page(outer_end));
> +
> +			/*
> +			 * split the free page has start page and put the pageblocks
> +			 * in the right migratetype list
> +			 */
> +			VM_BUG_ON(outer_end + (1UL << order) <= begin_pfn);

How could this possibily happen?

> +			{
> +				struct page *free_page = pfn_to_page(outer_end);
> +
> +				split_free_page_into_pageblocks(free_page, order, cc.zone);
> +			}
> +			outer_end += 1UL << order;
> +		} else
> +			outer_end = begin_pfn + 1;
>  	}

I think there are cases could optimize for. If the page has already been
split in pageblock by the outer_start loop, we could skip this outer_end
logic altogether.

E.g: An order-10 page is split in two pageblocks. There's nothing else
to be done, right? We could skip this. 


-- 
Oscar Salvador
SUSE Labs

^ permalink raw reply

* [Bug 215169] UBSAN: shift-out-of-bounds in arch/powerpc/mm/kasan/book3s_32.c:22:23
From: bugzilla-daemon @ 2022-02-04 14:57 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <bug-215169-206035@https.bugzilla.kernel.org/>

https://bugzilla.kernel.org/show_bug.cgi?id=215169

Erhard F. (erhard_f@mailbox.org) changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |CODE_FIX

--- Comment #2 from Erhard F. (erhard_f@mailbox.org) ---
Fix landed in 5.16.3 and LTS-kernels. Thanks!

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are watching the assignee of the bug.

^ permalink raw reply

* Re: [PATCH v4 4/7] mm: make alloc_contig_range work at pageblock granularity
From: Zi Yan @ 2022-02-04 15:19 UTC (permalink / raw)
  To: Oscar Salvador
  Cc: Mel Gorman, David Hildenbrand, linuxppc-dev, linux-kernel,
	virtualization, linux-mm, iommu, Eric Ren, Robin Murphy,
	Christoph Hellwig, Vlastimil Babka, Marek Szyprowski
In-Reply-To: <Yf0wpFmtckRRzLFg@localhost.localdomain>

[-- Attachment #1: Type: text/plain, Size: 4612 bytes --]

On 4 Feb 2022, at 8:56, Oscar Salvador wrote:

> On Wed, Jan 19, 2022 at 02:06:20PM -0500, Zi Yan wrote:
>> From: Zi Yan <ziy@nvidia.com>
>>
>> alloc_contig_range() worked at MAX_ORDER-1 granularity to avoid merging
>> pageblocks with different migratetypes. It might unnecessarily convert
>> extra pageblocks at the beginning and at the end of the range. Change
>> alloc_contig_range() to work at pageblock granularity.
>>
>> It is done by restoring pageblock types and split >pageblock_order free
>> pages after isolating at MAX_ORDER-1 granularity and migrating pages
>> away at pageblock granularity. The reason for this process is that
>> during isolation, some pages, either free or in-use, might have >pageblock
>> sizes and isolating part of them can cause free accounting issues.
>> Restoring the migratetypes of the pageblocks not in the interesting
>> range later is much easier.
>
> Hi Zi Yan,
>
> Due to time constraints I only glanced over, so some comments below
> about stuff that caught my eye:

Thanks for looking at the patches!

>
>> +static inline void split_free_page_into_pageblocks(struct page *free_page,
>> +				int order, struct zone *zone)
>> +{
>> +	unsigned long pfn;
>> +
>> +	spin_lock(&zone->lock);
>> +	del_page_from_free_list(free_page, zone, order);
>> +	for (pfn = page_to_pfn(free_page);
>> +	     pfn < page_to_pfn(free_page) + (1UL << order);
>
> It migt make sense to have a end_pfn variable so that does not have to
> be constantly evaluated. Or maybe the compiler is clever enough to only
> evualuate it once.

Sure. Will add end_pfn.

>
>> +	     pfn += pageblock_nr_pages) {
>> +		int mt = get_pfnblock_migratetype(pfn_to_page(pfn), pfn);
>> +
>> +		__free_one_page(pfn_to_page(pfn), pfn, zone, pageblock_order,
>> +				mt, FPI_NONE);
>> +	}
>> +	spin_unlock(&zone->lock);
>
> It is possible that free_page's order is already pageblock_order, so I
> would add a one-liner upfront to catch that case and return, otherwise
> we do the delete_from_freelist-and-free_it_again dance.

Make sense. Will do.

>
>> +	/* Save the migratepages of the pageblocks before start and after end */
>> +	num_pageblock_to_save = (alloc_start - isolate_start) / pageblock_nr_pages
>> +				+ (isolate_end - alloc_end) / pageblock_nr_pages;
>> +	saved_mt =
>> +		kmalloc_array(num_pageblock_to_save,
>> +			      sizeof(unsigned char), GFP_KERNEL);
>> +	if (!saved_mt)
>> +		return -ENOMEM;
>> +
>> +	num = save_migratetypes(saved_mt, isolate_start, alloc_start);
>> +
>> +	num = save_migratetypes(&saved_mt[num], alloc_end, isolate_end);
>
> I really hope we can put all this magic within start_isolate_page_range,
> and the counterparts in undo_isolate_page_range.
>

That is my plan too.

> Also, I kinda dislike the &saved_mt thing. I thought about some other
> approaches but nothing that wasn't too specific for this case, and I
> guess we want that function to be as generic as possible.
>
I do not like it either. This whole save and restore thing should go away
once I make MIGRATE_ISOLATE a standalone bit, so that the original
migrateypes will not be overwritten during isolation. Hopefully, I can
work on it soon to get rid of this hunk completely.

>> +	/*
>> +	 * Split free page spanning [alloc_end, isolate_end) and put the
>> +	 * pageblocks in the right migratetype list
>> +	 */
>> +	for (outer_end = alloc_end; outer_end < isolate_end;) {
>> +		unsigned long begin_pfn = outer_end;
>> +
>> +		order = 0;
>> +		while (!PageBuddy(pfn_to_page(outer_end))) {
>> +			if (++order >= MAX_ORDER) {
>> +				outer_end = begin_pfn;
>> +				break;
>> +			}
>> +			outer_end &= ~0UL << order;
>> +		}
>> +
>> +		if (outer_end != begin_pfn) {
>> +			order = buddy_order(pfn_to_page(outer_end));
>> +
>> +			/*
>> +			 * split the free page has start page and put the pageblocks
>> +			 * in the right migratetype list
>> +			 */
>> +			VM_BUG_ON(outer_end + (1UL << order) <= begin_pfn);
>
> How could this possibily happen?

Right. It is not possible. Will remove it.

>
>> +			{
>> +				struct page *free_page = pfn_to_page(outer_end);
>> +
>> +				split_free_page_into_pageblocks(free_page, order, cc.zone);
>> +			}
>> +			outer_end += 1UL << order;
>> +		} else
>> +			outer_end = begin_pfn + 1;
>>  	}
>
> I think there are cases could optimize for. If the page has already been
> split in pageblock by the outer_start loop, we could skip this outer_end
> logic altogether.
>
> E.g: An order-10 page is split in two pageblocks. There's nothing else
> to be done, right? We could skip this.

Yes. I will think about it more and do some optimization.


--
Best Regards,
Yan, Zi

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 854 bytes --]

^ permalink raw reply

* [PATCH v2 0/4] powerpc/pseries/vas: VAS/NXGZIP support with LPM
From: Haren Myneni @ 2022-02-06  2:25 UTC (permalink / raw)
  To: mpe, linuxppc-dev, npiggin, nathanl; +Cc: haren


Virtual Accelerator Switchboard (VAS) is an engine stays on the
chip. So all windows opened on a specific engine belongs to VAS
the chip. The hypervisor expects the partition to close all
active windows on the sources system and reopen them after
migration on the destination machine.

This patch series adds VAS support with the partition migration.
When the migration initiates, the VAS migration handler will be
invoked before pseries_suspend() to close all active windows and
mark them in-active with VAS_WIN_MIGRATE_CLOSE status. Whereas
this migration handler is called after migration to reopen all
windows which has VAS_WIN_MIGRATE_CLOSE status and make them
active again. The user space gets paste instruction failure
when it sends requests on these in-active windows.

These patches depend on VAS/DLPAR support patch series

Changes in v2:
- Added new patch "Define global hv_cop_caps struct" to eliminate
  memory allocation failure during migration (suggestion by
  Nathan Lynch)

Haren Myneni (4):
  powerpc/pseries/vas: Define global hv_cop_caps struct
  powerpc/pseries/vas: Modify reconfig open/close functions for
    migration
  powerpc/pseries/vas: Add VAS migration handler
  powerpc/pseries/vas: Disable window open during migration

 arch/powerpc/include/asm/vas.h            |   2 +
 arch/powerpc/platforms/pseries/mobility.c |   5 +
 arch/powerpc/platforms/pseries/vas.c      | 236 +++++++++++++++++-----
 arch/powerpc/platforms/pseries/vas.h      |   6 +
 4 files changed, 202 insertions(+), 47 deletions(-)

-- 
2.27.0



^ permalink raw reply

* [PATCH v2 1/4] powerpc/pseries/vas: Define global hv_cop_caps struct
From: Haren Myneni @ 2022-02-06  2:27 UTC (permalink / raw)
  To: mpe, linuxppc-dev, npiggin, nathanl
In-Reply-To: <d977832373068e57a13c0e2e47afb2dd4e8d7c3d.camel@linux.ibm.com>


The coprocessor capabilities struct is used to get default and
QoS capabilities from the hypervisor during init, DLPAR event and
migration. So instead of allocating this struct for each event,
define global struct and reuse it, especially eliminate memory
allocation failure during migration.

Also disable copy/paste feature flag if any capabilities HCALL
is failed.

Signed-off-by: Haren Myneni <haren@linux.ibm.com>
---
 arch/powerpc/platforms/pseries/vas.c | 49 ++++++++++++----------------
 1 file changed, 21 insertions(+), 28 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/vas.c b/arch/powerpc/platforms/pseries/vas.c
index 3400f4fc6609..933506b85dc6 100644
--- a/arch/powerpc/platforms/pseries/vas.c
+++ b/arch/powerpc/platforms/pseries/vas.c
@@ -26,6 +26,7 @@
 
 static struct vas_all_caps caps_all;
 static bool copypaste_feat;
+static struct hv_vas_cop_feat_caps hv_cop_caps;
 
 static struct vas_caps vascaps[VAS_MAX_FEAT_TYPE];
 static DEFINE_MUTEX(vas_pseries_mutex);
@@ -724,7 +725,6 @@ static int reconfig_close_windows(struct vas_caps *vcap, int excess_creds)
  */
 int vas_reconfig_capabilties(u8 type)
 {
-	struct hv_vas_cop_feat_caps *hv_caps;
 	struct vas_cop_feat_caps *caps;
 	int lpar_creds, new_creds;
 	struct vas_caps *vcaps;
@@ -738,17 +738,13 @@ int vas_reconfig_capabilties(u8 type)
 	vcaps = &vascaps[type];
 	caps = &vcaps->caps;
 
-	hv_caps = kmalloc(sizeof(*hv_caps), GFP_KERNEL);
-	if (!hv_caps)
-		return -ENOMEM;
-
 	mutex_lock(&vas_pseries_mutex);
 	rc = h_query_vas_capabilities(H_QUERY_VAS_CAPABILITIES, vcaps->feat,
-				      (u64)virt_to_phys(hv_caps));
+				      (u64)virt_to_phys(&hv_cop_caps));
 	if (rc)
 		goto out;
 
-	new_creds = be16_to_cpu(hv_caps->target_lpar_creds);
+	new_creds = be16_to_cpu(hv_cop_caps.target_lpar_creds);
 
 	lpar_creds = atomic_read(&caps->target_creds);
 
@@ -778,7 +774,6 @@ int vas_reconfig_capabilties(u8 type)
 
 out:
 	mutex_unlock(&vas_pseries_mutex);
-	kfree(hv_caps);
 	return rc;
 }
 
@@ -821,9 +816,8 @@ static struct notifier_block pseries_vas_nb = {
 
 static int __init pseries_vas_init(void)
 {
-	struct hv_vas_cop_feat_caps *hv_cop_caps;
 	struct hv_vas_all_caps *hv_caps;
-	int rc;
+	int rc = 0;
 
 	/*
 	 * Linux supports user space COPY/PASTE only with Radix
@@ -849,39 +843,38 @@ static int __init pseries_vas_init(void)
 
 	sysfs_pseries_vas_init(&caps_all);
 
-	hv_cop_caps = kmalloc(sizeof(*hv_cop_caps), GFP_KERNEL);
-	if (!hv_cop_caps) {
-		rc = -ENOMEM;
-		goto out;
-	}
 	/*
 	 * QOS capabilities available
 	 */
 	if (caps_all.feat_type & VAS_GZIP_QOS_FEAT_BIT) {
 		rc = get_vas_capabilities(VAS_GZIP_QOS_FEAT,
-					  VAS_GZIP_QOS_FEAT_TYPE, hv_cop_caps);
+					  VAS_GZIP_QOS_FEAT_TYPE, &hv_cop_caps);
 
 		if (rc)
-			goto out_cop;
+			goto out;
 	}
 	/*
 	 * Default capabilities available
 	 */
-	if (caps_all.feat_type & VAS_GZIP_DEF_FEAT_BIT) {
+	if (caps_all.feat_type & VAS_GZIP_DEF_FEAT_BIT)
 		rc = get_vas_capabilities(VAS_GZIP_DEF_FEAT,
-					  VAS_GZIP_DEF_FEAT_TYPE, hv_cop_caps);
-		if (rc)
-			goto out_cop;
-	}
+					  VAS_GZIP_DEF_FEAT_TYPE, &hv_cop_caps);
 
-	/* Processors can be added/removed only on LPAR */
-	if (copypaste_feat && firmware_has_feature(FW_FEATURE_LPAR))
-		of_reconfig_notifier_register(&pseries_vas_nb);
+	if (!rc && copypaste_feat) {
+		/* Processors can be added/removed only on LPAR */
+		if (firmware_has_feature(FW_FEATURE_LPAR))
+			of_reconfig_notifier_register(&pseries_vas_nb);
 
-	pr_info("GZIP feature is available\n");
+		pr_info("GZIP feature is available\n");
+	} else {
+		/*
+		 * Should not happen, but only when get default
+		 * capabilities HCALL failed. So disable copy paste
+		 * feature.
+		 */
+		copypaste_feat = false;
+	}
 
-out_cop:
-	kfree(hv_cop_caps);
 out:
 	kfree(hv_caps);
 	return rc;
-- 
2.27.0



^ permalink raw reply related

* [PATCH v2 2/4] powerpc/pseries/vas: Modify reconfig open/close functions for migration
From: Haren Myneni @ 2022-02-06  2:28 UTC (permalink / raw)
  To: mpe, linuxppc-dev, npiggin, nathanl
In-Reply-To: <d977832373068e57a13c0e2e47afb2dd4e8d7c3d.camel@linux.ibm.com>


VAS is a hardware engine stays on the chip. So when the partition
migrates, all VAS windows on the source system have to be closed
and reopen them on the destination after migration.

This patch make changes to the current reconfig_open/close_windows
functions to support migration:
- Set VAS_WIN_MIGRATE_CLOSE to the window status when closes and
  reopen windows with the same status during resume.
- Continue to close all windows even if deallocate HCALL failed
  (should not happen) since no way to stop migration with the
  current LPM implementation.
- If the DLPAR CPU event happens while migration is in progress,
  set VAS_WIN_NO_CRED_CLOSE to the window status. Close window
  happens with the first event (migration or DLPAR) and Reopen
  window happens only with the last event (migration or DLPAR).

Signed-off-by: Haren Myneni <haren@linux.ibm.com>
---
 arch/powerpc/include/asm/vas.h       |  2 +
 arch/powerpc/platforms/pseries/vas.c | 88 ++++++++++++++++++++++------
 2 files changed, 73 insertions(+), 17 deletions(-)

diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h
index ddc05a8fc2e3..f21e76f47175 100644
--- a/arch/powerpc/include/asm/vas.h
+++ b/arch/powerpc/include/asm/vas.h
@@ -42,6 +42,8 @@
 /* Linux status bits */
 #define VAS_WIN_NO_CRED_CLOSE	0x00000004 /* Window is closed due to */
 					   /* lost credit */
+#define VAS_WIN_MIGRATE_CLOSE	0x00000008 /* Window is closed due to */
+					   /* migration */
 /*
  * Get/Set bit fields
  */
diff --git a/arch/powerpc/platforms/pseries/vas.c b/arch/powerpc/platforms/pseries/vas.c
index 933506b85dc6..af495b6f64cc 100644
--- a/arch/powerpc/platforms/pseries/vas.c
+++ b/arch/powerpc/platforms/pseries/vas.c
@@ -457,11 +457,12 @@ static int vas_deallocate_window(struct vas_window *vwin)
 	mutex_lock(&vas_pseries_mutex);
 	/*
 	 * VAS window is already closed in the hypervisor when
-	 * lost the credit. So just remove the entry from
-	 * the list, remove task references and free vas_window
+	 * lost the credit or with migration. So just remove the entry
+	 * from the list, remove task references and free vas_window
 	 * struct.
 	 */
-	if (win->vas_win.status & VAS_WIN_NO_CRED_CLOSE) {
+	if (!(win->vas_win.status & VAS_WIN_NO_CRED_CLOSE) &&
+		!(win->vas_win.status & VAS_WIN_MIGRATE_CLOSE)) {
 		rc = deallocate_free_window(win);
 		if (rc) {
 			mutex_unlock(&vas_pseries_mutex);
@@ -578,12 +579,14 @@ static int __init get_vas_capabilities(u8 feat, enum vas_cop_feat_type type,
  * by setting the remapping to new paste address if the window is
  * active.
  */
-static int reconfig_open_windows(struct vas_caps *vcaps, int creds)
+static int reconfig_open_windows(struct vas_caps *vcaps, int creds,
+				 bool migrate)
 {
 	long domain[PLPAR_HCALL9_BUFSIZE] = {VAS_DEFAULT_DOMAIN_ID};
 	struct vas_cop_feat_caps *caps = &vcaps->caps;
 	struct pseries_vas_window *win = NULL, *tmp;
 	int rc, mv_ents = 0;
+	int flag;
 
 	/*
 	 * Nothing to do if there are no closed windows.
@@ -602,8 +605,10 @@ static int reconfig_open_windows(struct vas_caps *vcaps, int creds)
 	 * (dedicated). If 1 core is added, this LPAR can have 20 more
 	 * credits. It means the kernel can reopen 20 windows. So move
 	 * 20 entries in the VAS windows lost and reopen next 20 windows.
+	 * For partition migration, reopen all windows that are closed
+	 * during resume.
 	 */
-	if (vcaps->close_wins > creds)
+	if ((vcaps->close_wins > creds) && !migrate)
 		mv_ents = vcaps->close_wins - creds;
 
 	list_for_each_entry_safe(win, tmp, &vcaps->list, win_list) {
@@ -613,12 +618,35 @@ static int reconfig_open_windows(struct vas_caps *vcaps, int creds)
 		mv_ents--;
 	}
 
+	/*
+	 * Open windows if they are closed only with migration or
+	 * DLPAR (lost credit) before.
+	 */
+	if (migrate)
+		flag = VAS_WIN_MIGRATE_CLOSE;
+	else
+		flag = VAS_WIN_NO_CRED_CLOSE;
+
 	list_for_each_entry_safe_from(win, tmp, &vcaps->list, win_list) {
+		/*
+		 * This window is closed with DLPAR and migration events.
+		 * So reopen the window with the last event.
+		 * The user space is not suspended with the current
+		 * migration notifier. So the user space can issue DLPAR
+		 * CPU hotplug while migration in progress. In this case
+		 * this window will be opened with the last event.
+		 */
+		if ((win->vas_win.status & VAS_WIN_NO_CRED_CLOSE) &&
+			(win->vas_win.status & VAS_WIN_MIGRATE_CLOSE)) {
+			win->vas_win.status &= ~flag;
+			continue;
+		}
+
 		/*
 		 * Nothing to do on this window if it is not closed
-		 * with VAS_WIN_NO_CRED_CLOSE
+		 * with this flag
 		 */
-		if (!(win->vas_win.status & VAS_WIN_NO_CRED_CLOSE))
+		if (!(win->vas_win.status & flag))
 			continue;
 
 		rc = allocate_setup_window(win, (u64 *)&domain[0],
@@ -634,7 +662,7 @@ static int reconfig_open_windows(struct vas_caps *vcaps, int creds)
 		/*
 		 * Set window status to active
 		 */
-		win->vas_win.status &= ~VAS_WIN_NO_CRED_CLOSE;
+		win->vas_win.status &= ~flag;
 		mutex_unlock(&win->vas_win.task_ref.mmap_mutex);
 		win->win_type = caps->win_type;
 		if (!--vcaps->close_wins)
@@ -661,20 +689,32 @@ static int reconfig_open_windows(struct vas_caps *vcaps, int creds)
  * the user space to fall back to SW compression and manage with the
  * existing windows.
  */
-static int reconfig_close_windows(struct vas_caps *vcap, int excess_creds)
+static int reconfig_close_windows(struct vas_caps *vcap, int excess_creds,
+									bool migrate)
 {
 	struct pseries_vas_window *win, *tmp;
 	struct vas_user_win_ref *task_ref;
 	struct vm_area_struct *vma;
-	int rc = 0;
+	int rc = 0, flag;
+
+	if (migrate)
+		flag = VAS_WIN_MIGRATE_CLOSE;
+	else
+		flag = VAS_WIN_NO_CRED_CLOSE;
 
 	list_for_each_entry_safe(win, tmp, &vcap->list, win_list) {
 		/*
 		 * This window is already closed due to lost credit
-		 * before. Go for next window.
+		 * or for migration before. Go for next window.
+		 * For migration, nothing to do since this window
+		 * closed for DLPAR and will be reopened even on
+		 * the destination system with other DLPAR operation.
 		 */
-		if (win->vas_win.status & VAS_WIN_NO_CRED_CLOSE)
+		if ((win->vas_win.status & VAS_WIN_MIGRATE_CLOSE) ||
+			(win->vas_win.status & VAS_WIN_NO_CRED_CLOSE)) {
+			win->vas_win.status |= flag;
 			continue;
+		}
 
 		task_ref = &win->vas_win.task_ref;
 		mutex_lock(&task_ref->mmap_mutex);
@@ -683,7 +723,7 @@ static int reconfig_close_windows(struct vas_caps *vcap, int excess_creds)
 		 * Number of available credits are reduced, So select
 		 * and close windows.
 		 */
-		win->vas_win.status |= VAS_WIN_NO_CRED_CLOSE;
+		win->vas_win.status |= flag;
 
 		mmap_write_lock(task_ref->mm);
 		/*
@@ -706,12 +746,24 @@ static int reconfig_close_windows(struct vas_caps *vcap, int excess_creds)
 		 * later when the process issued with close(FD).
 		 */
 		rc = deallocate_free_window(win);
-		if (rc)
+		/*
+		 * This failure is from the hypervisor.
+		 * No way to stop migration for these failures.
+		 * So ignore error and continue closing other windows.
+		 */
+		if (rc && !migrate)
 			return rc;
 
 		vcap->close_wins++;
 
-		if (!--excess_creds)
+		/*
+		 * For migration, do not depend on lpar_creds in case if
+		 * mismatch with the hypervisor value (should not happen).
+		 * So close all active windows in the list and will be
+		 * reopened windows based on the new lpar_creds on the
+		 * destination system during resume.
+		 */
+		if (!migrate && !--excess_creds)
 			break;
 	}
 
@@ -761,7 +813,8 @@ int vas_reconfig_capabilties(u8 type)
 		 * target, reopen windows if they are closed due to
 		 * the previous DLPAR (core removal).
 		 */
-		rc = reconfig_open_windows(vcaps, new_creds - lpar_creds);
+		rc = reconfig_open_windows(vcaps, new_creds - lpar_creds,
+									false);
 	} else {
 		/*
 		 * # active windows is more than new LPAR available
@@ -769,7 +822,8 @@ int vas_reconfig_capabilties(u8 type)
 		 */
 		active_wins = vcaps->num_wins - vcaps->close_wins;
 		if (active_wins > new_creds)
-			rc = reconfig_close_windows(vcaps, active_wins - new_creds);
+			rc = reconfig_close_windows(vcaps, active_wins - new_creds,
+										false);
 	}
 
 out:
-- 
2.27.0



^ permalink raw reply related

* [PATCH v2 3/4] powerpc/pseries/vas: Add VAS migration handler
From: Haren Myneni @ 2022-02-06  2:28 UTC (permalink / raw)
  To: mpe, linuxppc-dev, npiggin, nathanl
In-Reply-To: <d977832373068e57a13c0e2e47afb2dd4e8d7c3d.camel@linux.ibm.com>


Since the VAS windows belong to the VAS hardware resource, the
hypervisor expects the partition to close them on source partition
and reopen them after the partition migrated on the destination
machine.

This handler is called before pseries_suspend() to close these
windows and again invoked after migration. All active windows
for both default and QoS types will be closed and mark them
in-active and reopened after migration with this handler.
During the migration, the user space receives paste instruction
failure if it issues copy/paste on these in-active windows.

Signed-off-by: Haren Myneni <haren@linux.ibm.com>
---
 arch/powerpc/platforms/pseries/mobility.c |  5 ++
 arch/powerpc/platforms/pseries/vas.c      | 86 +++++++++++++++++++++++
 arch/powerpc/platforms/pseries/vas.h      |  6 ++
 3 files changed, 97 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
index 85033f392c78..70004243e25e 100644
--- a/arch/powerpc/platforms/pseries/mobility.c
+++ b/arch/powerpc/platforms/pseries/mobility.c
@@ -26,6 +26,7 @@
 #include <asm/machdep.h>
 #include <asm/rtas.h>
 #include "pseries.h"
+#include "vas.h"	/* vas_migration_handler() */
 #include "../../kernel/cacheinfo.h"
 
 static struct kobject *mobility_kobj;
@@ -669,12 +670,16 @@ static int pseries_migrate_partition(u64 handle)
 	if (ret)
 		return ret;
 
+	vas_migration_handler(VAS_SUSPEND);
+
 	ret = pseries_suspend(handle);
 	if (ret == 0)
 		post_mobility_fixup();
 	else
 		pseries_cancel_migration(handle, ret);
 
+	vas_migration_handler(VAS_RESUME);
+
 	return ret;
 }
 
diff --git a/arch/powerpc/platforms/pseries/vas.c b/arch/powerpc/platforms/pseries/vas.c
index af495b6f64cc..345d469c3560 100644
--- a/arch/powerpc/platforms/pseries/vas.c
+++ b/arch/powerpc/platforms/pseries/vas.c
@@ -868,6 +868,92 @@ static struct notifier_block pseries_vas_nb = {
 	.notifier_call = pseries_vas_notifier,
 };
 
+/*
+ * For LPM, all windows have to be closed on the source partition
+ * before migration and reopen them on the destination partition
+ * after migration. So closing windows during suspend and
+ * reopen them during resume.
+ */
+int vas_migration_handler(int action)
+{
+	struct vas_cop_feat_caps *caps;
+	int lpar_creds, new_creds = 0;
+	struct vas_caps *vcaps;
+	int i, rc = 0;
+
+	/*
+	 * NX-GZIP is not enabled. Nothing to do for migration.
+	 */
+	if (!copypaste_feat)
+		return rc;
+
+	mutex_lock(&vas_pseries_mutex);
+
+	for (i = 0; i < VAS_MAX_FEAT_TYPE; i++) {
+		vcaps = &vascaps[i];
+		caps = &vcaps->caps;
+		lpar_creds = atomic_read(&caps->target_creds);
+
+		rc = h_query_vas_capabilities(H_QUERY_VAS_CAPABILITIES,
+					      vcaps->feat,
+					      (u64)virt_to_phys(&hv_cop_caps));
+		if (!rc) {
+			new_creds = be16_to_cpu(hv_cop_caps.target_lpar_creds);
+			/*
+			 * Should not happen. But incase print messages, close
+			 * all windows in the list during suspend and reopen
+			 * windows based on new lpar_creds on the destination
+			 * system.
+			 */
+			if (lpar_creds != new_creds) {
+				pr_err("state(%d): lpar creds: %d HV lpar creds: %d\n",
+					action, lpar_creds, new_creds);
+				pr_err("Used creds: %d, Active creds: %d\n",
+					atomic_read(&caps->used_creds),
+					vcaps->num_wins - vcaps->close_wins);
+			}
+		} else {
+			pr_err("state(%d): Get VAS capabilities failed with %d\n",
+				action, rc);
+			/*
+			 * We can not stop migration with the current lpm
+			 * implementation. So continue closing all windows in
+			 * the list (during suspend) and return without
+			 * opening windows (during resume) if VAS capabilities
+			 * HCALL failed.
+			 */
+			if (action == VAS_RESUME)
+				goto out;
+		}
+
+		switch (action) {
+		case VAS_SUSPEND:
+			rc = reconfig_close_windows(vcaps, vcaps->num_wins,
+							true);
+			break;
+		case VAS_RESUME:
+			atomic_set(&caps->target_creds, new_creds);
+			rc = reconfig_open_windows(vcaps, new_creds, true);
+			break;
+		default:
+			/* should not happen */
+			pr_err("Invalid migration action %d\n", action);
+			rc = -EINVAL;
+			goto out;
+		}
+
+		/*
+		 * Ignore errors during suspend and return for resume.
+		 */
+		if (rc && (action == VAS_RESUME))
+			goto out;
+	}
+
+out:
+	mutex_unlock(&vas_pseries_mutex);
+	return rc;
+}
+
 static int __init pseries_vas_init(void)
 {
 	struct hv_vas_all_caps *hv_caps;
diff --git a/arch/powerpc/platforms/pseries/vas.h b/arch/powerpc/platforms/pseries/vas.h
index 4cf1d0ef66a5..36dd140af01b 100644
--- a/arch/powerpc/platforms/pseries/vas.h
+++ b/arch/powerpc/platforms/pseries/vas.h
@@ -27,6 +27,11 @@
 #define VAS_GZIP_QOS_CAPABILITIES	0x56516F73477A6970
 #define VAS_GZIP_DEFAULT_CAPABILITIES	0x56446566477A6970
 
+enum vas_migrate_action {
+	VAS_SUSPEND,
+	VAS_RESUME,
+};
+
 /*
  * Co-processor feature - GZIP QoS windows or GZIP default windows
  */
@@ -127,4 +132,5 @@ struct pseries_vas_window {
 int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps);
 int vas_reconfig_capabilties(u8 type);
 int __init sysfs_pseries_vas_init(struct vas_all_caps *vas_caps);
+int vas_migration_handler(int action);
 #endif /* _VAS_H */
-- 
2.27.0



^ permalink raw reply related

* [PATCH v2 4/4] powerpc/pseries/vas: Disable window open during migration
From: Haren Myneni @ 2022-02-06  2:29 UTC (permalink / raw)
  To: mpe, linuxppc-dev, npiggin, nathanl
In-Reply-To: <d977832373068e57a13c0e2e47afb2dd4e8d7c3d.camel@linux.ibm.com>


The current partition migration implementation does not freeze the
user space and the user space can continue open VAS windows. So
when migration_in_progress flag is enabled, VAS open window
API returns -EBUSY.

Signed-off-by: Haren Myneni <haren@linux.ibm.com>
---
 arch/powerpc/platforms/pseries/vas.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/vas.c b/arch/powerpc/platforms/pseries/vas.c
index 345d469c3560..ffcf18cfb4e3 100644
--- a/arch/powerpc/platforms/pseries/vas.c
+++ b/arch/powerpc/platforms/pseries/vas.c
@@ -30,6 +30,7 @@ static struct hv_vas_cop_feat_caps hv_cop_caps;
 
 static struct vas_caps vascaps[VAS_MAX_FEAT_TYPE];
 static DEFINE_MUTEX(vas_pseries_mutex);
+static bool migration_in_progress;
 
 static long hcall_return_busy_check(long rc)
 {
@@ -356,8 +357,11 @@ static struct vas_window *vas_allocate_window(int vas_id, u64 flags,
 	 * same fault IRQ is not freed by the OS before.
 	 */
 	mutex_lock(&vas_pseries_mutex);
-	rc = allocate_setup_window(txwin, (u64 *)&domain[0],
-				   cop_feat_caps->win_type);
+	if (migration_in_progress)
+		rc = -EBUSY;
+	else
+		rc = allocate_setup_window(txwin, (u64 *)&domain[0],
+					   cop_feat_caps->win_type);
 	mutex_unlock(&vas_pseries_mutex);
 	if (rc)
 		goto out;
@@ -889,6 +893,11 @@ int vas_migration_handler(int action)
 
 	mutex_lock(&vas_pseries_mutex);
 
+	if (action == VAS_SUSPEND)
+		migration_in_progress = true;
+	else
+		migration_in_progress = false;
+
 	for (i = 0; i < VAS_MAX_FEAT_TYPE; i++) {
 		vcaps = &vascaps[i];
 		caps = &vcaps->caps;
-- 
2.27.0



^ permalink raw reply related

* Re: [PATCH v2] i2c: pasemi: Drop I2C classes from platform driver variant
From: Sven Peter @ 2022-02-06 12:46 UTC (permalink / raw)
  To: Martin Povišer
  Cc: Hector Martin, linux-kernel, Paul Mackerras, linux-i2c,
	linuxppc-dev, Alyssa Rosenzweig
In-Reply-To: <20220204095914.5678-1-povik+lin@cutebit.org>

On Fri, Feb 4, 2022, at 10:59, Martin Povišer wrote:
> Drop I2C device-probing classes from platform variant of the PASemi
> controller as it is only used on platforms where I2C devices should
> be instantiated in devicetree. (The I2C_CLASS_DEPRECATED flag is not
> raised as up to this point no devices relied on the old behavior.)
>
> Fixes: d88ae2932df0 ("i2c: pasemi: Add Apple platform driver")
> Signed-off-by: Martin Povišer <povik+lin@cutebit.org>

Reviewed-by: Sven Peter <sven@svenpeter.dev>


^ permalink raw reply

* Re: [PATCH v2] i2c: pasemi: Drop I2C classes from platform driver variant
From: Hector Martin @ 2022-02-06 14:17 UTC (permalink / raw)
  To: Martin Povišer, Sven Peter, Michael Ellerman
  Cc: linux-kernel, Paul Mackerras, linux-i2c, linuxppc-dev,
	Alyssa Rosenzweig
In-Reply-To: <20220204095914.5678-1-povik+lin@cutebit.org>

On 04/02/2022 18.59, Martin Povišer wrote:
> Drop I2C device-probing classes from platform variant of the PASemi
> controller as it is only used on platforms where I2C devices should
> be instantiated in devicetree. (The I2C_CLASS_DEPRECATED flag is not
> raised as up to this point no devices relied on the old behavior.)
> 
> Fixes: d88ae2932df0 ("i2c: pasemi: Add Apple platform driver")
> Signed-off-by: Martin Povišer <povik+lin@cutebit.org>

Acked-by: Hector Martin <marcan@marcan.st>

Heh, so that's where this was... I remember running into this and
wondering if there was a way to turn it off.

-- 
Hector Martin (marcan@marcan.st)
Public Key: https://mrcn.st/pub

^ permalink raw reply

* [PATCH v2 0/3] vstatus: TTY status message request
From: Walt Drummond @ 2022-02-06 15:48 UTC (permalink / raw)
  To: agordeev, arnd, benh, borntraeger, chris, davem, gregkh, hca,
	deller, ink, James.Bottomley, jirislaby, mattst88, jcmvbkbc, mpe,
	paulus, rth, dalias, tsbogend, gor, ysato
  Cc: linux-arch, linux-s390, linux-ia64, linux-parisc, linux-sh,
	linux-xtensa, walt, linux-kernel, linux-mips, linux-alpha,
	sparclinux, ar, linuxppc-dev

This patchset adds TTY status message request feature to the n_tty
line dicipline.  This feature prints a brief message containing basic
system and process group information to a user's TTY in response to a
new control character in the line dicipline (default Ctrl-T) or the
TIOCSTAT ioctl.  The message contains the current system load, the
name and PID of an interesting process in the forground process group,
it's run time, percent CPU usage and RSS.  An example of this message
is:

  load: 0.31  cmd: sleep 3616843 [sleeping] 0.36r 0.00u 0.00s 0% 696k

This feature is in many other Unix systems, both current and
historical.  In other implementations, this feature would also send
SIGINFO to the process group; this implementation does not.

User API visible changes are limited to:
 - The addition of VSTATUS in termios.c_cc[]
 - The addition of NOKERNINFO bit in termios.l_cflags
 - The addition of the TIOCSTAT ioctl number

None of these changes break the existing kernel api as the termios
structure on all architectures has enough space in the control
character array (.c_cc) for the new character.

Walt Drummond (3):
  vstatus: Allow the n_tty line dicipline to write to a user tty
  status: Add user space API definitions for VSTATUS, NOKERNINFO and
    TIOCSTAT
  vstatus: Display an informational message when the VSTATUS character
    is pressed or TIOCSTAT ioctl is called.

 arch/alpha/include/asm/termios.h         |   4 +-
 arch/alpha/include/uapi/asm/ioctls.h     |   1 +
 arch/alpha/include/uapi/asm/termbits.h   |   2 +
 arch/ia64/include/asm/termios.h          |   4 +-
 arch/ia64/include/uapi/asm/termbits.h    |   2 +
 arch/mips/include/asm/termios.h          |   4 +-
 arch/mips/include/uapi/asm/ioctls.h      |   1 +
 arch/mips/include/uapi/asm/termbits.h    |   2 +
 arch/parisc/include/asm/termios.h        |   4 +-
 arch/parisc/include/uapi/asm/ioctls.h    |   1 +
 arch/parisc/include/uapi/asm/termbits.h  |   2 +
 arch/powerpc/include/asm/termios.h       |   4 +-
 arch/powerpc/include/uapi/asm/ioctls.h   |   2 +
 arch/powerpc/include/uapi/asm/termbits.h |   2 +
 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   |   2 +
 arch/xtensa/include/uapi/asm/ioctls.h    |   1 +
 drivers/tty/Makefile                     |   2 +-
 drivers/tty/n_tty.c                      | 103 +++++++++----
 drivers/tty/n_tty_status.c               | 181 +++++++++++++++++++++++
 drivers/tty/tty_io.c                     |   2 +-
 include/asm-generic/termios.h            |   4 +-
 include/linux/tty.h                      |   7 +-
 include/uapi/asm-generic/ioctls.h        |   1 +
 include/uapi/asm-generic/termbits.h      |   2 +
 27 files changed, 301 insertions(+), 45 deletions(-)
 create mode 100644 drivers/tty/n_tty_status.c

-- 
2.30.2


^ permalink raw reply

* [PATCH v2 1/3] vstatus: Allow the n_tty line dicipline to write to a user tty
From: Walt Drummond @ 2022-02-06 15:48 UTC (permalink / raw)
  To: agordeev, arnd, benh, borntraeger, chris, davem, gregkh, hca,
	deller, ink, James.Bottomley, jirislaby, mattst88, jcmvbkbc, mpe,
	paulus, rth, dalias, tsbogend, gor, ysato
  Cc: linux-arch, linux-s390, linux-ia64, linux-parisc, linux-sh,
	linux-xtensa, walt, linux-kernel, linux-mips, linux-alpha,
	sparclinux, ar, linuxppc-dev
In-Reply-To: <20220206154856.2355838-1-walt@drummond.us>

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 <walt@drummond.us>
---
 drivers/tty/n_tty.c | 69 +++++++++++++++++++++++++++------------------
 include/linux/tty.h |  2 +-
 2 files changed, 42 insertions(+), 29 deletions(-)

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 0ec93f1a61f5..64a058a4c63b 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -2231,45 +2231,24 @@ 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,
-			   const unsigned char *buf, size_t nr)
+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;
 	DEFINE_WAIT_FUNC(wait, woken_wake_function);
 	int c;
 	ssize_t retval = 0;
 
+	lockdep_assert_held_read(&tty->termios_rwsem);
+
 	/* 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) {
+	if (L_TOSTOP(tty) &&
+	    !(file && file->f_op->write_iter != redirected_tty_write)) {
 		retval = tty_check_change(tty);
 		if (retval)
 			return retval;
 	}
 
-	down_read(&tty->termios_rwsem);
-
 	/* Write out any echoed characters that are still pending */
 	process_echoes(tty);
 
@@ -2336,10 +2315,44 @@ 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;
+
+	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
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 168e57e40bbb..cbe5d535a69d 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -237,7 +237,7 @@ struct tty_file_private {
 
 static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file)
 {
-	return file->f_flags & O_NONBLOCK ||
+	return (file && file->f_flags & O_NONBLOCK) ||
 		test_bit(TTY_LDISC_CHANGING, &tty->flags);
 }
 
-- 
2.30.2


^ permalink raw reply related

* [PATCH v2 2/3] status: Add user space API definitions for VSTATUS, NOKERNINFO and TIOCSTAT
From: Walt Drummond @ 2022-02-06 15:48 UTC (permalink / raw)
  To: agordeev, arnd, benh, borntraeger, chris, davem, gregkh, hca,
	deller, ink, James.Bottomley, jirislaby, mattst88, jcmvbkbc, mpe,
	paulus, rth, dalias, tsbogend, gor, ysato
  Cc: linux-arch, linux-s390, linux-ia64, linux-parisc, linux-sh,
	linux-xtensa, walt, linux-kernel, linux-mips, linux-alpha,
	sparclinux, ar, linuxppc-dev
In-Reply-To: <20220206154856.2355838-1-walt@drummond.us>

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 <walt@drummond.us>
---
 arch/alpha/include/asm/termios.h         | 4 ++--
 arch/alpha/include/uapi/asm/ioctls.h     | 1 +
 arch/alpha/include/uapi/asm/termbits.h   | 2 ++
 arch/ia64/include/asm/termios.h          | 4 ++--
 arch/ia64/include/uapi/asm/termbits.h    | 2 ++
 arch/mips/include/asm/termios.h          | 4 ++--
 arch/mips/include/uapi/asm/ioctls.h      | 1 +
 arch/mips/include/uapi/asm/termbits.h    | 2 ++
 arch/parisc/include/asm/termios.h        | 4 ++--
 arch/parisc/include/uapi/asm/ioctls.h    | 1 +
 arch/parisc/include/uapi/asm/termbits.h  | 2 ++
 arch/powerpc/include/asm/termios.h       | 4 ++--
 arch/powerpc/include/uapi/asm/ioctls.h   | 2 ++
 arch/powerpc/include/uapi/asm/termbits.h | 2 ++
 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   | 2 ++
 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      | 2 ++
 22 files changed, 37 insertions(+), 14 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..70fdeab2b5f2 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	_IO('T', 0x5E)	/* 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..9a1b9aa92d29 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
@@ -203,6 +204,7 @@ struct ktermios {
 #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..0b5fea00343b 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
@@ -189,6 +190,7 @@ struct ktermios {
 #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..f9ec28ac38db 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	_IO('T', 0x93) /* 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..a10be13a6f7b 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.  */
@@ -205,6 +206,7 @@ struct ktermios {
 #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..1ac156dd8209 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	_IO('T', 0x5E)	/* 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..b449d8ea1c00 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 */
@@ -182,6 +183,7 @@ struct ktermios {
 #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..0a0755863500 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	_IO('T', 0x5E)	/* 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..50d787d95c91 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
@@ -191,6 +192,7 @@ struct ktermios {
 #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..fefef10922ec 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	_IO('T', 0x5F)	/* 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..9819090bd850 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	_IO('T', 0x5E) /* 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..b8441ce42278 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
@@ -224,6 +225,7 @@ struct ktermios {
 #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..f92fb8e5b2a5 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	_IO('T', 0x5E)	/* 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..02ceb990ce9b 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        _IO('T', 0x5E)	/* 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..6219803d6f4d 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
@@ -180,6 +181,7 @@ struct ktermios {
 #define PENDIN	0040000
 #define IEXTEN	0100000
 #define EXTPROC	0200000
+#define NOKERNINFO 0400000
 
 /* tcflow() and TCXONC use these */
 #define	TCOOFF		0
-- 
2.30.2


^ permalink raw reply related

* [PATCH v2 3/3] vstatus: Display an informational message when the VSTATUS character is pressed or TIOCSTAT ioctl is called.
From: Walt Drummond @ 2022-02-06 15:48 UTC (permalink / raw)
  To: agordeev, arnd, benh, borntraeger, chris, davem, gregkh, hca,
	deller, ink, James.Bottomley, jirislaby, mattst88, jcmvbkbc, mpe,
	paulus, rth, dalias, tsbogend, gor, ysato
  Cc: linux-arch, linux-s390, linux-ia64, linux-parisc, linux-sh,
	linux-xtensa, walt, linux-kernel, linux-mips, linux-alpha,
	sparclinux, ar, linuxppc-dev
In-Reply-To: <20220206154856.2355838-1-walt@drummond.us>

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, the local flags ICANON and IEXTEN are enabled and NOKERNINFO is
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        |  34 +++++++
 drivers/tty/n_tty_status.c | 181 +++++++++++++++++++++++++++++++++++++
 drivers/tty/tty_io.c       |   2 +-
 include/linux/tty.h        |   5 +
 5 files changed, 222 insertions(+), 2 deletions(-)
 create mode 100644 drivers/tty/n_tty_status.c

diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index a2bd75fbaaa4..3539d7ab77e5 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 64a058a4c63b..fd70efc333d7 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 void 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) && L_IEXTEN(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);
@@ -2413,6 +2422,26 @@ static unsigned long inq_canon(struct n_tty_data *ldata)
 	return nr;
 }
 
+static void n_tty_status(struct tty_struct *tty)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+	char *msg;
+	size_t len;
+
+	msg = kzalloc(STATUS_LINE_LEN, GFP_KERNEL);
+
+	if (ldata->column != 0) {
+		*msg = '\n';
+		len = n_tty_get_status(tty, msg + 1, STATUS_LINE_LEN - 1);
+	} else {
+		len = n_tty_get_status(tty, msg, STATUS_LINE_LEN);
+	}
+
+	do_n_tty_write(tty, NULL, msg, len);
+
+	kfree(msg);
+}
+
 static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
@@ -2430,6 +2459,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);
+		n_tty_status(tty);
+		up_read(&tty->termios_rwsem);
+		return 0;
 	default:
 		return n_tty_ioctl_helper(tty, file, cmd, arg);
 	}
diff --git a/drivers/tty/n_tty_status.c b/drivers/tty/n_tty_status.c
new file mode 100644
index 000000000000..f0e053651368
--- /dev/null
+++ b/drivers/tty/n_tty_status.c
@@ -0,0 +1,181 @@
+// 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>
+#include <linux/sched/mm.h>
+
+/* Convert nanoseconds into centiseconds */
+static inline long ns_to_cs(long l)
+{
+	return l / (NSEC_PER_MSEC * 10);
+
+}
+
+/* We want the pid from the context of session */
+static inline pid_t __get_pid(struct task_struct *tsk, struct tty_struct *tty)
+{
+	struct pid_namespace *ns;
+
+	spin_lock_irq(&tty->ctrl.lock);
+	ns = ns_of_pid(tty->ctrl.session);
+	spin_unlock_irq(&tty->ctrl.lock);
+
+	return __task_pid_nr_ns(tsk, PIDTYPE_PID, ns);
+}
+
+/* This is the same odd "bitmap" described in
+ * fs/proc/array.c:get_task_state().  Consistency with standard
+ * implementations of VSTATUS requires a different set of state
+ * names.
+ */
+static const char * const task_state_name_array[] = {
+	"running",
+	"sleeping",
+	"disk sleep",
+	"stopped",
+	"tracing stop",
+	"dead",
+	"zombie",
+	"parked",
+	"idle",
+};
+
+static inline const char *get_task_state_name(struct task_struct *tsk)
+{
+	BUILD_BUG_ON(1 + ilog2(TASK_REPORT_MAX) != ARRAY_SIZE(task_state_name_array));
+	return task_state_name_array[task_state_index(tsk)];
+}
+
+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 tty_struct *tty)
+{
+	struct task_struct *new, *winner = NULL;
+
+	read_lock(&tasklist_lock);
+	spin_lock_irq(&tty->ctrl.lock);
+
+	do_each_pid_task(tty->ctrl.pgrp, PIDTYPE_PGID, new) {
+		winner = compare(new, winner);
+	} while_each_pid_task(tty->ctrl.pgrp, PIDTYPE_PGID, new);
+
+	spin_unlock_irq(&tty->ctrl.lock);
+
+	if (winner)
+		winner = get_task_struct(winner);
+
+	read_unlock(&tasklist_lock);
+
+	return winner;
+}
+
+size_t n_tty_get_status(struct tty_struct *tty, char *msg, size_t msglen)
+{
+	struct task_struct *p;
+	struct mm_struct *mm;
+	struct rusage rusage;
+	unsigned long loadavg[3];
+	uint64_t pcpu, cputime, wallclock;
+	struct timespec64 utime, stime, rtime;
+	char tname[TASK_COMM_LEN];
+	unsigned int pid;
+	char *state;
+	unsigned long rss = 0;
+	size_t len = 0;
+
+	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;
+	}
+
+	/* Note that if p is refcounted */
+	p = pick_process(tty);
+	if (p == NULL) {
+		len += scnprintf(msg + len, msglen - len,
+				 "empty foreground process group\n");
+		goto out;
+	}
+
+	mm = get_task_mm(p);
+	if (mm) {
+		rss = get_mm_rss(mm) * PAGE_SIZE / 1024;
+		mmput(mm);
+	}
+	get_task_comm(tname, p);
+	getrusage(p, RUSAGE_BOTH, &rusage);
+	pid = __get_pid(p, tty);
+	state = (char *) get_task_state_name(p);
+	wallclock = ktime_get_ns() - p->start_time;
+	put_task_struct(p);
+
+	/* After this point, any of the information we have on p might
+	 * become stale.  It's OK if the status message is a little bit
+	 * lossy.
+	 */
+
+	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,	pid, state,
+			 rtime.tv_sec, ns_to_cs(rtime.tv_nsec),
+			 utime.tv_sec, ns_to_cs(utime.tv_nsec),
+			 stime.tv_sec, ns_to_cs(stime.tv_nsec),
+			 pcpu, rss);
+
+out:
+	return len;
+}
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 cbe5d535a69d..2e483708608c 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -49,6 +49,7 @@
 #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))
@@ -114,6 +115,7 @@
 #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;
@@ -389,6 +391,9 @@ extern void __init n_tty_init(void);
 static inline void n_tty_init(void) { }
 #endif
 
+/* n_tty_status.c */
+size_t n_tty_get_status(struct tty_struct *tty, char *msg, size_t msglen);
+
 /* tty_audit.c */
 #ifdef CONFIG_AUDIT
 extern void tty_audit_exit(void);
-- 
2.30.2


^ permalink raw reply related

* Re: [PATCH v2 2/3] status: Add user space API definitions for VSTATUS, NOKERNINFO and TIOCSTAT
From: Greg KH @ 2022-02-06 17:09 UTC (permalink / raw)
  To: Walt Drummond
  Cc: dalias, linux-ia64, linux-sh, linux-mips, James.Bottomley,
	jcmvbkbc, paulus, sparclinux, agordeev, ar, jirislaby, linux-arch,
	linux-s390, arnd, deller, ysato, borntraeger, mattst88,
	linux-xtensa, gor, hca, ink, rth, chris, tsbogend, linux-parisc,
	linux-kernel, linux-alpha, linuxppc-dev, davem
In-Reply-To: <20220206154856.2355838-3-walt@drummond.us>

On Sun, Feb 06, 2022 at 07:48:53AM -0800, Walt Drummond wrote:
> 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 <walt@drummond.us>
> ---
>  arch/alpha/include/asm/termios.h         | 4 ++--
>  arch/alpha/include/uapi/asm/ioctls.h     | 1 +
>  arch/alpha/include/uapi/asm/termbits.h   | 2 ++
>  arch/ia64/include/asm/termios.h          | 4 ++--
>  arch/ia64/include/uapi/asm/termbits.h    | 2 ++
>  arch/mips/include/asm/termios.h          | 4 ++--
>  arch/mips/include/uapi/asm/ioctls.h      | 1 +
>  arch/mips/include/uapi/asm/termbits.h    | 2 ++
>  arch/parisc/include/asm/termios.h        | 4 ++--
>  arch/parisc/include/uapi/asm/ioctls.h    | 1 +
>  arch/parisc/include/uapi/asm/termbits.h  | 2 ++
>  arch/powerpc/include/asm/termios.h       | 4 ++--
>  arch/powerpc/include/uapi/asm/ioctls.h   | 2 ++
>  arch/powerpc/include/uapi/asm/termbits.h | 2 ++
>  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   | 2 ++
>  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      | 2 ++
>  22 files changed, 37 insertions(+), 14 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..70fdeab2b5f2 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	_IO('T', 0x5E)	/* 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..9a1b9aa92d29 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
> @@ -203,6 +204,7 @@ struct ktermios {
>  #define PENDIN	0x20000000
>  #define IEXTEN	0x00000400
>  #define EXTPROC	0x10000000
> +#define NOKERNINFO 0x40000000

Here, and elsewhere, you seem to mix tabs and spaces.  Please use what
is in the original file (tabs here.)

>  /* 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

Same here.  And for the other files in this patch.  Let's keep them
unified please.

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH v2 3/3] vstatus: Display an informational message when the VSTATUS character is pressed or TIOCSTAT ioctl is called.
From: Greg KH @ 2022-02-06 17:16 UTC (permalink / raw)
  To: Walt Drummond
  Cc: dalias, linux-ia64, linux-sh, linux-mips, James.Bottomley,
	jcmvbkbc, paulus, sparclinux, agordeev, ar, jirislaby, linux-arch,
	linux-s390, arnd, deller, ysato, borntraeger, mattst88,
	linux-xtensa, gor, hca, ink, rth, chris, tsbogend, linux-parisc,
	linux-kernel, linux-alpha, linuxppc-dev, davem
In-Reply-To: <20220206154856.2355838-4-walt@drummond.us>

On Sun, Feb 06, 2022 at 07:48:54AM -0800, 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

This should be documented somewhere, and not buried in a changelog text
like this.  Can you also add this information somewhere in the
Documentation/ directory so that people have a hint as to what is going
on here?

> The message is only displayed when the tty has the VSTATUS character
> set, the local flags ICANON and IEXTEN are enabled and NOKERNINFO is
> 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        |  34 +++++++
>  drivers/tty/n_tty_status.c | 181 +++++++++++++++++++++++++++++++++++++
>  drivers/tty/tty_io.c       |   2 +-
>  include/linux/tty.h        |   5 +
>  5 files changed, 222 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/tty/n_tty_status.c

Also, any chance for a test to be added so that we can ensure that this
doesn't change over time in ways that confuse/break people?

Is this now a new user/kernel api format that we must preserve for
forever?  Can we add/remove items over time that make sense or are
programs (not just people), going to parse this?

> 
> diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
> index a2bd75fbaaa4..3539d7ab77e5 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 64a058a4c63b..fd70efc333d7 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 */

Tabs please.


>  
>  #undef N_TTY_TRACE
>  #ifdef N_TTY_TRACE
> @@ -127,6 +128,8 @@ struct n_tty_data {
>  	struct mutex output_lock;
>  };
>  
> +static void 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) && L_IEXTEN(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);
> @@ -2413,6 +2422,26 @@ static unsigned long inq_canon(struct n_tty_data *ldata)
>  	return nr;
>  }
>  
> +static void n_tty_status(struct tty_struct *tty)
> +{
> +	struct n_tty_data *ldata = tty->disc_data;
> +	char *msg;
> +	size_t len;
> +
> +	msg = kzalloc(STATUS_LINE_LEN, GFP_KERNEL);

Please check for memory failures.

> +
> +	if (ldata->column != 0) {
> +		*msg = '\n';
> +		len = n_tty_get_status(tty, msg + 1, STATUS_LINE_LEN - 1);
> +	} else {
> +		len = n_tty_get_status(tty, msg, STATUS_LINE_LEN);
> +	}
> +
> +	do_n_tty_write(tty, NULL, msg, len);
> +
> +	kfree(msg);
> +}
> +
>  static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
>  		       unsigned int cmd, unsigned long arg)
>  {
> @@ -2430,6 +2459,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);
> +		n_tty_status(tty);
> +		up_read(&tty->termios_rwsem);
> +		return 0;
>  	default:
>  		return n_tty_ioctl_helper(tty, file, cmd, arg);
>  	}
> diff --git a/drivers/tty/n_tty_status.c b/drivers/tty/n_tty_status.c
> new file mode 100644
> index 000000000000..f0e053651368
> --- /dev/null
> +++ b/drivers/tty/n_tty_status.c
> @@ -0,0 +1,181 @@
> +// SPDX-License-Identifier: GPL-1.0+

We can not take GPL-1.0 code into the kernel anymore, sorry.  Please
consider using a sane license :)


> +/*
> + * 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>
> +#include <linux/sched/mm.h>
> +
> +/* Convert nanoseconds into centiseconds */
> +static inline long ns_to_cs(long l)
> +{
> +	return l / (NSEC_PER_MSEC * 10);
> +
> +}

Unneded blank line.


> +
> +/* We want the pid from the context of session */
> +static inline pid_t __get_pid(struct task_struct *tsk, struct tty_struct *tty)
> +{
> +	struct pid_namespace *ns;
> +
> +	spin_lock_irq(&tty->ctrl.lock);
> +	ns = ns_of_pid(tty->ctrl.session);
> +	spin_unlock_irq(&tty->ctrl.lock);
> +
> +	return __task_pid_nr_ns(tsk, PIDTYPE_PID, ns);
> +}
> +
> +/* This is the same odd "bitmap" described in
> + * fs/proc/array.c:get_task_state().  Consistency with standard
> + * implementations of VSTATUS requires a different set of state
> + * names.
> + */
> +static const char * const task_state_name_array[] = {
> +	"running",
> +	"sleeping",
> +	"disk sleep",
> +	"stopped",
> +	"tracing stop",
> +	"dead",
> +	"zombie",
> +	"parked",
> +	"idle",
> +};

How often is this going to get out-of-sync?  Should we use a real
enumerated type here?  Put the string somewhere else to keep this only
in one place?


> +
> +static inline const char *get_task_state_name(struct task_struct *tsk)
> +{
> +	BUILD_BUG_ON(1 + ilog2(TASK_REPORT_MAX) != ARRAY_SIZE(task_state_name_array));

What is this protecting from?  What is going to change that requires
this to be increased?

> +	return task_state_name_array[task_state_index(tsk)];
> +}
> +
> +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 tty_struct *tty)
> +{
> +	struct task_struct *new, *winner = NULL;
> +
> +	read_lock(&tasklist_lock);
> +	spin_lock_irq(&tty->ctrl.lock);
> +
> +	do_each_pid_task(tty->ctrl.pgrp, PIDTYPE_PGID, new) {
> +		winner = compare(new, winner);
> +	} while_each_pid_task(tty->ctrl.pgrp, PIDTYPE_PGID, new);
> +
> +	spin_unlock_irq(&tty->ctrl.lock);
> +
> +	if (winner)
> +		winner = get_task_struct(winner);
> +
> +	read_unlock(&tasklist_lock);
> +
> +	return winner;
> +}


What are these two functions trying to do?  A comment would be nice to
give us a hint as I am guessing I am going to have to maintain this for
forever :)

> +
> +size_t n_tty_get_status(struct tty_struct *tty, char *msg, size_t msglen)
> +{
> +	struct task_struct *p;
> +	struct mm_struct *mm;
> +	struct rusage rusage;
> +	unsigned long loadavg[3];
> +	uint64_t pcpu, cputime, wallclock;
> +	struct timespec64 utime, stime, rtime;
> +	char tname[TASK_COMM_LEN];
> +	unsigned int pid;
> +	char *state;
> +	unsigned long rss = 0;
> +	size_t len = 0;
> +
> +	get_avenrun(loadavg, FIXED_1/200, 0);

Why 200?

> +	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;
> +	}
> +
> +	/* Note that if p is refcounted */
> +	p = pick_process(tty);
> +	if (p == NULL) {
> +		len += scnprintf(msg + len, msglen - len,
> +				 "empty foreground process group\n");
> +		goto out;
> +	}
> +
> +	mm = get_task_mm(p);
> +	if (mm) {
> +		rss = get_mm_rss(mm) * PAGE_SIZE / 1024;
> +		mmput(mm);
> +	}
> +	get_task_comm(tname, p);
> +	getrusage(p, RUSAGE_BOTH, &rusage);
> +	pid = __get_pid(p, tty);
> +	state = (char *) get_task_state_name(p);
> +	wallclock = ktime_get_ns() - p->start_time;
> +	put_task_struct(p);
> +
> +	/* After this point, any of the information we have on p might
> +	 * become stale.  It's OK if the status message is a little bit
> +	 * lossy.
> +	 */
> +
> +	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,	pid, state,
> +			 rtime.tv_sec, ns_to_cs(rtime.tv_nsec),
> +			 utime.tv_sec, ns_to_cs(utime.tv_nsec),
> +			 stime.tv_sec, ns_to_cs(stime.tv_nsec),
> +			 pcpu, rss);
> +
> +out:
> +	return len;
> +}
> 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 cbe5d535a69d..2e483708608c 100644
> --- a/include/linux/tty.h
> +++ b/include/linux/tty.h
> @@ -49,6 +49,7 @@
>  #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))
> @@ -114,6 +115,7 @@
>  #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;
> @@ -389,6 +391,9 @@ extern void __init n_tty_init(void);
>  static inline void n_tty_init(void) { }
>  #endif
>  
> +/* n_tty_status.c */
> +size_t n_tty_get_status(struct tty_struct *tty, char *msg, size_t msglen);

No need for this to be in include/linux/tty.h, put it in the .h file in
drivers/tty/ please.

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH] Styleguide fix: Removed un-needed whitespaces and formatting errors in drivers/tty
From: Greg KH @ 2022-02-06 19:23 UTC (permalink / raw)
  To: Ankit Kumar Pandey; +Cc: linuxppc-dev, jirislaby, linux-kernel, laurentiu.tudor
In-Reply-To: <YgAWN0ytumzY/n8W@ankit-vm>

On Mon, Feb 07, 2022 at 12:33:07AM +0530, Ankit Kumar Pandey wrote:
> There were lot of styleguide errors raised by checkpatch.pl against
> drivers/tty/* which I have fixed. There is zero code change apart from
> changes related to styleguide. checkpatch.pl returns 0 error for
> style guide now.
> 
> ---
>  drivers/tty/amiserial.c    | 285 ++++++++++++++++++-------------------
>  drivers/tty/ehv_bytechan.c |   5 +-
>  drivers/tty/goldfish.c     |   2 +
>  3 files changed, 142 insertions(+), 150 deletions(-)
> 
> diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
> index 1e60dbef6..15917254e 100644
> --- a/drivers/tty/amiserial.c
> +++ b/drivers/tty/amiserial.c
> @@ -12,13 +12,13 @@
>   * (non hardware specific) changes to serial.c.
>   *
>   * The port is registered with the tty driver as minor device 64, and
> - * therefore other ports should should only use 65 upwards.
> + * therefore other ports should only use 65 upwards.
>   *
>   * Richard Lucock 28/12/99
>   *
>   *  Copyright (C) 1991, 1992  Linus Torvalds
> - *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 
> - * 		1998, 1999  Theodore Ts'o
> + *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
> + *		1998, 1999  Theodore Ts'o
>   *
>   */
>  
> @@ -78,8 +78,8 @@ struct serial_state {
>  	int			ignore_status_mask;
>  	int			timeout;
>  	int			quot;
> -	int			IER; 	/* Interrupt Enable Register */
> -	int			MCR; 	/* Modem control register */
> +	int			IER;	/* Interrupt Enable Register */
> +	int			MCR;	/* Modem control register */
>  	int			x_char;	/* xon/xoff character */
>  };
>  
> @@ -116,9 +116,9 @@ static struct serial_state serial_state;
>  #define SER_CTS     (1<<4)
>  #define SER_DSR     (1<<3)
>  
> -static __inline__ void rtsdtr_ctrl(int bits)
> +static inline void rtsdtr_ctrl(int bits)
>  {
> -    ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR));
> +	ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR));
>  }
>  
>  /*
> @@ -175,7 +175,7 @@ static void rs_start(struct tty_struct *tty)
>  
>  static void receive_chars(struct serial_state *info)
>  {
> -        int status;
> +	int status;
>  	int serdatr;
>  	unsigned char ch, flag;
>  	struct	async_icount *icount;
> @@ -189,10 +189,10 @@ static void receive_chars(struct serial_state *info)
>  	amiga_custom.intreq = IF_RBF;
>  	mb();
>  
> -	if((serdatr & 0x1ff) == 0)
> -	    status |= UART_LSR_BI;
> -	if(serdatr & SDR_OVRUN)
> -	    status |= UART_LSR_OE;
> +	if ((serdatr & 0x1ff) == 0)
> +		status |= UART_LSR_BI;
> +	if (serdatr & SDR_OVRUN)
> +		status |= UART_LSR_OE;
>  
>  	ch = serdatr & 0xff;
>  	icount->rx++;
> @@ -213,45 +213,44 @@ static void receive_chars(struct serial_state *info)
>  	  /*
>  	   * For statistics only
>  	   */
> -	  if (status & UART_LSR_BI) {
> -	    status &= ~(UART_LSR_FE | UART_LSR_PE);
> -	    icount->brk++;
> -	  } else if (status & UART_LSR_PE)
> -	    icount->parity++;
> -	  else if (status & UART_LSR_FE)
> -	    icount->frame++;
> -	  if (status & UART_LSR_OE)
> -	    icount->overrun++;
> +		if (status & UART_LSR_BI) {
> +			status &= ~(UART_LSR_FE | UART_LSR_PE);
> +			icount->brk++;
> +		} else if (status & UART_LSR_PE)
> +			icount->parity++;
> +		else if (status & UART_LSR_FE)
> +			icount->frame++;
> +		if (status & UART_LSR_OE)
> +			icount->overrun++;
>  
>  	  /*
>  	   * Now check to see if character should be
>  	   * ignored, and mask off conditions which
>  	   * should be ignored.
>  	   */
> -	  if (status & info->ignore_status_mask)
> -	    goto out;
> +		if (status & info->ignore_status_mask)
> +			goto out;
>  
> -	  status &= info->read_status_mask;
> -
> -	  if (status & (UART_LSR_BI)) {
> +		status &= info->read_status_mask;
> +		if (status & (UART_LSR_BI)) {
>  #ifdef SERIAL_DEBUG_INTR
> -	    printk("handling break....");
> +			printk("handling break....");
>  #endif
> -	    flag = TTY_BREAK;
> -	    if (info->tport.flags & ASYNC_SAK)
> -	      do_SAK(info->tport.tty);
> -	  } else if (status & UART_LSR_PE)
> -	    flag = TTY_PARITY;
> -	  else if (status & UART_LSR_FE)
> -	    flag = TTY_FRAME;
> -	  if (status & UART_LSR_OE) {
> -	    /*
> -	     * Overrun is special, since it's
> -	     * reported immediately, and doesn't
> -	     * affect the current character
> -	     */
> -	     oe = 1;
> -	  }
> +			flag = TTY_BREAK;
> +			if (info->tport.flags & ASYNC_SAK)
> +				do_SAK(info->tport.tty);
> +		} else if (status & UART_LSR_PE)
> +			flag = TTY_PARITY;
> +		else if (status & UART_LSR_FE)
> +			flag = TTY_FRAME;
> +		if (status & UART_LSR_OE) {
> +			/*
> +			 * Overrun is special, since it's
> +			 * reported immediately, and doesn't
> +			 * affect the current character
> +			 */
> +			oe = 1;
> +		}
>  	}
>  	tty_insert_flip_char(&info->tport, ch, flag);
>  	if (oe == 1)
> @@ -266,7 +265,7 @@ static void transmit_chars(struct serial_state *info)
>  	amiga_custom.intreq = IF_TBE;
>  	mb();
>  	if (info->x_char) {
> -	        amiga_custom.serdat = info->x_char | 0x100;
> +		amiga_custom.serdat = info->x_char | 0x100;
>  		mb();
>  		info->icount.tx++;
>  		info->x_char = 0;
> @@ -276,7 +275,7 @@ static void transmit_chars(struct serial_state *info)
>  	    || info->tport.tty->flow.stopped
>  	    || info->tport.tty->hw_stopped) {
>  		info->IER &= ~UART_IER_THRI;
> -	        amiga_custom.intena = IF_TBE;
> +		amiga_custom.intena = IF_TBE;
>  		mb();
>  		return;
>  	}
> @@ -295,7 +294,7 @@ static void transmit_chars(struct serial_state *info)
>  	printk("THRE...");
>  #endif
>  	if (info->xmit.head == info->xmit.tail) {
> -	        amiga_custom.intena = IF_TBE;
> +		amiga_custom.intena = IF_TBE;
>  		mb();
>  		info->IER &= ~UART_IER_THRI;
>  	}
> @@ -317,9 +316,8 @@ static void check_modem_status(struct serial_state *info)
>  		/* update input line counters */
>  		if (dstatus & SER_DSR)
>  			icount->dsr++;
> -		if (dstatus & SER_DCD) {
> +		if (dstatus & SER_DCD)
>  			icount->dcd++;
> -		}
>  		if (dstatus & SER_CTS)
>  			icount->cts++;
>  		wake_up_interruptible(&port->delta_msr_wait);
> @@ -372,17 +370,16 @@ static void check_modem_status(struct serial_state *info)
>  		}
>  	}
>  }
> -
> -static irqreturn_t ser_vbl_int( int irq, void *data)
> +static irqreturn_t ser_vbl_int(int irq, void *data)
>  {
> -        /* vbl is just a periodic interrupt we tie into to update modem status */
> +	/* vbl is just a periodic interrupt we tie into to update modem status */
>  	struct serial_state *info = data;
>  	/*
>  	 * TBD - is it better to unregister from this interrupt or to
>  	 * ignore it if MSI is clear ?
>  	 */
> -	if(info->IER & UART_IER_MSI)
> -	  check_modem_status(info);
> +	if (info->IER & UART_IER_MSI)
> +		check_modem_status(info);
>  	return IRQ_HANDLED;
>  }
>  
> @@ -410,10 +407,9 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id)
>  
>  	if (amiga_custom.serdatr & SDR_TBE) {
>  #ifdef SERIAL_DEBUG_INTR
> -	  printk("ser_tx_int...");
> +		printk("ser_tx_int...");
>  #endif
> -
> -	  if (!info->tport.tty)
> +	if (!info->tport.tty)
>  		return IRQ_NONE;
>  
>  	  transmit_chars(info);
> @@ -443,7 +439,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
>  {
>  	struct tty_port *port = &info->tport;
>  	unsigned long flags;
> -	int	retval=0;
> +	int	retval = 0;
>  	unsigned long page;
>  
>  	page = get_zeroed_page(GFP_KERNEL);
> @@ -490,7 +486,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
>  
>  	info->MCR = 0;
>  	if (C_BAUD(tty))
> -	  info->MCR = SER_DTR | SER_RTS;
> +		info->MCR = SER_DTR | SER_RTS;
>  	rtsdtr_ctrl(info->MCR);
>  
>  	clear_bit(TTY_IO_ERROR, &tty->flags);
> @@ -571,7 +567,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
>  {
>  	struct tty_port *port = &info->tport;
>  	int	quot = 0, baud_base, baud;
> -	unsigned cflag, cval = 0;
> +	unsigned int cflag, cval = 0;
>  	int	bits;
>  	unsigned long	flags;
>  
> @@ -668,7 +664,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
>  	if (I_IGNBRK(tty)) {
>  		info->ignore_status_mask |= UART_LSR_BI;
>  		/*
> -		 * If we're ignore parity and break indicators, ignore 
> +		 * If we're ignore parity and break indicators, ignore
>  		 * overruns too.  (For real raw support).
>  		 */
>  		if (I_IGNPAR(tty))
> @@ -682,16 +678,13 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
>  	local_irq_save(flags);
>  
>  	{
> -	  short serper;
> -
> +	short serper;
>  	/* Set up the baud rate */
> -	  serper = quot - 1;
> +	serper = quot - 1;
>  
>  	/* Enable or disable parity bit */
> -
> -	if(cval & UART_LCR_PARITY)
> -	  serper |= (SERPER_PARENB);
> -
> +	if (cval & UART_LCR_PARITY)
> +		serper |= (SERPER_PARENB);
>  	amiga_custom.serper = serper;
>  	mb();
>  	}
> @@ -744,7 +737,7 @@ static void rs_flush_chars(struct tty_struct *tty)
>  	local_irq_restore(flags);
>  }
>  
> -static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count)
> +static int rs_write(struct tty_struct *tty, const unsigned char *buf, int count)
>  {
>  	int	c, ret = 0;
>  	struct serial_state *info = tty->driver_data;
> @@ -760,9 +753,8 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
>  				      SERIAL_XMIT_SIZE);
>  		if (count < c)
>  			c = count;
> -		if (c <= 0) {
> +		if (c <= 0)
>  			break;
> -		}
>  		memcpy(info->xmit.buf + info->xmit.head, buf, c);
>  		info->xmit.head = ((info->xmit.head + c) &
>  				   (SERIAL_XMIT_SIZE-1));
> @@ -820,20 +812,20 @@ static void rs_flush_buffer(struct tty_struct *tty)
>  static void rs_send_xchar(struct tty_struct *tty, char ch)
>  {
>  	struct serial_state *info = tty->driver_data;
> -        unsigned long flags;
> +	unsigned long flags;
>  
>  	info->x_char = ch;
>  	if (ch) {
>  		/* Make sure transmit interrupts are on */
>  
> -	        /* Check this ! */
> -	        local_irq_save(flags);
> -		if(!(amiga_custom.intenar & IF_TBE)) {
> -		    amiga_custom.intena = IF_SETCLR | IF_TBE;
> -		    mb();
> -		    /* set a pending Tx Interrupt, transmitter should restart now */
> -		    amiga_custom.intreq = IF_SETCLR | IF_TBE;
> -		    mb();
> +		/* Check this ! */
> +		local_irq_save(flags);
> +		if (!(amiga_custom.intenar & IF_TBE)) {
> +			amiga_custom.intena = IF_SETCLR | IF_TBE;
> +			mb();
> +			/* set a pending Tx Interrupt, transmitter should restart now */
> +			amiga_custom.intreq = IF_SETCLR | IF_TBE;
> +			mb();
>  		}
>  		local_irq_restore(flags);
>  
> @@ -844,12 +836,12 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
>  /*
>   * ------------------------------------------------------------
>   * rs_throttle()
> - * 
> + *
>   * This routine is called by the upper-layer tty layer to signal that
>   * incoming characters should be throttled.
>   * ------------------------------------------------------------
>   */
> -static void rs_throttle(struct tty_struct * tty)
> +static void rs_throttle(struct tty_struct *tty)
>  {
>  	struct serial_state *info = tty->driver_data;
>  	unsigned long flags;
> @@ -868,7 +860,7 @@ static void rs_throttle(struct tty_struct * tty)
>  	local_irq_restore(flags);
>  }
>  
> -static void rs_unthrottle(struct tty_struct * tty)
> +static void rs_unthrottle(struct tty_struct *tty)
>  {
>  	struct serial_state *info = tty->driver_data;
>  	unsigned long flags;
> @@ -923,7 +915,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
>  	struct serial_state *state = tty->driver_data;
>  	struct tty_port *port = &state->tport;
>  	bool change_spd;
> -	int 			retval = 0;
> +	int retval = 0;
>  	unsigned int close_delay, closing_wait;
>  
>  	tty_lock(tty);
> @@ -990,11 +982,11 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
>   * get_lsr_info - get line status register info
>   *
>   * Purpose: Let user call ioctl() to get info when the UART physically
> - * 	    is emptied.  On bus types like RS485, the transmitter must
> - * 	    release the bus after transmitting. This must be done when
> - * 	    the transmit shift register is empty, not be done when the
> - * 	    transmit holding register is empty.  This functionality
> - * 	    allows an RS485 driver to be written in user space. 
> + *	    is emptied.  On bus types like RS485, the transmitter must
> + *	    release the bus after transmitting. This must be done when
> + *	    the transmit shift register is empty, not be done when the
> + *	    transmit holding register is empty.  This functionality
> + *	    allows an RS485 driver to be written in user space.
>   */
>  static int get_lsr_info(struct serial_state *info, unsigned int __user *value)
>  {
> @@ -1065,9 +1057,9 @@ static int rs_break(struct tty_struct *tty, int break_state)
>  
>  	local_irq_save(flags);
>  	if (break_state == -1)
> -	  amiga_custom.adkcon = AC_SETCLR | AC_UARTBRK;
> +		amiga_custom.adkcon = AC_SETCLR | AC_UARTBRK;
>  	else
> -	  amiga_custom.adkcon = AC_UARTBRK;
> +		amiga_custom.adkcon = AC_UARTBRK;
>  	mb();
>  	local_irq_restore(flags);
>  	return 0;
> @@ -1117,59 +1109,57 @@ static int rs_ioctl(struct tty_struct *tty,
>  	if ((cmd != TIOCSERCONFIG) &&
>  	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
>  		if (tty_io_error(tty))
> -		    return -EIO;
> +			return -EIO;
>  	}
> -
>  	switch (cmd) {
> -		case TIOCSERCONFIG:
> -			return 0;
> +	case TIOCSERCONFIG:
> +		return 0;
>  
> -		case TIOCSERGETLSR: /* Get line status register */
> -			return get_lsr_info(info, argp);
> +	case TIOCSERGETLSR: /* Get line status register */
> +		return get_lsr_info(info, argp);
>  
>  		/*
>  		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
>  		 * - mask passed in arg for lines of interest
> - 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
> -		 * Caller should use TIOCGICOUNT to see which one it was
> +		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
> +		 *   Caller should use TIOCGICOUNT to see which one it was
>  		 */
> -		case TIOCMIWAIT:
> +	case TIOCMIWAIT:
> +		local_irq_save(flags);
> +		/* note the counters on entry */
> +		cprev = info->icount;
> +		local_irq_restore(flags);
> +		while (1) {
> +			prepare_to_wait(&info->tport.delta_msr_wait,
> +					&wait, TASK_INTERRUPTIBLE);
>  			local_irq_save(flags);
> -			/* note the counters on entry */
> -			cprev = info->icount;
> +			cnow = info->icount; /* atomic copy */
>  			local_irq_restore(flags);
> -			while (1) {
> -				prepare_to_wait(&info->tport.delta_msr_wait,
> -						&wait, TASK_INTERRUPTIBLE);
> -				local_irq_save(flags);
> -				cnow = info->icount; /* atomic copy */
> -				local_irq_restore(flags);
> -				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
> -				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
> -					ret = -EIO; /* no change => error */
> -					break;
> -				}
> -				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
> -				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
> -				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
> -				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
> -					ret = 0;
> -					break;
> -				}
> -				schedule();
> -				/* see if a signal did it */
> -				if (signal_pending(current)) {
> -					ret = -ERESTARTSYS;
> -					break;
> -				}
> -				cprev = cnow;
> +			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
> +					cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
> +				ret = -EIO; /* no change => error */
> +				break;
>  			}
> -			finish_wait(&info->tport.delta_msr_wait, &wait);
> -			return ret;
> -
> -		default:
> -			return -ENOIOCTLCMD;
> +			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
> +					((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
> +					((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
> +					((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
> +				ret = 0;
> +				break;
> +			}
> +			schedule();
> +			/* see if a signal did it */
> +			if (signal_pending(current)) {
> +				ret = -ERESTARTSYS;
> +				break;
> +			}
> +			cprev = cnow;
>  		}
> +		finish_wait(&info->tport.delta_msr_wait, &wait);
> +		return ret;
> +	default:
> +		return -ENOIOCTLCMD;
> +	}
>  	return 0;
>  }
>  
> @@ -1220,14 +1210,14 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
>  /*
>   * ------------------------------------------------------------
>   * rs_close()
> - * 
> + *
>   * This routine is called when the serial port gets closed.  First, we
>   * wait for the last remaining data to be sent.  Then, we unlink its
>   * async structure from the interrupt chain if necessary, and we free
>   * that IRQ if nothing is left in the chain.
>   * ------------------------------------------------------------
>   */
> -static void rs_close(struct tty_struct *tty, struct file * filp)
> +static void rs_close(struct tty_struct *tty, struct file *filp)
>  {
>  	struct serial_state *state = tty->driver_data;
>  	struct tty_port *port = &state->tport;
> @@ -1243,8 +1233,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
>  	 */
>  	state->read_status_mask &= ~UART_LSR_DR;
>  	if (tty_port_initialized(port)) {
> -	        /* disable receive interrupts */
> -	        amiga_custom.intena = IF_RBF;
> +		/* disable receive interrupts */
> +		amiga_custom.intena = IF_RBF;
>  		mb();
>  		/* clear any pending receive interrupt */
>  		amiga_custom.intreq = IF_RBF;
> @@ -1259,7 +1249,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
>  	}
>  	shutdown(tty, state);
>  	rs_flush_buffer(tty);
> -		
> +
>  	tty_ldisc_flush(tty);
>  	port->tty = NULL;
>  
> @@ -1281,7 +1271,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
>  	 * Set the check interval to be 1/5 of the estimated time to
>  	 * send a single character, and make it at least 1.  The check
>  	 * interval should also be less than the timeout.
> -	 * 
> +	 *
>  	 * Note: we have to use pretty tight timings here to satisfy
>  	 * the NIST-PCTS.
>  	 */
> @@ -1290,7 +1280,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
>  	if (char_time == 0)
>  		char_time = 1;
>  	if (timeout)
> -	  char_time = min_t(unsigned long, char_time, timeout);
> +		char_time = min_t(unsigned long, char_time, timeout);
>  	/*
>  	 * If the transmitter hasn't cleared in twice the approximate
>  	 * amount of time to send the entire FIFO, it probably won't
> @@ -1306,7 +1296,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
>  	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
>  	printk("jiff=%lu...", jiffies);
>  #endif
> -	while(!((lsr = amiga_custom.serdatr) & SDR_TSRE)) {
> +	while (!((lsr = amiga_custom.serdatr) & SDR_TSRE)) {
>  #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
>  		printk("serdatr = %d (jiff=%lu)...", lsr, jiffies);
>  #endif
> @@ -1344,7 +1334,7 @@ static void rs_hangup(struct tty_struct *tty)
>   * the IRQ chain.   It also performs the serial-specific
>   * initialization for the tty structure.
>   */
> -static int rs_open(struct tty_struct *tty, struct file * filp)
> +static int rs_open(struct tty_struct *tty, struct file *filp)
>  {
>  	struct tty_port *port = tty->port;
>  	struct serial_state *info = container_of(port, struct serial_state,
> @@ -1356,9 +1346,8 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
>  	tty->driver_data = info;
>  
>  	retval = startup(tty, info);
> -	if (retval) {
> +	if (retval)
>  		return retval;
> -	}
>  
>  	return tty_port_block_til_ready(port, tty, filp);
>  }
> @@ -1382,15 +1371,15 @@ static inline void line_info(struct seq_file *m, int line,
>  
>  	stat_buf[0] = 0;
>  	stat_buf[1] = 0;
> -	if(!(control & SER_RTS))
> +	if (!(control & SER_RTS))
>  		strcat(stat_buf, "|RTS");
> -	if(!(status & SER_CTS))
> +	if (!(status & SER_CTS))
>  		strcat(stat_buf, "|CTS");
> -	if(!(control & SER_DTR))
> +	if (!(control & SER_DTR))
>  		strcat(stat_buf, "|DTR");
> -	if(!(status & SER_DSR))
> +	if (!(status & SER_DSR))
>  		strcat(stat_buf, "|DSR");
> -	if(!(status & SER_DCD))
> +	if (!(status & SER_DCD))
>  		strcat(stat_buf, "|CD");
>  
>  	if (state->quot)
> @@ -1418,7 +1407,7 @@ static inline void line_info(struct seq_file *m, int line,
>  
>  static int rs_proc_show(struct seq_file *m, void *v)
>  {
> -	seq_printf(m, "serinfo:1.0 driver:4.30\n");
> +	seq_puts(m, "serinfo:1.0 driver:4.30\n");
>  	line_info(m, 0, &serial_state);
>  	return 0;
>  }
> @@ -1618,7 +1607,7 @@ static void amiga_serial_putc(char c)
>   *	The console must be locked when we get here.
>   */
>  static void serial_console_write(struct console *co, const char *s,
> -				unsigned count)
> +				unsigned int count)
>  {
>  	unsigned short intena = amiga_custom.intenar;
>  
> diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
> index 19d32cb6a..c41c4c07b 100644
> --- a/drivers/tty/ehv_bytechan.c
> +++ b/drivers/tty/ehv_bytechan.c
> @@ -324,8 +324,9 @@ static int __init ehv_bc_console_init(void)
>  #endif
>  
>  	/* add_preferred_console() must be called before register_console(),
> -	   otherwise it won't work.  However, we don't want to enumerate all the
> -	   byte channels here, either, since we only care about one. */
> +	 * otherwise it won't work.  However, we don't want to enumerate all the
> +	 * byte channels here, either, since we only care about one.
> +	 */
>  
>  	add_preferred_console(ehv_bc_console.name, ehv_bc_console.index, NULL);
>  	register_console(&ehv_bc_console);
> diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
> index 5ed19a985..61ccbf670 100644
> --- a/drivers/tty/goldfish.c
> +++ b/drivers/tty/goldfish.c
> @@ -173,6 +173,7 @@ static void goldfish_tty_shutdown(struct tty_port *port)
>  static int goldfish_tty_open(struct tty_struct *tty, struct file *filp)
>  {
>  	struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
> +
>  	return tty_port_open(&qtty->port, tty, filp);
>  }
>  
> @@ -202,6 +203,7 @@ static unsigned int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
>  {
>  	struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
>  	void __iomem *base = qtty->base;
> +
>  	return __raw_readl(base + GOLDFISH_TTY_REG_BYTES_READY);
>  }
>  
> -- 
> 2.32.0
> 

Hi,

This is the friendly patch-bot of Greg Kroah-Hartman.  You have sent him
a patch that has triggered this response.  He used to manually respond
to these common problems, but in order to save his sanity (he kept
writing the same thing over and over, yet to different people), I was
created.  Hopefully you will not take offence and will fix the problem
in your patch and resubmit it so that it can be accepted into the Linux
kernel tree.

You are receiving this message because of the following common error(s)
as indicated below:

- Your patch does not have a Signed-off-by: line.  Please read the
  kernel file, Documentation/SubmittingPatches and resend it after
  adding that line.  Note, the line needs to be in the body of the
  email, before the patch, not at the bottom of the patch or in the
  email signature.

- Your patch did many different things all at once, making it difficult
  to review.  All Linux kernel patches need to only do one thing at a
  time.  If you need to do multiple things (such as clean up all coding
  style issues in a file/driver), do it in a sequence of patches, each
  one doing only one thing.  This will make it easier to review the
  patches to ensure that they are correct, and to help alleviate any
  merge issues that larger patches can cause.

- You did not specify a description of why the patch is needed, or
  possibly, any description at all, in the email body.  Please read the
  section entitled "The canonical patch format" in the kernel file,
  Documentation/SubmittingPatches for what is needed in order to
  properly describe the change.

- You did not write a descriptive Subject: for the patch, allowing Greg,
  and everyone else, to know what this patch is all about.  Please read
  the section entitled "The canonical patch format" in the kernel file,
  Documentation/SubmittingPatches for what a proper Subject: line should
  look like.

If you wish to discuss this problem further, or you have questions about
how to resolve this issue, please feel free to respond to this email and
Greg will reply once he has dug out from the pending patches received
from other developers.

thanks,

greg k-h's patch email bot

^ permalink raw reply

* [PATCH v2] i2c: pasemi: Drop I2C classes from platform driver variant
From: Martin Povišer @ 2022-02-04  9:59 UTC (permalink / raw)
  To: Hector Martin, Sven Peter, Michael Ellerman
  Cc: linux-kernel, Paul Mackerras, linux-i2c, Martin Povišer,
	linuxppc-dev, Alyssa Rosenzweig

Drop I2C device-probing classes from platform variant of the PASemi
controller as it is only used on platforms where I2C devices should
be instantiated in devicetree. (The I2C_CLASS_DEPRECATED flag is not
raised as up to this point no devices relied on the old behavior.)

Fixes: d88ae2932df0 ("i2c: pasemi: Add Apple platform driver")
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
---
I am sending v2 as some people got their copy in v1 encrypted with
their WKD keys (by accident). I changed email provider since.

 drivers/i2c/busses/i2c-pasemi-core.c | 1 -
 drivers/i2c/busses/i2c-pasemi-pci.c  | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-pasemi-core.c b/drivers/i2c/busses/i2c-pasemi-core.c
index 4e161a4089d8..7728c8460dc0 100644
--- a/drivers/i2c/busses/i2c-pasemi-core.c
+++ b/drivers/i2c/busses/i2c-pasemi-core.c
@@ -333,7 +333,6 @@ int pasemi_i2c_common_probe(struct pasemi_smbus *smbus)
 	smbus->adapter.owner = THIS_MODULE;
 	snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
 		 "PA Semi SMBus adapter (%s)", dev_name(smbus->dev));
-	smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
 	smbus->adapter.algo = &smbus_algorithm;
 	smbus->adapter.algo_data = smbus;
 
diff --git a/drivers/i2c/busses/i2c-pasemi-pci.c b/drivers/i2c/busses/i2c-pasemi-pci.c
index 1ab1f28744fb..cfc89e04eb94 100644
--- a/drivers/i2c/busses/i2c-pasemi-pci.c
+++ b/drivers/i2c/busses/i2c-pasemi-pci.c
@@ -56,6 +56,7 @@ static int pasemi_smb_pci_probe(struct pci_dev *dev,
 	if (!smbus->ioaddr)
 		return -EBUSY;
 
+	smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
 	error = pasemi_i2c_common_probe(smbus);
 	if (error)
 		return error;
-- 
2.33.0


^ permalink raw reply related

* [PATCH] Styleguide fix: Removed un-needed whitespaces and formatting errors in drivers/tty
From: Ankit Kumar Pandey @ 2022-02-06 19:03 UTC (permalink / raw)
  To: gregkh

There were lot of styleguide errors raised by checkpatch.pl against
drivers/tty/* which I have fixed. There is zero code change apart from
changes related to styleguide. checkpatch.pl returns 0 error for
style guide now.

---
 drivers/tty/amiserial.c    | 285 ++++++++++++++++++-------------------
 drivers/tty/ehv_bytechan.c |   5 +-
 drivers/tty/goldfish.c     |   2 +
 3 files changed, 142 insertions(+), 150 deletions(-)

diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 1e60dbef6..15917254e 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -12,13 +12,13 @@
  * (non hardware specific) changes to serial.c.
  *
  * The port is registered with the tty driver as minor device 64, and
- * therefore other ports should should only use 65 upwards.
+ * therefore other ports should only use 65 upwards.
  *
  * Richard Lucock 28/12/99
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 
- * 		1998, 1999  Theodore Ts'o
+ *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
+ *		1998, 1999  Theodore Ts'o
  *
  */
 
@@ -78,8 +78,8 @@ struct serial_state {
 	int			ignore_status_mask;
 	int			timeout;
 	int			quot;
-	int			IER; 	/* Interrupt Enable Register */
-	int			MCR; 	/* Modem control register */
+	int			IER;	/* Interrupt Enable Register */
+	int			MCR;	/* Modem control register */
 	int			x_char;	/* xon/xoff character */
 };
 
@@ -116,9 +116,9 @@ static struct serial_state serial_state;
 #define SER_CTS     (1<<4)
 #define SER_DSR     (1<<3)
 
-static __inline__ void rtsdtr_ctrl(int bits)
+static inline void rtsdtr_ctrl(int bits)
 {
-    ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR));
+	ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR));
 }
 
 /*
@@ -175,7 +175,7 @@ static void rs_start(struct tty_struct *tty)
 
 static void receive_chars(struct serial_state *info)
 {
-        int status;
+	int status;
 	int serdatr;
 	unsigned char ch, flag;
 	struct	async_icount *icount;
@@ -189,10 +189,10 @@ static void receive_chars(struct serial_state *info)
 	amiga_custom.intreq = IF_RBF;
 	mb();
 
-	if((serdatr & 0x1ff) == 0)
-	    status |= UART_LSR_BI;
-	if(serdatr & SDR_OVRUN)
-	    status |= UART_LSR_OE;
+	if ((serdatr & 0x1ff) == 0)
+		status |= UART_LSR_BI;
+	if (serdatr & SDR_OVRUN)
+		status |= UART_LSR_OE;
 
 	ch = serdatr & 0xff;
 	icount->rx++;
@@ -213,45 +213,44 @@ static void receive_chars(struct serial_state *info)
 	  /*
 	   * For statistics only
 	   */
-	  if (status & UART_LSR_BI) {
-	    status &= ~(UART_LSR_FE | UART_LSR_PE);
-	    icount->brk++;
-	  } else if (status & UART_LSR_PE)
-	    icount->parity++;
-	  else if (status & UART_LSR_FE)
-	    icount->frame++;
-	  if (status & UART_LSR_OE)
-	    icount->overrun++;
+		if (status & UART_LSR_BI) {
+			status &= ~(UART_LSR_FE | UART_LSR_PE);
+			icount->brk++;
+		} else if (status & UART_LSR_PE)
+			icount->parity++;
+		else if (status & UART_LSR_FE)
+			icount->frame++;
+		if (status & UART_LSR_OE)
+			icount->overrun++;
 
 	  /*
 	   * Now check to see if character should be
 	   * ignored, and mask off conditions which
 	   * should be ignored.
 	   */
-	  if (status & info->ignore_status_mask)
-	    goto out;
+		if (status & info->ignore_status_mask)
+			goto out;
 
-	  status &= info->read_status_mask;
-
-	  if (status & (UART_LSR_BI)) {
+		status &= info->read_status_mask;
+		if (status & (UART_LSR_BI)) {
 #ifdef SERIAL_DEBUG_INTR
-	    printk("handling break....");
+			printk("handling break....");
 #endif
-	    flag = TTY_BREAK;
-	    if (info->tport.flags & ASYNC_SAK)
-	      do_SAK(info->tport.tty);
-	  } else if (status & UART_LSR_PE)
-	    flag = TTY_PARITY;
-	  else if (status & UART_LSR_FE)
-	    flag = TTY_FRAME;
-	  if (status & UART_LSR_OE) {
-	    /*
-	     * Overrun is special, since it's
-	     * reported immediately, and doesn't
-	     * affect the current character
-	     */
-	     oe = 1;
-	  }
+			flag = TTY_BREAK;
+			if (info->tport.flags & ASYNC_SAK)
+				do_SAK(info->tport.tty);
+		} else if (status & UART_LSR_PE)
+			flag = TTY_PARITY;
+		else if (status & UART_LSR_FE)
+			flag = TTY_FRAME;
+		if (status & UART_LSR_OE) {
+			/*
+			 * Overrun is special, since it's
+			 * reported immediately, and doesn't
+			 * affect the current character
+			 */
+			oe = 1;
+		}
 	}
 	tty_insert_flip_char(&info->tport, ch, flag);
 	if (oe == 1)
@@ -266,7 +265,7 @@ static void transmit_chars(struct serial_state *info)
 	amiga_custom.intreq = IF_TBE;
 	mb();
 	if (info->x_char) {
-	        amiga_custom.serdat = info->x_char | 0x100;
+		amiga_custom.serdat = info->x_char | 0x100;
 		mb();
 		info->icount.tx++;
 		info->x_char = 0;
@@ -276,7 +275,7 @@ static void transmit_chars(struct serial_state *info)
 	    || info->tport.tty->flow.stopped
 	    || info->tport.tty->hw_stopped) {
 		info->IER &= ~UART_IER_THRI;
-	        amiga_custom.intena = IF_TBE;
+		amiga_custom.intena = IF_TBE;
 		mb();
 		return;
 	}
@@ -295,7 +294,7 @@ static void transmit_chars(struct serial_state *info)
 	printk("THRE...");
 #endif
 	if (info->xmit.head == info->xmit.tail) {
-	        amiga_custom.intena = IF_TBE;
+		amiga_custom.intena = IF_TBE;
 		mb();
 		info->IER &= ~UART_IER_THRI;
 	}
@@ -317,9 +316,8 @@ static void check_modem_status(struct serial_state *info)
 		/* update input line counters */
 		if (dstatus & SER_DSR)
 			icount->dsr++;
-		if (dstatus & SER_DCD) {
+		if (dstatus & SER_DCD)
 			icount->dcd++;
-		}
 		if (dstatus & SER_CTS)
 			icount->cts++;
 		wake_up_interruptible(&port->delta_msr_wait);
@@ -372,17 +370,16 @@ static void check_modem_status(struct serial_state *info)
 		}
 	}
 }
-
-static irqreturn_t ser_vbl_int( int irq, void *data)
+static irqreturn_t ser_vbl_int(int irq, void *data)
 {
-        /* vbl is just a periodic interrupt we tie into to update modem status */
+	/* vbl is just a periodic interrupt we tie into to update modem status */
 	struct serial_state *info = data;
 	/*
 	 * TBD - is it better to unregister from this interrupt or to
 	 * ignore it if MSI is clear ?
 	 */
-	if(info->IER & UART_IER_MSI)
-	  check_modem_status(info);
+	if (info->IER & UART_IER_MSI)
+		check_modem_status(info);
 	return IRQ_HANDLED;
 }
 
@@ -410,10 +407,9 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id)
 
 	if (amiga_custom.serdatr & SDR_TBE) {
 #ifdef SERIAL_DEBUG_INTR
-	  printk("ser_tx_int...");
+		printk("ser_tx_int...");
 #endif
-
-	  if (!info->tport.tty)
+	if (!info->tport.tty)
 		return IRQ_NONE;
 
 	  transmit_chars(info);
@@ -443,7 +439,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
 {
 	struct tty_port *port = &info->tport;
 	unsigned long flags;
-	int	retval=0;
+	int	retval = 0;
 	unsigned long page;
 
 	page = get_zeroed_page(GFP_KERNEL);
@@ -490,7 +486,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
 
 	info->MCR = 0;
 	if (C_BAUD(tty))
-	  info->MCR = SER_DTR | SER_RTS;
+		info->MCR = SER_DTR | SER_RTS;
 	rtsdtr_ctrl(info->MCR);
 
 	clear_bit(TTY_IO_ERROR, &tty->flags);
@@ -571,7 +567,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
 {
 	struct tty_port *port = &info->tport;
 	int	quot = 0, baud_base, baud;
-	unsigned cflag, cval = 0;
+	unsigned int cflag, cval = 0;
 	int	bits;
 	unsigned long	flags;
 
@@ -668,7 +664,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
 	if (I_IGNBRK(tty)) {
 		info->ignore_status_mask |= UART_LSR_BI;
 		/*
-		 * If we're ignore parity and break indicators, ignore 
+		 * If we're ignore parity and break indicators, ignore
 		 * overruns too.  (For real raw support).
 		 */
 		if (I_IGNPAR(tty))
@@ -682,16 +678,13 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
 	local_irq_save(flags);
 
 	{
-	  short serper;
-
+	short serper;
 	/* Set up the baud rate */
-	  serper = quot - 1;
+	serper = quot - 1;
 
 	/* Enable or disable parity bit */
-
-	if(cval & UART_LCR_PARITY)
-	  serper |= (SERPER_PARENB);
-
+	if (cval & UART_LCR_PARITY)
+		serper |= (SERPER_PARENB);
 	amiga_custom.serper = serper;
 	mb();
 	}
@@ -744,7 +737,7 @@ static void rs_flush_chars(struct tty_struct *tty)
 	local_irq_restore(flags);
 }
 
-static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int rs_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
 	int	c, ret = 0;
 	struct serial_state *info = tty->driver_data;
@@ -760,9 +753,8 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
 				      SERIAL_XMIT_SIZE);
 		if (count < c)
 			c = count;
-		if (c <= 0) {
+		if (c <= 0)
 			break;
-		}
 		memcpy(info->xmit.buf + info->xmit.head, buf, c);
 		info->xmit.head = ((info->xmit.head + c) &
 				   (SERIAL_XMIT_SIZE-1));
@@ -820,20 +812,20 @@ static void rs_flush_buffer(struct tty_struct *tty)
 static void rs_send_xchar(struct tty_struct *tty, char ch)
 {
 	struct serial_state *info = tty->driver_data;
-        unsigned long flags;
+	unsigned long flags;
 
 	info->x_char = ch;
 	if (ch) {
 		/* Make sure transmit interrupts are on */
 
-	        /* Check this ! */
-	        local_irq_save(flags);
-		if(!(amiga_custom.intenar & IF_TBE)) {
-		    amiga_custom.intena = IF_SETCLR | IF_TBE;
-		    mb();
-		    /* set a pending Tx Interrupt, transmitter should restart now */
-		    amiga_custom.intreq = IF_SETCLR | IF_TBE;
-		    mb();
+		/* Check this ! */
+		local_irq_save(flags);
+		if (!(amiga_custom.intenar & IF_TBE)) {
+			amiga_custom.intena = IF_SETCLR | IF_TBE;
+			mb();
+			/* set a pending Tx Interrupt, transmitter should restart now */
+			amiga_custom.intreq = IF_SETCLR | IF_TBE;
+			mb();
 		}
 		local_irq_restore(flags);
 
@@ -844,12 +836,12 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
 /*
  * ------------------------------------------------------------
  * rs_throttle()
- * 
+ *
  * This routine is called by the upper-layer tty layer to signal that
  * incoming characters should be throttled.
  * ------------------------------------------------------------
  */
-static void rs_throttle(struct tty_struct * tty)
+static void rs_throttle(struct tty_struct *tty)
 {
 	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
@@ -868,7 +860,7 @@ static void rs_throttle(struct tty_struct * tty)
 	local_irq_restore(flags);
 }
 
-static void rs_unthrottle(struct tty_struct * tty)
+static void rs_unthrottle(struct tty_struct *tty)
 {
 	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
@@ -923,7 +915,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
 	struct serial_state *state = tty->driver_data;
 	struct tty_port *port = &state->tport;
 	bool change_spd;
-	int 			retval = 0;
+	int retval = 0;
 	unsigned int close_delay, closing_wait;
 
 	tty_lock(tty);
@@ -990,11 +982,11 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
  * get_lsr_info - get line status register info
  *
  * Purpose: Let user call ioctl() to get info when the UART physically
- * 	    is emptied.  On bus types like RS485, the transmitter must
- * 	    release the bus after transmitting. This must be done when
- * 	    the transmit shift register is empty, not be done when the
- * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space. 
+ *	    is emptied.  On bus types like RS485, the transmitter must
+ *	    release the bus after transmitting. This must be done when
+ *	    the transmit shift register is empty, not be done when the
+ *	    transmit holding register is empty.  This functionality
+ *	    allows an RS485 driver to be written in user space.
  */
 static int get_lsr_info(struct serial_state *info, unsigned int __user *value)
 {
@@ -1065,9 +1057,9 @@ static int rs_break(struct tty_struct *tty, int break_state)
 
 	local_irq_save(flags);
 	if (break_state == -1)
-	  amiga_custom.adkcon = AC_SETCLR | AC_UARTBRK;
+		amiga_custom.adkcon = AC_SETCLR | AC_UARTBRK;
 	else
-	  amiga_custom.adkcon = AC_UARTBRK;
+		amiga_custom.adkcon = AC_UARTBRK;
 	mb();
 	local_irq_restore(flags);
 	return 0;
@@ -1117,59 +1109,57 @@ static int rs_ioctl(struct tty_struct *tty,
 	if ((cmd != TIOCSERCONFIG) &&
 	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
 		if (tty_io_error(tty))
-		    return -EIO;
+			return -EIO;
 	}
-
 	switch (cmd) {
-		case TIOCSERCONFIG:
-			return 0;
+	case TIOCSERCONFIG:
+		return 0;
 
-		case TIOCSERGETLSR: /* Get line status register */
-			return get_lsr_info(info, argp);
+	case TIOCSERGETLSR: /* Get line status register */
+		return get_lsr_info(info, argp);
 
 		/*
 		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
 		 * - mask passed in arg for lines of interest
- 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-		 * Caller should use TIOCGICOUNT to see which one it was
+		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+		 *   Caller should use TIOCGICOUNT to see which one it was
 		 */
-		case TIOCMIWAIT:
+	case TIOCMIWAIT:
+		local_irq_save(flags);
+		/* note the counters on entry */
+		cprev = info->icount;
+		local_irq_restore(flags);
+		while (1) {
+			prepare_to_wait(&info->tport.delta_msr_wait,
+					&wait, TASK_INTERRUPTIBLE);
 			local_irq_save(flags);
-			/* note the counters on entry */
-			cprev = info->icount;
+			cnow = info->icount; /* atomic copy */
 			local_irq_restore(flags);
-			while (1) {
-				prepare_to_wait(&info->tport.delta_msr_wait,
-						&wait, TASK_INTERRUPTIBLE);
-				local_irq_save(flags);
-				cnow = info->icount; /* atomic copy */
-				local_irq_restore(flags);
-				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
-				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
-					ret = -EIO; /* no change => error */
-					break;
-				}
-				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
-					ret = 0;
-					break;
-				}
-				schedule();
-				/* see if a signal did it */
-				if (signal_pending(current)) {
-					ret = -ERESTARTSYS;
-					break;
-				}
-				cprev = cnow;
+			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+					cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+				ret = -EIO; /* no change => error */
+				break;
 			}
-			finish_wait(&info->tport.delta_msr_wait, &wait);
-			return ret;
-
-		default:
-			return -ENOIOCTLCMD;
+			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+					((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+					((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+					((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+				ret = 0;
+				break;
+			}
+			schedule();
+			/* see if a signal did it */
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+			cprev = cnow;
 		}
+		finish_wait(&info->tport.delta_msr_wait, &wait);
+		return ret;
+	default:
+		return -ENOIOCTLCMD;
+	}
 	return 0;
 }
 
@@ -1220,14 +1210,14 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 /*
  * ------------------------------------------------------------
  * rs_close()
- * 
+ *
  * This routine is called when the serial port gets closed.  First, we
  * wait for the last remaining data to be sent.  Then, we unlink its
  * async structure from the interrupt chain if necessary, and we free
  * that IRQ if nothing is left in the chain.
  * ------------------------------------------------------------
  */
-static void rs_close(struct tty_struct *tty, struct file * filp)
+static void rs_close(struct tty_struct *tty, struct file *filp)
 {
 	struct serial_state *state = tty->driver_data;
 	struct tty_port *port = &state->tport;
@@ -1243,8 +1233,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 	 */
 	state->read_status_mask &= ~UART_LSR_DR;
 	if (tty_port_initialized(port)) {
-	        /* disable receive interrupts */
-	        amiga_custom.intena = IF_RBF;
+		/* disable receive interrupts */
+		amiga_custom.intena = IF_RBF;
 		mb();
 		/* clear any pending receive interrupt */
 		amiga_custom.intreq = IF_RBF;
@@ -1259,7 +1249,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 	}
 	shutdown(tty, state);
 	rs_flush_buffer(tty);
-		
+
 	tty_ldisc_flush(tty);
 	port->tty = NULL;
 
@@ -1281,7 +1271,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 	 * Set the check interval to be 1/5 of the estimated time to
 	 * send a single character, and make it at least 1.  The check
 	 * interval should also be less than the timeout.
-	 * 
+	 *
 	 * Note: we have to use pretty tight timings here to satisfy
 	 * the NIST-PCTS.
 	 */
@@ -1290,7 +1280,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 	if (char_time == 0)
 		char_time = 1;
 	if (timeout)
-	  char_time = min_t(unsigned long, char_time, timeout);
+		char_time = min_t(unsigned long, char_time, timeout);
 	/*
 	 * If the transmitter hasn't cleared in twice the approximate
 	 * amount of time to send the entire FIFO, it probably won't
@@ -1306,7 +1296,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
 	printk("jiff=%lu...", jiffies);
 #endif
-	while(!((lsr = amiga_custom.serdatr) & SDR_TSRE)) {
+	while (!((lsr = amiga_custom.serdatr) & SDR_TSRE)) {
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 		printk("serdatr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
@@ -1344,7 +1334,7 @@ static void rs_hangup(struct tty_struct *tty)
  * the IRQ chain.   It also performs the serial-specific
  * initialization for the tty structure.
  */
-static int rs_open(struct tty_struct *tty, struct file * filp)
+static int rs_open(struct tty_struct *tty, struct file *filp)
 {
 	struct tty_port *port = tty->port;
 	struct serial_state *info = container_of(port, struct serial_state,
@@ -1356,9 +1346,8 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
 	tty->driver_data = info;
 
 	retval = startup(tty, info);
-	if (retval) {
+	if (retval)
 		return retval;
-	}
 
 	return tty_port_block_til_ready(port, tty, filp);
 }
@@ -1382,15 +1371,15 @@ static inline void line_info(struct seq_file *m, int line,
 
 	stat_buf[0] = 0;
 	stat_buf[1] = 0;
-	if(!(control & SER_RTS))
+	if (!(control & SER_RTS))
 		strcat(stat_buf, "|RTS");
-	if(!(status & SER_CTS))
+	if (!(status & SER_CTS))
 		strcat(stat_buf, "|CTS");
-	if(!(control & SER_DTR))
+	if (!(control & SER_DTR))
 		strcat(stat_buf, "|DTR");
-	if(!(status & SER_DSR))
+	if (!(status & SER_DSR))
 		strcat(stat_buf, "|DSR");
-	if(!(status & SER_DCD))
+	if (!(status & SER_DCD))
 		strcat(stat_buf, "|CD");
 
 	if (state->quot)
@@ -1418,7 +1407,7 @@ static inline void line_info(struct seq_file *m, int line,
 
 static int rs_proc_show(struct seq_file *m, void *v)
 {
-	seq_printf(m, "serinfo:1.0 driver:4.30\n");
+	seq_puts(m, "serinfo:1.0 driver:4.30\n");
 	line_info(m, 0, &serial_state);
 	return 0;
 }
@@ -1618,7 +1607,7 @@ static void amiga_serial_putc(char c)
  *	The console must be locked when we get here.
  */
 static void serial_console_write(struct console *co, const char *s,
-				unsigned count)
+				unsigned int count)
 {
 	unsigned short intena = amiga_custom.intenar;
 
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 19d32cb6a..c41c4c07b 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -324,8 +324,9 @@ static int __init ehv_bc_console_init(void)
 #endif
 
 	/* add_preferred_console() must be called before register_console(),
-	   otherwise it won't work.  However, we don't want to enumerate all the
-	   byte channels here, either, since we only care about one. */
+	 * otherwise it won't work.  However, we don't want to enumerate all the
+	 * byte channels here, either, since we only care about one.
+	 */
 
 	add_preferred_console(ehv_bc_console.name, ehv_bc_console.index, NULL);
 	register_console(&ehv_bc_console);
diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
index 5ed19a985..61ccbf670 100644
--- a/drivers/tty/goldfish.c
+++ b/drivers/tty/goldfish.c
@@ -173,6 +173,7 @@ static void goldfish_tty_shutdown(struct tty_port *port)
 static int goldfish_tty_open(struct tty_struct *tty, struct file *filp)
 {
 	struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
+
 	return tty_port_open(&qtty->port, tty, filp);
 }
 
@@ -202,6 +203,7 @@ static unsigned int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
 {
 	struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
 	void __iomem *base = qtty->base;
+
 	return __raw_readl(base + GOLDFISH_TTY_REG_BYTES_READY);
 }
 
-- 
2.32.0


^ permalink raw reply related


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