git: 18b6bb5231bf - main - procdesc: track count of open files

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 07 Jul 2026 01:57:15 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=18b6bb5231bf1c927a6f8de24e466764fe1f7470

commit 18b6bb5231bf1c927a6f8de24e466764fe1f7470
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-05-21 00:47:20 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-07-07 01:24:02 +0000

    procdesc: track count of open files
    
    Introduce pd_fpcount that counts the number of file references to the
    procdesc.  Remove the PDF_CLOSED flag, now it is expressed as
    pd_fpcount == 0.
    
    Only send SIGKILL and clear pointers when we are closing the last file
    referencing procdesc.
    
    This should be nop until the next commit.
    
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D57124
---
 sys/kern/kern_exit.c    |  4 ++--
 sys/kern/sys_procdesc.c | 17 +++++++++++------
 sys/sys/procdesc.h      |  4 +++-
 3 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 8f9007752b3b..db8882d70041 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1573,8 +1573,8 @@ kern_pdwait(struct thread *td, int fd, int *status,
 
 	for (;;) {
 		/* We own a reference on the procdesc file. */
-		KASSERT((pd->pd_flags & PDF_CLOSED) == 0,
-		    ("PDF_CLOSED proc %p procdesc %p pd flags %#x",
+		KASSERT(pd->pd_fpcount > 0,
+		    ("closed proc %p procdesc %p pd flags %#x",
 		    p, pd, pd->pd_flags));
 
 		sx_xlock(&proctree_lock);
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index e6174ea3cbb9..c5be98f66749 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -219,6 +219,7 @@ procdesc_alloc(int flags)
 	 * struct file, and the other from their struct proc.
 	 */
 	refcount_init(&pd->pd_refcount, 2);
+	pd->pd_fpcount = 1;
 
 	return (pd);
 }
@@ -293,8 +294,8 @@ procdesc_free(struct procdesc *pd)
 	if (refcount_release(&pd->pd_refcount)) {
 		KASSERT(pd->pd_proc == NULL,
 		    ("procdesc_free: pd_proc != NULL"));
-		KASSERT((pd->pd_flags & PDF_CLOSED),
-		    ("procdesc_free: !PDF_CLOSED"));
+		KASSERT(pd->pd_fpcount == 0,
+		    ("procdesc_free: not closed %p %d", pd, pd->pd_fpcount));
 
 		if (pd->pd_pid != -1)
 			proc_id_clear(PROC_ID_PID, pd->pd_pid);
@@ -322,7 +323,7 @@ procdesc_exit(struct proc *p)
 	pd = p->p_procdesc;
 
 	PROCDESC_LOCK(pd);
-	KASSERT((pd->pd_flags & PDF_CLOSED) == 0 || p->p_pptr == p->p_reaper,
+	KASSERT(pd->pd_fpcount > 0 || p->p_pptr == p->p_reaper,
 	    ("procdesc_exit: closed && parent not reaper"));
 
 	pd->pd_flags |= PDF_EXITED;
@@ -334,7 +335,7 @@ procdesc_exit(struct proc *p)
 	 * Clean up the procdesc now rather than letting it happen during
 	 * that reap.
 	 */
-	if (pd->pd_flags & PDF_CLOSED) {
+	if (pd->pd_fpcount == 0) {
 		PROCDESC_UNLOCK(pd);
 		pd->pd_proc = NULL;
 		p->p_procdesc = NULL;
@@ -388,7 +389,8 @@ procdesc_close(struct file *fp, struct thread *td)
 
 	sx_xlock(&proctree_lock);
 	PROCDESC_LOCK(pd);
-	pd->pd_flags |= PDF_CLOSED;
+	MPASS(pd->pd_fpcount > 0);
+	pd->pd_fpcount--;
 	PROCDESC_UNLOCK(pd);
 	p = pd->pd_proc;
 	if (p == NULL) {
@@ -408,7 +410,7 @@ procdesc_close(struct file *fp, struct thread *td)
 			 * calls back into procdesc_reap().
 			 */
 			proc_reap(curthread, p, NULL, 0);
-		} else {
+		} else if (pd->pd_fpcount == 0) /* last procdesc */ {
 			/*
 			 * If the process is not yet dead, we need to kill it,
 			 * but we can't wait around synchronously for it to go
@@ -438,6 +440,9 @@ procdesc_close(struct file *fp, struct thread *td)
 				kern_psignal(p, SIGKILL);
 			PROC_UNLOCK(p);
 			sx_xunlock(&proctree_lock);
+		} else {
+			PROC_UNLOCK(p);
+			sx_xunlock(&proctree_lock);
 		}
 	}
 
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
index a6be5dbe576c..08b563828b95 100644
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -51,6 +51,8 @@
  * (r) - Atomic reference count.
  * (s) - Protected by selinfo.
  * (t) - Protected by the proctree_lock
+ * (p|t) - Both procree_lock and process descriptor must be locked
+ *	 for pd_fpcount
  */
 struct proc;
 struct sigio;
@@ -63,6 +65,7 @@ struct procdesc {
 	struct proc	*pd_proc;		/* (t) Process. */
 	pid_t		 pd_pid;		/* (c) Cached pid. */
 	u_int		 pd_refcount;		/* (r) Reference count. */
+	u_int		 pd_fpcount;		/* (p|t) files referencing me */
 
 	/*
 	 * In-flight data and notification of events.
@@ -85,7 +88,6 @@ struct procdesc {
 /*
  * Flags for the pd_flags field.
  */
-#define	PDF_CLOSED	0x00000001	/* Descriptor has closed. */
 #define	PDF_EXITED	0x00000004	/* Process exited. */
 #define	PDF_DAEMON	0x00000008	/* Don't exit when procdesc closes. */