From owner-svn-src-user@FreeBSD.ORG Thu Feb 26 21:30:44 2015 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id A1BEB70F; Thu, 26 Feb 2015 21:30:44 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 8ADA1A5C; Thu, 26 Feb 2015 21:30:44 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t1QLUi3o027965; Thu, 26 Feb 2015 21:30:44 GMT (envelope-from dchagin@FreeBSD.org) Received: (from dchagin@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t1QLUfwf027872; Thu, 26 Feb 2015 21:30:41 GMT (envelope-from dchagin@FreeBSD.org) Message-Id: <201502262130.t1QLUfwf027872@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: dchagin set sender to dchagin@FreeBSD.org using -f From: Dmitry Chagin Date: Thu, 26 Feb 2015 21:30:41 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r279335 - in user/dchagin/lemul/sys: compat/linprocfs fs/procfs fs/pseudofs modules/procfs X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 26 Feb 2015 21:30:44 -0000 Author: dchagin Date: Thu Feb 26 21:30:40 2015 New Revision: 279335 URL: https://svnweb.freebsd.org/changeset/base/279335 Log: Add preliminary support of /proc/[pid]/fd. On Linux this is a subdirectory containing one entry for each file which the process has open, named by its file descriptor, and which is a symbolic link to the actual file. For now only regular file descriptors are supported. Added: user/dchagin/lemul/sys/fs/procfs/procfs_fdlink.c (contents, props changed) Modified: user/dchagin/lemul/sys/compat/linprocfs/linprocfs.c user/dchagin/lemul/sys/fs/procfs/procfs.c user/dchagin/lemul/sys/fs/procfs/procfs.h user/dchagin/lemul/sys/fs/pseudofs/pseudofs.c user/dchagin/lemul/sys/fs/pseudofs/pseudofs.h user/dchagin/lemul/sys/fs/pseudofs/pseudofs_fileno.c user/dchagin/lemul/sys/fs/pseudofs/pseudofs_internal.h user/dchagin/lemul/sys/fs/pseudofs/pseudofs_vncache.c user/dchagin/lemul/sys/fs/pseudofs/pseudofs_vnops.c user/dchagin/lemul/sys/modules/procfs/Makefile Modified: user/dchagin/lemul/sys/compat/linprocfs/linprocfs.c ============================================================================== --- user/dchagin/lemul/sys/compat/linprocfs/linprocfs.c Thu Feb 26 21:15:02 2015 (r279334) +++ user/dchagin/lemul/sys/compat/linprocfs/linprocfs.c Thu Feb 26 21:30:40 2015 (r279335) @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -1351,21 +1352,6 @@ linprocfs_domodules(PFS_FILL_ARGS) #endif /* - * Filler function for proc/pid/fd - */ -static int -linprocfs_dofdescfs(PFS_FILL_ARGS) -{ - - if (p == curproc) - sbuf_printf(sb, "/dev/fd"); - else - sbuf_printf(sb, "unknown"); - return (0); -} - - -/* * Filler function for proc/sys/kernel/random/uuid */ static int @@ -1498,10 +1484,11 @@ linprocfs_init(PFS_INIT_ARGS) NULL, NULL, NULL, PFS_RD); pfs_create_file(dir, "status", &linprocfs_doprocstatus, NULL, NULL, NULL, PFS_RD); - pfs_create_link(dir, "fd", &linprocfs_dofdescfs, - NULL, NULL, NULL, 0); pfs_create_file(dir, "auxv", &linprocfs_doauxv, NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD); + dir = pfs_create_dir(dir, "fd", NULL, NULL, NULL, 0); + pfs_create_link(dir, "---", &procfs_dofdlink, + NULL, &procfs_candebug, NULL, PFS_PROCFDDEP); /* /proc/scsi/... */ dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); Modified: user/dchagin/lemul/sys/fs/procfs/procfs.c ============================================================================== --- user/dchagin/lemul/sys/fs/procfs/procfs.c Thu Feb 26 21:15:02 2015 (r279334) +++ user/dchagin/lemul/sys/fs/procfs/procfs.c Thu Feb 26 21:30:40 2015 (r279335) @@ -196,6 +196,10 @@ procfs_init(PFS_INIT_ARGS) pfs_create_link(dir, "file", procfs_doprocfile, NULL, procfs_notsystem, NULL, 0); + dir = pfs_create_dir(dir, "fd", NULL, NULL, NULL, 0); + pfs_create_link(dir, "---", &procfs_dofdlink, + NULL, procfs_candebug, NULL, PFS_PROCFDDEP); + return (0); } Modified: user/dchagin/lemul/sys/fs/procfs/procfs.h ============================================================================== --- user/dchagin/lemul/sys/fs/procfs/procfs.h Thu Feb 26 21:15:02 2015 (r279334) +++ user/dchagin/lemul/sys/fs/procfs/procfs.h Thu Feb 26 21:30:40 2015 (r279335) @@ -39,6 +39,7 @@ #ifdef _KERNEL int procfs_docurproc(PFS_FILL_ARGS); +int procfs_dofdlink(PFS_FILL_ARGS); int procfs_doosrel(PFS_FILL_ARGS); int procfs_doproccmdline(PFS_FILL_ARGS); int procfs_doprocctl(PFS_FILL_ARGS); Added: user/dchagin/lemul/sys/fs/procfs/procfs_fdlink.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/dchagin/lemul/sys/fs/procfs/procfs_fdlink.c Thu Feb 26 21:30:40 2015 (r279335) @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2015 Dmitry Chagin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +int +procfs_dofdlink(PFS_FILL_ARGS) +{ + char *fullpath, *freepath, *endfileno; + struct filedesc *fdp; + struct vnode *vp; + struct file *fp; + int fileno, error; + + if (vnode_name == NULL) + return (ENOENT); + + fileno = (int)strtol(vnode_name, &endfileno, 10); + if (fileno == 0 && (vnode_namelen > 1 || + (vnode_namelen == 1 && vnode_name[0] != '0'))) + return (ENOENT); + if (vnode_namelen != endfileno - vnode_name) + return (ENOENT); + + fdp = fdhold(p); + if (fdp == NULL) + return (ENOENT); + + error = fget_unlocked(fdp, fileno, NULL, &fp, NULL); + if (error != 0) + goto out; + + freepath = NULL; + fullpath = "-"; + vp = fp->f_vnode; + if (vp != NULL) { + vref(vp); + error = vn_fullpath(td, vp, &fullpath, &freepath); + vrele(vp); + } + if (error == 0) + error = sbuf_printf(sb, "%s", fullpath); + if (freepath != NULL) + free(freepath, M_TEMP); + fdrop(fp, td); + + out: + fddrop(fdp); + return (error); +} Modified: user/dchagin/lemul/sys/fs/pseudofs/pseudofs.c ============================================================================== --- user/dchagin/lemul/sys/fs/pseudofs/pseudofs.c Thu Feb 26 21:15:02 2015 (r279334) +++ user/dchagin/lemul/sys/fs/pseudofs/pseudofs.c Thu Feb 26 21:30:40 2015 (r279335) @@ -222,7 +222,8 @@ pfs_create_link(struct pfs_node *parent, { struct pfs_node *pn; - pn = pfs_alloc_node(parent->pn_info, name, pfstype_symlink); + pn = pfs_alloc_node(parent->pn_info, name, + (flags & PFS_PROCFDDEP) ? pfstype_fdlink : pfstype_symlink); pn->pn_fill = fill; pn->pn_attr = attr; pn->pn_vis = vis; @@ -361,7 +362,7 @@ pfs_root(struct mount *mp, int flags, st struct pfs_info *pi; pi = (struct pfs_info *)mp->mnt_data; - return (pfs_vncache_alloc(mp, vpp, pi->pi_root, NO_PID)); + return (pfs_vncache_alloc(mp, vpp, pi->pi_root, NO_PID, NULL, 0)); } /* Modified: user/dchagin/lemul/sys/fs/pseudofs/pseudofs.h ============================================================================== --- user/dchagin/lemul/sys/fs/pseudofs/pseudofs.h Thu Feb 26 21:15:02 2015 (r279334) +++ user/dchagin/lemul/sys/fs/pseudofs/pseudofs.h Thu Feb 26 21:30:40 2015 (r279335) @@ -62,7 +62,8 @@ typedef enum { pfstype_parent, pfstype_file, pfstype_symlink, - pfstype_procdir + pfstype_procdir, + pfstype_fdlink } pfs_type_t; /* @@ -75,6 +76,7 @@ typedef enum { #define PFS_RAWWR 0x0008 /* raw writer */ #define PFS_RAW (PFS_RAWRD|PFS_RAWWR) #define PFS_PROCDEP 0x0010 /* process-dependent */ +#define PFS_PROCFDDEP 0x0020 /* process-filedesc-dependent */ /* * Data structures @@ -100,9 +102,10 @@ typedef int (*pfs_init_t)(PFS_INIT_ARGS) */ #define PFS_FILL_ARGS \ struct thread *td, struct proc *p, struct pfs_node *pn, \ - struct sbuf *sb, struct uio *uio + struct sbuf *sb, struct uio *uio, char *vnode_name, \ + int vnode_namelen #define PFS_FILL_ARGNAMES \ - td, p, pn, sb, uio + td, p, pn, sb, uio, vnode_name, vnode_namelen #define PFS_FILL_PROTO(name) \ int name(PFS_FILL_ARGS); typedef int (*pfs_fill_t)(PFS_FILL_ARGS); Modified: user/dchagin/lemul/sys/fs/pseudofs/pseudofs_fileno.c ============================================================================== --- user/dchagin/lemul/sys/fs/pseudofs/pseudofs_fileno.c Thu Feb 26 21:15:02 2015 (r279334) +++ user/dchagin/lemul/sys/fs/pseudofs/pseudofs_fileno.c Thu Feb 26 21:30:40 2015 (r279335) @@ -92,6 +92,7 @@ pfs_fileno_alloc(struct pfs_node *pn) case pfstype_file: case pfstype_symlink: case pfstype_procdir: + case pfstype_fdlink: pn->pn_fileno = alloc_unr(pn->pn_info->pi_unrhdr); break; case pfstype_this: @@ -145,6 +146,7 @@ pfs_fileno_free(struct pfs_node *pn) case pfstype_file: case pfstype_symlink: case pfstype_procdir: + case pfstype_fdlink: free_unr(pn->pn_info->pi_unrhdr, pn->pn_fileno); break; case pfstype_this: Modified: user/dchagin/lemul/sys/fs/pseudofs/pseudofs_internal.h ============================================================================== --- user/dchagin/lemul/sys/fs/pseudofs/pseudofs_internal.h Thu Feb 26 21:15:02 2015 (r279334) +++ user/dchagin/lemul/sys/fs/pseudofs/pseudofs_internal.h Thu Feb 26 21:30:40 2015 (r279335) @@ -43,6 +43,8 @@ struct pfs_vdata { struct pfs_node *pvd_pn; pid_t pvd_pid; struct vnode *pvd_vnode; + char *pvd_vnode_name; + int pvd_vnode_namelen; struct pfs_vdata*pvd_prev, *pvd_next; int pvd_dead:1; }; @@ -53,7 +55,8 @@ struct pfs_vdata { void pfs_vncache_load (void); void pfs_vncache_unload (void); int pfs_vncache_alloc (struct mount *, struct vnode **, - struct pfs_node *, pid_t pid); + struct pfs_node *, pid_t pid, + char *name, int namelen); int pfs_vncache_free (struct vnode *); /* Modified: user/dchagin/lemul/sys/fs/pseudofs/pseudofs_vncache.c ============================================================================== --- user/dchagin/lemul/sys/fs/pseudofs/pseudofs_vncache.c Thu Feb 26 21:15:02 2015 (r279334) +++ user/dchagin/lemul/sys/fs/pseudofs/pseudofs_vncache.c Thu Feb 26 21:30:40 2015 (r279335) @@ -108,13 +108,15 @@ pfs_vncache_unload(void) * Allocate a vnode */ int -pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, - struct pfs_node *pn, pid_t pid) +pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, struct pfs_node *pn, + pid_t pid, char *name, int namelen) { struct pfs_vdata *pvd, *pvd2; struct vnode *vp; int error; + PFS_TRACE(("%s", (name != NULL? name : pn->pn_name))); + /* * See if the vnode is in the cache. * XXX linear search is not very efficient. @@ -124,6 +126,10 @@ retry: for (pvd = pfs_vncache; pvd; pvd = pvd->pvd_next) { if (pvd->pvd_pn == pn && pvd->pvd_pid == pid && pvd->pvd_vnode->v_mount == mp) { + if ((pn->pn_flags & PFS_PROCFDDEP) && + (namelen != pvd->pvd_vnode_namelen || + bcmp(name, pvd->pvd_vnode_name, namelen))) + continue; vp = pvd->pvd_vnode; VI_LOCK(vp); mtx_unlock(&pfs_vncache_mutex); @@ -148,7 +154,7 @@ retry: mtx_unlock(&pfs_vncache_mutex); /* nope, get a new one */ - pvd = malloc(sizeof *pvd, M_PFSVNCACHE, M_WAITOK); + pvd = malloc(sizeof *pvd, M_PFSVNCACHE, M_WAITOK|M_ZERO); pvd->pvd_next = pvd->pvd_prev = NULL; error = getnewvnode("pseudofs", mp, &pfs_vnodeops, vpp); if (error) { @@ -157,6 +163,12 @@ retry: } pvd->pvd_pn = pn; pvd->pvd_pid = pid; + if (name != NULL && namelen > 0) { + pvd->pvd_vnode_name = malloc(namelen + 1, M_PFSVNCACHE, + M_WAITOK); + strlcpy(pvd->pvd_vnode_name, name, namelen + 1); + pvd->pvd_vnode_namelen = namelen; + } (*vpp)->v_data = pvd; switch (pn->pn_type) { case pfstype_root: @@ -175,6 +187,7 @@ retry: (*vpp)->v_type = VREG; break; case pfstype_symlink: + case pfstype_fdlink: (*vpp)->v_type = VLNK; break; case pfstype_none: @@ -207,6 +220,10 @@ retry2: for (pvd2 = pfs_vncache; pvd2; pvd2 = pvd2->pvd_next) { if (pvd2->pvd_pn == pn && pvd2->pvd_pid == pid && pvd2->pvd_vnode->v_mount == mp) { + if ((pn->pn_flags & PFS_PROCFDDEP) && + (namelen != pvd2->pvd_vnode_namelen || + bcmp(name, pvd2->pvd_vnode_name, namelen))) + continue; vp = pvd2->pvd_vnode; VI_LOCK(vp); mtx_unlock(&pfs_vncache_mutex); @@ -243,7 +260,11 @@ pfs_vncache_free(struct vnode *vp) mtx_lock(&pfs_vncache_mutex); pvd = (struct pfs_vdata *)vp->v_data; + KASSERT(pvd != NULL, ("pfs_vncache_free(): no vnode data\n")); + PFS_TRACE(("%s", (pvd->pvd_vnode_name != NULL ? + pvd->pvd_vnode_name : pvd->pvd_pn->pn_name))); + if (pvd->pvd_next) pvd->pvd_next->pvd_prev = pvd->pvd_prev; if (pvd->pvd_prev) { @@ -255,6 +276,8 @@ pfs_vncache_free(struct vnode *vp) } mtx_unlock(&pfs_vncache_mutex); + if (pvd->pvd_vnode_name != NULL) + free(pvd->pvd_vnode_name, M_PFSVNCACHE); free(pvd, M_PFSVNCACHE); vp->v_data = NULL; return (0); Modified: user/dchagin/lemul/sys/fs/pseudofs/pseudofs_vnops.c ============================================================================== --- user/dchagin/lemul/sys/fs/pseudofs/pseudofs_vnops.c Thu Feb 26 21:15:02 2015 (r279334) +++ user/dchagin/lemul/sys/fs/pseudofs/pseudofs_vnops.c Thu Feb 26 21:30:40 2015 (r279335) @@ -34,9 +34,12 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -63,7 +66,8 @@ __FBSDID("$FreeBSD$"); ("%s(): VREG vnode refers to non-file pfs_node", __func__)) #define KASSERT_PN_IS_LINK(pn) \ - KASSERT((pn)->pn_type == pfstype_symlink, \ + KASSERT((pn)->pn_type == pfstype_symlink || \ + (pn)->pn_type == pfstype_fdlink, \ ("%s(): VLNK vnode refers to non-link pfs_node", __func__)) /* @@ -139,7 +143,8 @@ pfs_access(struct vop_access_args *va) struct vattr vattr; int error; - PFS_TRACE(("%s", pvd->pvd_pn->pn_name)); + PFS_TRACE(("%s", (pvd->pvd_vnode_name != NULL ? + pvd->pvd_vnode_name : pvd->pvd_pn->pn_name))); (void)pvd; error = VOP_GETATTR(vn, &vattr, va->a_cred); @@ -229,6 +234,7 @@ pfs_getattr(struct vop_getattr_args *va) break; case pfstype_file: case pfstype_symlink: + case pfstype_fdlink: vap->va_mode = 0444; break; default: @@ -402,7 +408,7 @@ pfs_vptocnp(struct vop_vptocnp_args *ap) locked = VOP_ISLOCKED(vp); VOP_UNLOCK(vp, 0); - error = pfs_vncache_alloc(mp, dvp, pn, pid); + error = pfs_vncache_alloc(mp, dvp, pn, pid, NULL, 0); if (error) { vn_lock(vp, locked | LK_RETRY); vfs_unbusy(mp); @@ -432,10 +438,15 @@ pfs_lookup(struct vop_cachedlookup_args struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pd = pvd->pvd_pn; struct pfs_node *pn, *pdn = NULL; + struct thread *td = curthread; struct mount *mp; + cap_rights_t rights; pid_t pid = pvd->pvd_pid; - char *pname; - int error, i, namelen, visible; + char *pname, *pnameend; + int error, i, namelen, visible, fileno; + struct filedesc *fdp; + struct file *fp; + struct proc *p; PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr)); pfs_assert_not_owned(pd); @@ -519,7 +530,8 @@ pfs_lookup(struct vop_cachedlookup_args /* named node */ for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next) - if (pn->pn_type == pfstype_procdir) + if (pn->pn_type == pfstype_procdir || + pn->pn_type == pfstype_fdlink) pdn = pn; else if (pn->pn_name[namelen] == '\0' && bcmp(pname, pn->pn_name, namelen) == 0) { @@ -528,7 +540,7 @@ pfs_lookup(struct vop_cachedlookup_args } /* process dependent node */ - if ((pn = pdn) != NULL) { + if ((pn = pdn) != NULL && pn->pn_type == pfstype_procdir) { pid = 0; for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i) if ((pid = pid * 10 + pname[i] - '0') > PID_MAX) @@ -539,8 +551,38 @@ pfs_lookup(struct vop_cachedlookup_args } } - pfs_unlock(pd); + /* process filedesc dependent node */ + if ((pn = pdn) != NULL && pn->pn_type == pfstype_fdlink) { + pfs_unlock(pd); + fileno = (int)strtol(pname, &pnameend, 10); + if ((fileno == 0 && (namelen > 1 || + (namelen == 1 && pname[0] != '0'))) || + (namelen != pnameend - pname)) { + goto bad; + } + if ((p = pfind(pid)) == NULL) + goto bad; + fdp = fdhold(p); + if (fdp == NULL) { + PROC_UNLOCK(p); + goto bad; + } + + error = fget_unlocked(fdp, fileno, + cap_rights_init(&rights, CAP_READ), &fp, NULL); + if (error == 0) { + fdrop(fp, td); + fddrop(fdp); + PROC_UNLOCK(p); + goto got_pnode; + } + fddrop(fdp); + PROC_UNLOCK(p); + goto bad; + } + pfs_unlock(pd); + bad: PFS_RETURN (ENOENT); got_pnode: @@ -552,7 +594,7 @@ pfs_lookup(struct vop_cachedlookup_args goto failed; } - error = pfs_vncache_alloc(mp, vpp, pn, pid); + error = pfs_vncache_alloc(mp, vpp, pn, pid, pname, namelen); if (error) goto failed; @@ -648,7 +690,8 @@ pfs_read(struct vop_read_args *va) if (pn->pn_flags & PFS_RAWRD) { PFS_TRACE(("%zd resid", uio->uio_resid)); - error = pn_fill(curthread, proc, pn, NULL, uio); + error = pn_fill(curthread, proc, pn, NULL, uio, + pvd->pvd_vnode_name, pvd->pvd_vnode_namelen); PFS_TRACE(("%zd resid", uio->uio_resid)); goto ret; } @@ -668,7 +711,8 @@ pfs_read(struct vop_read_args *va) goto ret; } - error = pn_fill(curthread, proc, pn, sb, uio); + error = pn_fill(curthread, proc, pn, sb, uio, + pvd->pvd_vnode_name, pvd->pvd_vnode_namelen); if (error) { sbuf_delete(sb); @@ -697,9 +741,11 @@ ret: */ static int pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd, - struct pfs_node **pn, struct proc **p) + struct pfs_node **pn, struct proc **p, struct filedesc **fdp, int *fileno) { - int visible; + struct file *fp; + cap_rights_t rights; + int error, visible; sx_assert(&allproc_lock, SX_SLOCKED); pfs_assert_owned(pd); @@ -707,7 +753,8 @@ pfs_iterate(struct thread *td, struct pr if (*pn == NULL) { /* first node */ *pn = pd->pn_nodes; - } else if ((*pn)->pn_type != pfstype_procdir) { + } else if ((*pn)->pn_type != pfstype_procdir && + (*pn)->pn_type != pfstype_fdlink) { /* next node */ *pn = (*pn)->pn_next; } @@ -723,7 +770,35 @@ pfs_iterate(struct thread *td, struct pr else PROC_LOCK(*p); } + if (*pn != NULL && (*pn)->pn_type == pfstype_fdlink) { + /* Next fileno */ + KASSERT(proc != NULL, + ("%s(): fdlink has no proc", __func__)); + if (*fdp == NULL) { + *fdp = fdhold(proc); + if (*fdp != NULL) + *fileno = -1; + } + while (*fdp != NULL) { + (*fileno) += 1; + if ((*fdp)->fd_nfiles == 0 || + *fileno > (*fdp)->fd_lastfile) { + fddrop(*fdp); + *fdp = NULL; + break; + } + error = fget_unlocked(*fdp, *fileno, + cap_rights_init(&rights, CAP_READ), &fp, NULL); + if (error == 0) { + fdrop(fp, td); + break; + } + } + /* Out of process files: next node */ + if (*fdp == NULL) + *pn = (*pn)->pn_next; + } if ((*pn) == NULL) return (-1); @@ -759,12 +834,13 @@ pfs_readdir(struct vop_readdir_args *va) struct pfs_node *pd = pvd->pvd_pn; pid_t pid = pvd->pvd_pid; struct proc *p, *proc; + struct filedesc *fdp; struct pfs_node *pn; struct uio *uio; struct pfsentry *pfsent, *pfsent2; struct pfsdirentlist lst; off_t offset; - int error, i, resid; + int error, i, resid, fileno; STAILQ_INIT(&lst); error = 0; @@ -799,12 +875,16 @@ pfs_readdir(struct vop_readdir_args *va) KASSERT(pid == NO_PID || proc != NULL, ("%s(): no process for pid %lu", __func__, (unsigned long)pid)); + fdp = NULL; /* skip unwanted entries */ for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) { - if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) { + if (pfs_iterate(curthread, + proc, pd, &pn, &p, &fdp, &fileno) == -1) { /* nothing left... */ if (proc != NULL) PROC_UNLOCK(proc); + if (fdp != NULL) + fddrop(fdp); pfs_unlock(pd); sx_sunlock(&allproc_lock); PFS_RETURN (0); @@ -812,7 +892,7 @@ pfs_readdir(struct vop_readdir_args *va) } /* fill in entries */ - while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 && + while (pfs_iterate(curthread, proc, pd, &pn, &p, &fdp, &fileno) != -1 && resid >= PFS_DELEN) { if ((pfsent = malloc(sizeof(struct pfsentry), M_IOV, M_NOWAIT | M_ZERO)) == NULL) { @@ -822,8 +902,12 @@ pfs_readdir(struct vop_readdir_args *va) pfsent->entry.d_reclen = PFS_DELEN; pfsent->entry.d_fileno = pn_fileno(pn, pid); /* PFS_DELEN was picked to fit PFS_NAMLEN */ - for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i) - pfsent->entry.d_name[i] = pn->pn_name[i]; + + if (pn->pn_type != pfstype_procdir && + pn->pn_type != pfstype_fdlink) + for (i = 0; i < PFS_NAMELEN - 1 && + pn->pn_name[i] != '\0'; ++i) + pfsent->entry.d_name[i] = pn->pn_name[i]; pfsent->entry.d_name[i] = 0; pfsent->entry.d_namlen = i; switch (pn->pn_type) { @@ -842,6 +926,10 @@ pfs_readdir(struct vop_readdir_args *va) case pfstype_file: pfsent->entry.d_type = DT_REG; break; + case pfstype_fdlink: + pfsent->entry.d_namlen = snprintf(pfsent->entry.d_name, + PFS_NAMELEN, "%d", fileno); + /* FALLTHROUGH */ case pfstype_symlink: pfsent->entry.d_type = DT_LNK; break; @@ -855,6 +943,8 @@ pfs_readdir(struct vop_readdir_args *va) } if (proc != NULL) PROC_UNLOCK(proc); + if (fdp != NULL) + fddrop(fdp); pfs_unlock(pd); sx_sunlock(&allproc_lock); i = 0; @@ -883,7 +973,8 @@ pfs_readlink(struct vop_readlink_args *v struct sbuf sb; int error, locked; - PFS_TRACE(("%s", pn->pn_name)); + PFS_TRACE(("%s", (pvd->pvd_vnode_name != NULL ? + pvd->pvd_vnode_name : pn->pn_name))); pfs_assert_not_owned(pn); if (vn->v_type != VLNK) @@ -910,12 +1001,21 @@ pfs_readlink(struct vop_readlink_args *v /* sbuf_new() can't fail with a static buffer */ sbuf_new(&sb, buf, sizeof buf, 0); - error = pn_fill(curthread, proc, pn, &sb, NULL); + error = pn_fill(curthread, proc, pn, &sb, NULL, + pvd->pvd_vnode_name, pvd->pvd_vnode_namelen); if (proc != NULL) PRELE(proc); vn_lock(vn, locked | LK_RETRY); - vdrop(vn); + + /* + * Vgone file descriptor dependent node right after use as + * is not trivial to control file operations from pseudofs + */ + if (pn->pn_flags & PFS_PROCFDDEP) + vgone(vn); + else + vdrop(vn); if (error) { sbuf_delete(&sb); @@ -942,7 +1042,8 @@ pfs_reclaim(struct vop_reclaim_args *va) struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; - PFS_TRACE(("%s", pn->pn_name)); + PFS_TRACE(("%s", (pvd->pvd_vnode_name != NULL ? + pvd->pvd_vnode_name : pn->pn_name))); pfs_assert_not_owned(pn); return (pfs_vncache_free(va->a_vp)); @@ -1003,7 +1104,8 @@ pfs_write(struct vop_write_args *va) } if (pn->pn_flags & PFS_RAWWR) { - error = pn_fill(curthread, proc, pn, NULL, uio); + error = pn_fill(curthread, proc, pn, NULL, uio, + pvd->pvd_vnode_name, pvd->pvd_vnode_namelen); if (proc != NULL) PRELE(proc); PFS_RETURN (error); @@ -1016,7 +1118,8 @@ pfs_write(struct vop_write_args *va) PFS_RETURN (error); } - error = pn_fill(curthread, proc, pn, &sb, uio); + error = pn_fill(curthread, proc, pn, &sb, uio, + pvd->pvd_vnode_name, pvd->pvd_vnode_namelen); sbuf_delete(&sb); if (proc != NULL) Modified: user/dchagin/lemul/sys/modules/procfs/Makefile ============================================================================== --- user/dchagin/lemul/sys/modules/procfs/Makefile Thu Feb 26 21:15:02 2015 (r279334) +++ user/dchagin/lemul/sys/modules/procfs/Makefile Thu Feb 26 21:30:40 2015 (r279335) @@ -8,6 +8,7 @@ SRCS+= opt_compat.h SRCS+= vnode_if.h SRCS+= procfs_ctl.c SRCS+= procfs_dbregs.c +SRCS+= procfs_fdlink.c SRCS+= procfs_fpregs.c SRCS+= procfs_ioctl.c SRCS+= procfs_map.c @@ -27,6 +28,7 @@ EXPORT_SYMS+= procfs_docurproc EXPORT_SYMS+= procfs_doprocfile EXPORT_SYMS+= procfs_doprocmem EXPORT_SYMS+= procfs_notsystem +EXPORT_SYMS+= procfs_dofdlink .if !defined(KERNBUILDDIR) opt_compat.h: