svn commit: r279335 - in user/dchagin/lemul/sys: compat/linprocfs fs/procfs fs/pseudofs modules/procfs

Dmitry Chagin dchagin at FreeBSD.org
Thu Feb 26 21:30:44 UTC 2015


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 <sys/conf.h>
 #include <sys/exec.h>
 #include <sys/fcntl.h>
+#include <sys/file.h>
 #include <sys/filedesc.h>
 #include <sys/jail.h>
 #include <sys/kernel.h>
@@ -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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/vnode.h>
+#include <sys/uio.h>
+
+#include <fs/pseudofs/pseudofs.h>
+#include <fs/procfs/procfs.h>
+
+
+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 <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/systm.h>
+#include <sys/capsicum.h>
 #include <sys/ctype.h>
 #include <sys/dirent.h>
 #include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
@@ -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:


More information about the svn-src-user mailing list