diff options
author | Andy Fiddaman <omnios@citrus-it.co.uk> | 2019-11-19 11:04:46 +0000 |
---|---|---|
committer | Andy Fiddaman <omnios@citrus-it.co.uk> | 2020-01-24 08:04:05 +0000 |
commit | a02120c4550735e4c33259ff2671a5ef9d06c5cc (patch) | |
tree | b3e98992c422f4688a44e7e76ffee23c0c92c7fb /usr/src/uts/common/fs/proc/prvnops.c | |
parent | e3bf7d5a53699b06ef4e776789b585322c4bf8ed (diff) | |
download | illumos-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.c | 302 |
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 */ |