devfs: make persistent controlling terminal an ABI property

Linux leaves the session's controlling terminal in place after the
last file descriptor on the slave is closed, so a later open of
/dev/tty succeeds.  FreeBSD drops the session vnode reference on that
close. /dev/tty then fails, which breaks Linux programs such as xterm
that close the pty slave during startup and expect /dev/tty to keep
working.

When the closer is a Linux process, leave the session reference in
place.  Still pass FLASTCLOSE to the driver so the master sees hangup.
Native close behavior is unchanged.

Add the SV_PERSISTENT_CTTY sysentvec flag for ABIs that retain the
controlling terminal after the last slave descriptor is closed.  This
keeps the devfs behavior ABI-agnostic and allows other ABIs to request
the same semantics if needed.  Use the flag in devfs_close().

Reviewed by:	kib
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D60701
This commit is contained in:
Vladimir Grebenshchikov authored and Konstantin Belousov committed 2026-10-20 20:38:09 +03:00
1 parent 44961edac8
commit e8923c7346
6 files changed
+15 -6

No files matched your search

+1 -1
View File
@@ -705,7 +705,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,
+2 -1
View File
@@ -805,7 +805,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,
+1 -1
View File
@@ -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,
+7 -1
View File
@@ -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) {
+3 -2
View File
@@ -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,
+1
View File
@@ -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))