git: 9dcc20504c8b - stable/15 - devfs: make persistent controlling terminal an ABI property

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Mon, 26 Oct 2026 03:40:15 UTC
The branch stable/15 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=9dcc20504c8bee707bcd8cb01a0b1ef07e41c3c0

commit 9dcc20504c8bee707bcd8cb01a0b1ef07e41c3c0
Author:     Vladimir Grebenshchikov <vova@zote.me>
AuthorDate: 2026-10-13 23:04:27 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-10-26 03:38:18 +0000

    devfs: make persistent controlling terminal an ABI property
    
    (cherry picked from commit e8923c7346a882418352683f72e7c4f8e68d6907)
---
 sys/amd64/linux/linux_sysvec.c     | 2 +-
 sys/amd64/linux32/linux32_sysvec.c | 3 ++-
 sys/arm64/linux/linux_sysvec.c     | 2 +-
 sys/fs/devfs/devfs_vnops.c         | 8 +++++++-
 sys/i386/linux/linux_sysvec.c      | 5 +++--
 sys/sys/sysent.h                   | 1 +
 6 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c
index 210c3e127de3..8ba0673a2cc2 100644
--- a/sys/amd64/linux/linux_sysvec.c
+++ b/sys/amd64/linux/linux_sysvec.c
@@ -701,7 +701,7 @@ struct sysentvec elf_linux_sysvec = {
 	.sv_fixlimit	= NULL,
 	.sv_maxssiz	= NULL,
 	.sv_flags	= SV_ABI_LINUX | SV_LP64 | SV_SHP | SV_SIG_DISCIGN |
-	    SV_SIG_WAITNDQ | SV_TIMEKEEP,
+	    SV_SIG_WAITNDQ | SV_TIMEKEEP | SV_PERSISTENT_CTTY,
 	.sv_set_syscall_retval = linux_set_syscall_retval,
 	.sv_fetch_syscall_args = linux_fetch_syscall_args,
 	.sv_syscallnames = linux_syscallnames,
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
index a61039a2dc16..5934aaee9a80 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -801,7 +801,8 @@ struct sysentvec elf_linux_sysvec = {
 	.sv_fixlimit	= linux32_fixlimit,
 	.sv_maxssiz	= &linux32_maxssiz,
 	.sv_flags	= SV_ABI_LINUX | SV_ILP32 | SV_SHP |
-	    SV_SIG_DISCIGN | SV_SIG_WAITNDQ | SV_TIMEKEEP,
+	    SV_SIG_DISCIGN | SV_SIG_WAITNDQ | SV_TIMEKEEP |
+	    SV_PERSISTENT_CTTY,
 	.sv_set_syscall_retval = linux32_set_syscall_retval,
 	.sv_fetch_syscall_args = linux32_fetch_syscall_args,
 	.sv_syscallnames = linux32_syscallnames,
diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c
index ac05820f89bc..03e86307dc34 100644
--- a/sys/arm64/linux/linux_sysvec.c
+++ b/sys/arm64/linux/linux_sysvec.c
@@ -449,7 +449,7 @@ struct sysentvec elf_linux_sysvec = {
 	.sv_fixlimit	= NULL,
 	.sv_maxssiz	= NULL,
 	.sv_flags	= SV_ABI_LINUX | SV_LP64 | SV_SHP | SV_SIG_DISCIGN |
-	    SV_SIG_WAITNDQ | SV_TIMEKEEP,
+	    SV_SIG_WAITNDQ | SV_TIMEKEEP | SV_PERSISTENT_CTTY,
 	.sv_set_syscall_retval = linux_set_syscall_retval,
 	.sv_fetch_syscall_args = linux_fetch_syscall_args,
 	.sv_syscallnames = linux_syscallnames,
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index bb708afad103..643a966a08a5 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -59,6 +59,7 @@
 #include <sys/stat.h>
 #include <sys/sx.h>
 #include <sys/sysctl.h>
+#include <sys/sysent.h>
 #include <sys/time.h>
 #include <sys/ttycom.h>
 #include <sys/unistd.h>
@@ -716,8 +717,13 @@ devfs_close(struct vop_close_args *ap)
 	 * process' controlling terminal.  In that case,
 	 * if the reference count is 2 (this last descriptor
 	 * plus the session), release the reference from the session.
+	 *
+	 * Some ABIs keep the controlling terminal after the last
+	 * slave descriptor is closed.  A closer with SV_PERSISTENT_CTTY
+	 * leaves the session reference in place.
 	 */
-	if (de->de_usecount == 2 && td != NULL) {
+	if (!SV_PROC_FLAG(curproc, SV_PERSISTENT_CTTY) &&
+	    de->de_usecount == 2 && td != NULL) {
 		p = td->td_proc;
 		PROC_LOCK(p);
 		if (vp == p->p_session->s_ttyvp) {
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index 14b5f64388d2..333f8d21cdb3 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -597,7 +597,7 @@ struct sysentvec linux_sysvec = {
 	.sv_fixlimit	= NULL,
 	.sv_maxssiz	= NULL,
 	.sv_flags	= SV_ABI_LINUX | SV_AOUT | SV_ILP32 |
-	    SV_SIG_DISCIGN | SV_SIG_WAITNDQ,
+	    SV_SIG_DISCIGN | SV_SIG_WAITNDQ | SV_PERSISTENT_CTTY,
 	.sv_set_syscall_retval = linux_set_syscall_retval,
 	.sv_fetch_syscall_args = linux_fetch_syscall_args,
 	.sv_syscallnames = linux_syscallnames,
@@ -641,7 +641,8 @@ struct sysentvec elf_linux_sysvec = {
 	.sv_fixlimit	= NULL,
 	.sv_maxssiz	= NULL,
 	.sv_flags	= SV_ABI_LINUX | SV_ILP32 | SV_SHP |
-	    SV_SIG_DISCIGN | SV_SIG_WAITNDQ | SV_TIMEKEEP,
+	    SV_SIG_DISCIGN | SV_SIG_WAITNDQ | SV_TIMEKEEP |
+	    SV_PERSISTENT_CTTY,
 	.sv_set_syscall_retval = linux_set_syscall_retval,
 	.sv_fetch_syscall_args = linux_fetch_syscall_args,
 	.sv_syscallnames = NULL,
diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h
index b2a559da7844..8b45d0cb4dff 100644
--- a/sys/sys/sysent.h
+++ b/sys/sys/sysent.h
@@ -175,6 +175,7 @@ struct sysentvec {
 #define	SV_SIG_DISCIGN	0x200000	/* Do not discard ignored signals */
 #define	SV_SIG_WAITNDQ	0x400000	/* Wait does not dequeue SIGCHLD */
 #define	SV_DSO_SIG	0x800000	/* Signal trampoline packed in dso */
+#define	SV_PERSISTENT_CTTY 0x1000000 /* Keep ctty after the last close */
 
 #define	SV_ABI_MASK	0xff
 #define	SV_PROC_FLAG(p, x)	((p)->p_sysent->sv_flags & (x))