summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/proc/prsubr.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/fs/proc/prsubr.c')
-rw-r--r--usr/src/uts/common/fs/proc/prsubr.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/usr/src/uts/common/fs/proc/prsubr.c b/usr/src/uts/common/fs/proc/prsubr.c
index 34e9c730f5..be41826b54 100644
--- a/usr/src/uts/common/fs/proc/prsubr.c
+++ b/usr/src/uts/common/fs/proc/prsubr.c
@@ -24,6 +24,7 @@
* Copyright 2019 Joyent, Inc.
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
* Copyright 2022 MNX Cloud, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -1622,6 +1623,54 @@ retry:
return (fp);
}
+
+/*
+ * Just as pr_getf() is a little unusual in how it goes about making the file_t
+ * safe for procfs consumers to access it, so too is pr_releasef() for safely
+ * releasing that "hold". The "hold" is unlike normal file descriptor activity
+ * -- procfs is just an interloper here, wanting access to the vnode_t without
+ * risk of a racing close() disrupting the state. Just as pr_getf() avoids some
+ * of the typical file_t behavior (such as auditing) when establishing its hold,
+ * so too should pr_releasef(). It should not go through the motions of
+ * closef() (since it is not a true close()) unless racing activity causes it to
+ * be the last actor holding the refcount above zero.
+ *
+ * Under normal circumstances, we expect to find file_t`f_count > 1 after
+ * the successful pr_getf() call. We are, after all, accessing a resource
+ * already held by the process in question. We would also expect to rarely race
+ * with a close() of the underlying fd, meaning that file_t`f_count > 1 would
+ * still holds at pr_releasef() time. That would mean we only need to decrement
+ * f_count, leaving it to the process to later close the fd (thus triggering
+ * VOP_CLOSE(), etc).
+ *
+ * It is only when that process manages to close() the fd while we have it
+ * "held" in procfs that we must make a trip through the traditional closef()
+ * logic to ensure proper tear-down of the file_t.
+ */
+void
+pr_releasef(file_t *fp)
+{
+ mutex_enter(&fp->f_tlock);
+ if (fp->f_count > 1) {
+ /*
+ * This is the most common case: The file is still held open by
+ * the process, and we simply need to release our hold by
+ * decrementing f_count
+ */
+ fp->f_count--;
+ mutex_exit(&fp->f_tlock);
+ } else {
+ /*
+ * A rare occasion: The process snuck a close() of this file
+ * while we were doing our business in procfs. Given that
+ * f_count == 1, we are the only one with a reference to the
+ * file_t and need to take a trip through closef() to free it.
+ */
+ mutex_exit(&fp->f_tlock);
+ (void) closef(fp);
+ }
+}
+
void
pr_object_name(char *name, vnode_t *vp, struct vattr *vattr)
{