summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/proc/prvnops.c
diff options
context:
space:
mode:
authorAndy Fiddaman <omnios@citrus-it.co.uk>2019-11-19 11:04:46 +0000
committerAndy Fiddaman <omnios@citrus-it.co.uk>2020-01-24 08:04:05 +0000
commita02120c4550735e4c33259ff2671a5ef9d06c5cc (patch)
treeb3e98992c422f4688a44e7e76ffee23c0c92c7fb /usr/src/uts/common/fs/proc/prvnops.c
parente3bf7d5a53699b06ef4e776789b585322c4bf8ed (diff)
downloadillumos-gate-a02120c4550735e4c33259ff2671a5ef9d06c5cc.tar.gz
12046 Provide /proc/<PID>/fdinfo/
Reviewed by: John Levon <john.levon@joyent.com> Reviewed by: Robert Mustacchi <rm@fingolfin.org> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/uts/common/fs/proc/prvnops.c')
-rw-r--r--usr/src/uts/common/fs/proc/prvnops.c302
1 files changed, 246 insertions, 56 deletions
diff --git a/usr/src/uts/common/fs/proc/prvnops.c b/usr/src/uts/common/fs/proc/prvnops.c
index 2cf007c42c..a324181683 100644
--- a/usr/src/uts/common/fs/proc/prvnops.c
+++ b/usr/src/uts/common/fs/proc/prvnops.c
@@ -23,6 +23,7 @@
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
* Copyright (c) 2017 by Delphix. All rights reserved.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -154,20 +155,22 @@ static prdirent_t piddir[] = {
"root" },
{ PR_FDDIR, 21 * sizeof (prdirent_t), sizeof (prdirent_t),
"fd" },
- { PR_OBJECTDIR, 22 * sizeof (prdirent_t), sizeof (prdirent_t),
+ { PR_FDINFODIR, 22 * sizeof (prdirent_t), sizeof (prdirent_t),
+ "fdinfo" },
+ { PR_OBJECTDIR, 23 * sizeof (prdirent_t), sizeof (prdirent_t),
"object" },
- { PR_LWPDIR, 23 * sizeof (prdirent_t), sizeof (prdirent_t),
+ { PR_LWPDIR, 24 * sizeof (prdirent_t), sizeof (prdirent_t),
"lwp" },
- { PR_PRIV, 24 * sizeof (prdirent_t), sizeof (prdirent_t),
+ { PR_PRIV, 25 * sizeof (prdirent_t), sizeof (prdirent_t),
"priv" },
- { PR_PATHDIR, 25 * sizeof (prdirent_t), sizeof (prdirent_t),
+ { PR_PATHDIR, 26 * sizeof (prdirent_t), sizeof (prdirent_t),
"path" },
- { PR_CTDIR, 26 * sizeof (prdirent_t), sizeof (prdirent_t),
+ { PR_CTDIR, 27 * sizeof (prdirent_t), sizeof (prdirent_t),
"contracts" },
- { PR_SECFLAGS, 27 * sizeof (prdirent_t), sizeof (prdirent_t),
+ { PR_SECFLAGS, 28 * sizeof (prdirent_t), sizeof (prdirent_t),
"secflags" },
#if defined(__x86)
- { PR_LDT, 28 * sizeof (prdirent_t), sizeof (prdirent_t),
+ { PR_LDT, 29 * sizeof (prdirent_t), sizeof (prdirent_t),
"ldt" },
#endif
};
@@ -596,7 +599,8 @@ static int pr_read_inval(), pr_read_as(), pr_read_status(),
#if defined(__sparc)
pr_read_gwindows(), pr_read_asrs(),
#endif
- pr_read_piddir(), pr_read_pidfile(), pr_read_opagedata();
+ pr_read_piddir(), pr_read_pidfile(), pr_read_opagedata(),
+ pr_read_fdinfo();
static int (*pr_read_function[PR_NFILES])() = {
pr_read_inval, /* /proc */
@@ -625,6 +629,8 @@ static int (*pr_read_function[PR_NFILES])() = {
pr_read_inval, /* /proc/<pid>/root */
pr_read_inval, /* /proc/<pid>/fd */
pr_read_inval, /* /proc/<pid>/fd/nn */
+ pr_read_inval, /* /proc/<pid>/fdinfo */
+ pr_read_fdinfo, /* /proc/<pid>/fdinfo/nn */
pr_read_inval, /* /proc/<pid>/object */
pr_read_inval, /* /proc/<pid>/object/xxx */
pr_read_inval, /* /proc/<pid>/lwp */
@@ -813,6 +819,95 @@ pr_read_psinfo(prnode_t *pnp, uio_t *uiop)
}
static int
+pr_read_fdinfo(prnode_t *pnp, uio_t *uiop)
+{
+ prfdinfo_t *fdinfo;
+ list_t data;
+ proc_t *p;
+ vnode_t *vp;
+ uint_t fd;
+ file_t *fp;
+ cred_t *cred;
+ short ufp_flag;
+ int error = 0;
+
+ ASSERT(pnp->pr_type == PR_FDINFO);
+
+ /*
+ * This is a guess at the size of the structure that needs to
+ * be returned. It's a balance between not allocating too much more
+ * space than is required and not requiring too many subsequent
+ * reallocations. Allocate it before acquiring the process lock.
+ */
+ pr_iol_initlist(&data, sizeof (prfdinfo_t) + MAXPATHLEN + 2, 1);
+
+ if ((error = prlock(pnp, ZNO)) != 0) {
+ pr_iol_freelist(&data);
+ return (error);
+ }
+
+ p = pnp->pr_common->prc_proc;
+
+ if ((p->p_flag & SSYS) || p->p_as == &kas) {
+ prunlock(pnp);
+ pr_iol_freelist(&data);
+ return (0);
+ }
+
+ fd = pnp->pr_index;
+
+ /* Fetch and lock the file_t for this descriptor */
+ fp = pr_getf(p, fd, &ufp_flag);
+
+ if (fp == NULL) {
+ error = ENOENT;
+ prunlock(pnp);
+ goto out;
+ }
+
+ vp = fp->f_vnode;
+ VN_HOLD(vp);
+
+ /*
+ * For fdinfo, we don't want to include the placeholder pr_misc at the
+ * end of the struct. We'll terminate the data with an empty pr_misc
+ * header before returning.
+ */
+
+ fdinfo = pr_iol_newbuf(&data, offsetof(prfdinfo_t, pr_misc));
+ fdinfo->pr_fd = fd;
+ fdinfo->pr_fdflags = ufp_flag;
+ /* FEPOLLED on f_flag2 should never be user-visible */
+ fdinfo->pr_fileflags = (fp->f_flag2 & ~FEPOLLED) << 16 | fp->f_flag;
+ if ((fdinfo->pr_fileflags & (FSEARCH | FEXEC)) == 0)
+ fdinfo->pr_fileflags += FOPEN;
+ fdinfo->pr_offset = fp->f_offset;
+ cred = fp->f_cred;
+ crhold(cred);
+ /*
+ * Information from the vnode (rather than the file_t) is retrieved
+ * later, in prgetfdinfo() - for example sock_getfasync()
+ */
+ pr_releasef(p, fd);
+
+ prunlock(pnp);
+
+ error = prgetfdinfo(p, vp, fdinfo, cred, &data);
+
+ crfree(cred);
+
+ VN_RELE(vp);
+
+out:
+ if (error == 0)
+ error = pr_iol_uiomove_and_free(&data, uiop, error);
+ else
+ pr_iol_freelist(&data);
+
+ return (error);
+}
+
+static int
pr_read_lpsinfo(prnode_t *pnp, uio_t *uiop)
{
proc_t *p;
@@ -1835,6 +1930,8 @@ static int (*pr_read_function_32[PR_NFILES])() = {
pr_read_inval, /* /proc/<pid>/root */
pr_read_inval, /* /proc/<pid>/fd */
pr_read_inval, /* /proc/<pid>/fd/nn */
+ pr_read_inval, /* /proc/<pid>/fdinfo */
+ pr_read_fdinfo, /* /proc/<pid>/fdinfo/nn */
pr_read_inval, /* /proc/<pid>/object */
pr_read_inval, /* /proc/<pid>/object/xxx */
pr_read_inval, /* /proc/<pid>/lwp */
@@ -3080,9 +3177,29 @@ prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
vap->va_size = 0;
break;
case PR_FDDIR:
+ case PR_FDINFODIR:
vap->va_nlink = 2;
vap->va_size = (P_FINFO(p)->fi_nfiles + 2) * PRSDSIZE;
break;
+ case PR_FDINFO: {
+ file_t *fp;
+ vnode_t *vp;
+ int fd = pnp->pr_index;
+
+ fp = pr_getf(p, fd, NULL);
+ if (fp == NULL) {
+ prunlock(pnp);
+ return (ENOENT);
+ }
+ vp = fp->f_vnode;
+ VN_HOLD(vp);
+ pr_releasef(p, fd);
+ prunlock(pnp);
+ vap->va_size = prgetfdinfosize(p, vp, cr);
+ VN_RELE(vp);
+ vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
+ return (0);
+ }
case PR_LWPDIR:
/*
* va_nlink: count each lwp as a directory link.
@@ -3407,8 +3524,8 @@ praccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
*/
static vnode_t *pr_lookup_notdir(), *pr_lookup_procdir(), *pr_lookup_piddir(),
*pr_lookup_objectdir(), *pr_lookup_lwpdir(), *pr_lookup_lwpiddir(),
- *pr_lookup_fddir(), *pr_lookup_pathdir(), *pr_lookup_tmpldir(),
- *pr_lookup_ctdir();
+ *pr_lookup_fddir(), *pr_lookup_fdinfodir(), *pr_lookup_pathdir(),
+ *pr_lookup_tmpldir(), *pr_lookup_ctdir();
static vnode_t *(*pr_lookup_function[PR_NFILES])() = {
pr_lookup_procdir, /* /proc */
@@ -3437,6 +3554,8 @@ static vnode_t *(*pr_lookup_function[PR_NFILES])() = {
pr_lookup_notdir, /* /proc/<pid>/root */
pr_lookup_fddir, /* /proc/<pid>/fd */
pr_lookup_notdir, /* /proc/<pid>/fd/nn */
+ pr_lookup_fdinfodir, /* /proc/<pid>/fdinfo */
+ pr_lookup_notdir, /* /proc/<pid>/fdinfo/nn */
pr_lookup_objectdir, /* /proc/<pid>/object */
pr_lookup_notdir, /* /proc/<pid>/object/xxx */
pr_lookup_lwpdir, /* /proc/<pid>/lwp */
@@ -3524,7 +3643,8 @@ prlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
break;
}
- if ((type == PR_OBJECTDIR || type == PR_FDDIR || type == PR_PATHDIR) &&
+ if ((type == PR_OBJECTDIR || type == PR_FDDIR ||
+ type == PR_FDINFODIR || type == PR_PATHDIR) &&
(error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
return (error);
@@ -4138,8 +4258,6 @@ pr_lookup_fddir(vnode_t *dp, char *comp)
file_t *fp;
uint_t fd;
int c;
- uf_entry_t *ufp;
- uf_info_t *fip;
ASSERT(dpnp->pr_type == PR_FDDIR);
@@ -4149,8 +4267,8 @@ pr_lookup_fddir(vnode_t *dp, char *comp)
if (c < '0' || c > '9')
return (NULL);
ofd = fd;
- fd = 10*fd + c - '0';
- if (fd/10 != ofd) /* integer overflow */
+ fd = 10 * fd + c - '0';
+ if (fd / 10 != ofd) /* integer overflow */
return (NULL);
}
@@ -4167,49 +4285,98 @@ pr_lookup_fddir(vnode_t *dp, char *comp)
return (NULL);
}
- fip = P_FINFO(p);
- mutex_exit(&p->p_lock);
- mutex_enter(&fip->fi_lock);
- if (fd < fip->fi_nfiles) {
- UF_ENTER(ufp, fip, fd);
- if ((fp = ufp->uf_file) != NULL) {
- pnp->pr_mode = 07111;
- if (fp->f_flag & FREAD)
- pnp->pr_mode |= 0444;
- if (fp->f_flag & FWRITE)
- pnp->pr_mode |= 0222;
- vp = fp->f_vnode;
- VN_HOLD(vp);
- }
- UF_EXIT(ufp);
+ if ((fp = pr_getf(p, fd, NULL)) != NULL) {
+ pnp->pr_mode = 07111;
+ if (fp->f_flag & FREAD)
+ pnp->pr_mode |= 0444;
+ if (fp->f_flag & FWRITE)
+ pnp->pr_mode |= 0222;
+ vp = fp->f_vnode;
+ VN_HOLD(vp);
+ pr_releasef(p, fd);
}
- mutex_exit(&fip->fi_lock);
- mutex_enter(&p->p_lock);
+
prunlock(dpnp);
- if (vp == NULL)
+ if (vp == NULL) {
prfreenode(pnp);
- else {
- /*
- * Fill in the prnode so future references will
- * be able to find the underlying object's vnode.
- * Don't link this prnode into the list of all
- * prnodes for the process; this is a one-use node.
- */
- pnp->pr_realvp = vp;
- pnp->pr_parent = dp; /* needed for prlookup */
- VN_HOLD(dp);
- vp = PTOV(pnp);
- if (pnp->pr_realvp->v_type == VDIR) {
- vp->v_type = VDIR;
- vp->v_flag |= VTRAVERSE;
- }
+ return (NULL);
+ }
+
+ /*
+ * Fill in the prnode so future references will
+ * be able to find the underlying object's vnode.
+ * Don't link this prnode into the list of all
+ * prnodes for the process; this is a one-use node.
+ */
+ pnp->pr_realvp = vp;
+ pnp->pr_parent = dp; /* needed for prlookup */
+ VN_HOLD(dp);
+ vp = PTOV(pnp);
+ if (pnp->pr_realvp->v_type == VDIR) {
+ vp->v_type = VDIR;
+ vp->v_flag |= VTRAVERSE;
}
return (vp);
}
static vnode_t *
+pr_lookup_fdinfodir(vnode_t *dp, char *comp)
+{
+ prnode_t *dpnp = VTOP(dp);
+ prnode_t *pnp;
+ vnode_t *vp = NULL;
+ proc_t *p;
+ uint_t fd;
+ int c;
+
+ ASSERT(dpnp->pr_type == PR_FDINFODIR);
+
+ fd = 0;
+ while ((c = *comp++) != '\0') {
+ int ofd;
+ if (c < '0' || c > '9')
+ return (NULL);
+ ofd = fd;
+ fd = 10 * fd + c - '0';
+ if (fd / 10 != ofd) /* integer overflow */
+ return (NULL);
+ }
+
+ pnp = prgetnode(dp, PR_FDINFO);
+
+ if (prlock(dpnp, ZNO) != 0) {
+ prfreenode(pnp);
+ return (NULL);
+ }
+ p = dpnp->pr_common->prc_proc;
+ if ((p->p_flag & SSYS) || p->p_as == &kas) {
+ prunlock(dpnp);
+ prfreenode(pnp);
+ return (NULL);
+ }
+
+ /*
+ * Don't link this prnode into the list of all
+ * prnodes for the process; this is a one-use node.
+ * Unlike the FDDIR case, the underlying vnode is not stored in
+ * pnp->pr_realvp. Instead, the fd number is stored in pnp->pr_index
+ * and used by pr_read_fdinfo() to return information for the right
+ * file descriptor.
+ */
+ pnp->pr_common = dpnp->pr_common;
+ pnp->pr_pcommon = dpnp->pr_pcommon;
+ pnp->pr_parent = dp;
+ pnp->pr_index = fd;
+ VN_HOLD(dp);
+ prunlock(dpnp);
+ vp = PTOV(pnp);
+
+ return (vp);
+}
+
+static vnode_t *
pr_lookup_pathdir(vnode_t *dp, char *comp)
{
prnode_t *dpnp = VTOP(dp);
@@ -4667,6 +4834,7 @@ prgetnode(vnode_t *dp, prnodetype_t type)
case PR_CURDIR:
case PR_ROOTDIR:
case PR_FDDIR:
+ case PR_FDINFODIR:
case PR_OBJECTDIR:
case PR_PATHDIR:
case PR_CTDIR:
@@ -4799,8 +4967,8 @@ prfreecommon(prcommon_t *pcp)
*/
static int pr_readdir_notdir(), pr_readdir_procdir(), pr_readdir_piddir(),
pr_readdir_objectdir(), pr_readdir_lwpdir(), pr_readdir_lwpiddir(),
- pr_readdir_fddir(), pr_readdir_pathdir(), pr_readdir_tmpldir(),
- pr_readdir_ctdir();
+ pr_readdir_fddir(), pr_readdir_fdinfodir(), pr_readdir_pathdir(),
+ pr_readdir_tmpldir(), pr_readdir_ctdir();
static int (*pr_readdir_function[PR_NFILES])() = {
pr_readdir_procdir, /* /proc */
@@ -4829,6 +4997,8 @@ static int (*pr_readdir_function[PR_NFILES])() = {
pr_readdir_notdir, /* /proc/<pid>/root */
pr_readdir_fddir, /* /proc/<pid>/fd */
pr_readdir_notdir, /* /proc/<pid>/fd/nn */
+ pr_readdir_fdinfodir, /* /proc/<pid>/fdinfo */
+ pr_readdir_notdir, /* /proc/<pid>/fdinfo/nn */
pr_readdir_objectdir, /* /proc/<pid>/object */
pr_readdir_notdir, /* /proc/<pid>/object/xxx */
pr_readdir_lwpdir, /* /proc/<pid>/lwp */
@@ -5361,9 +5531,12 @@ out:
return (0);
}
-/* ARGSUSED */
+/*
+ * Helper function for reading a directory which lists open file desciptors
+ */
static int
-pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
+pr_readdir_fdlist(prnode_t *pnp, uio_t *uiop, int *eofp,
+ prnodetype_t dirtype, prnodetype_t entrytype)
{
gfs_readdir_state_t gstate;
int error, eof = 0;
@@ -5373,8 +5546,6 @@ pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
int fddirsize;
uf_info_t *fip;
- ASSERT(pnp->pr_type == PR_FDDIR);
-
if ((error = prlock(pnp, ZNO)) != 0)
return (error);
p = pnp->pr_common->prc_proc;
@@ -5383,7 +5554,7 @@ pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
mutex_exit(&p->p_lock);
if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
- pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_FDDIR), 0)) != 0) {
+ pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, dirtype), 0)) != 0) {
mutex_enter(&p->p_lock);
prunlock(pnp);
return (error);
@@ -5414,7 +5585,7 @@ pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
}
error = gfs_readdir_emitn(&gstate, uiop, n,
- pmkino(n, pslot, PR_FD), n);
+ pmkino(n, pslot, entrytype), n);
if (error)
break;
}
@@ -5426,6 +5597,24 @@ pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
return (gfs_readdir_fini(&gstate, error, eofp, eof));
}
+static int
+pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
+{
+
+ ASSERT(pnp->pr_type == PR_FDDIR);
+
+ return (pr_readdir_fdlist(pnp, uiop, eofp, pnp->pr_type, PR_FD));
+}
+
+static int
+pr_readdir_fdinfodir(prnode_t *pnp, uio_t *uiop, int *eofp)
+{
+
+ ASSERT(pnp->pr_type == PR_FDINFODIR);
+
+ return (pr_readdir_fdlist(pnp, uiop, eofp, pnp->pr_type, PR_FDINFO));
+}
+
/* ARGSUSED */
static int
pr_readdir_pathdir(prnode_t *pnp, uio_t *uiop, int *eofp)
@@ -5735,6 +5924,7 @@ prinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
switch (type) {
case PR_OBJECT:
case PR_FD:
+ case PR_FDINFO:
case PR_SELF:
case PR_PATH:
/* These are not linked into the usual lists */