diff options
Diffstat (limited to 'usr/src/uts/common/fs/proc/prsubr.c')
-rw-r--r-- | usr/src/uts/common/fs/proc/prsubr.c | 49 |
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) { |