xref: /freebsd/sys/fs/pseudofs/pseudofs_vnops.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
1 /*-
2  * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *	$FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/systm.h>
34 #include <sys/ctype.h>
35 #include <sys/dirent.h>
36 #include <sys/fcntl.h>
37 #include <sys/lock.h>
38 #include <sys/mount.h>
39 #include <sys/mutex.h>
40 #include <sys/namei.h>
41 #include <sys/proc.h>
42 #include <sys/sbuf.h>
43 #include <sys/sx.h>
44 #include <sys/sysctl.h>
45 #include <sys/vnode.h>
46 
47 #include <fs/pseudofs/pseudofs.h>
48 #include <fs/pseudofs/pseudofs_internal.h>
49 
50 #if 0
51 #define PFS_TRACE(foo) \
52 	do { \
53 		printf("pseudofs: %s(): line %d: ", __func__, __LINE__); \
54 		printf foo ; \
55 		printf("\n"); \
56 	} while (0)
57 #define PFS_RETURN(err) \
58 	do { \
59 		printf("pseudofs: %s(): line %d: returning %d\n", \
60 		    __func__, __LINE__, err); \
61 		return (err); \
62 	} while (0)
63 #else
64 #define PFS_TRACE(foo) \
65 	do { /* nothing */ } while (0)
66 #define PFS_RETURN(err) \
67 	return (err)
68 #endif
69 
70 /*
71  * Returns non-zero if given file is visible to given process
72  */
73 static int
74 pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid)
75 {
76 	struct proc *proc;
77 	int r;
78 
79 	PFS_TRACE(("%s (pid: %d, req: %d)",
80 	    pn->pn_name, pid, td->td_proc->p_pid));
81 
82 	if (pn->pn_flags & PFS_DISABLED)
83 		PFS_RETURN (0);
84 
85 	r = 1;
86 	if (pid != NO_PID) {
87 		if ((proc = pfind(pid)) == NULL)
88 			PFS_RETURN (0);
89 		if (p_cansee(td, proc) != 0 ||
90 		    (pn->pn_vis != NULL && !(pn->pn_vis)(td, proc, pn)))
91 			r = 0;
92 		PROC_UNLOCK(proc);
93 	}
94 	PFS_RETURN (r);
95 }
96 
97 /*
98  * Verify permissions
99  */
100 static int
101 pfs_access(struct vop_access_args *va)
102 {
103 	struct vnode *vn = va->a_vp;
104 	struct vattr vattr;
105 	int error;
106 
107 	PFS_TRACE((((struct pfs_vdata *)vn->v_data)->pvd_pn->pn_name));
108 
109 	error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_td);
110 	if (error)
111 		PFS_RETURN (error);
112 	error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid,
113 	    vattr.va_gid, va->a_mode, va->a_cred, NULL);
114 	PFS_RETURN (error);
115 }
116 
117 /*
118  * Close a file or directory
119  */
120 static int
121 pfs_close(struct vop_close_args *va)
122 {
123 	struct vnode *vn = va->a_vp;
124 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
125 	struct pfs_node *pn = pvd->pvd_pn;
126 	struct proc *proc;
127 	int error;
128 
129 	PFS_TRACE((pn->pn_name));
130 
131 	/*
132 	 * Do nothing unless this is the last close and the node has a
133 	 * last-close handler.
134 	 */
135 	if (vrefcnt(vn) > 1 || pn->pn_close == NULL)
136 		PFS_RETURN (0);
137 
138 	if (pvd->pvd_pid != NO_PID)
139 		proc = pfind(pvd->pvd_pid);
140 	else
141 		proc = NULL;
142 
143 	error = (pn->pn_close)(va->a_td, proc, pn);
144 
145 	if (proc != NULL)
146 		PROC_UNLOCK(proc);
147 
148 	PFS_RETURN (error);
149 }
150 
151 /*
152  * Get file attributes
153  */
154 static int
155 pfs_getattr(struct vop_getattr_args *va)
156 {
157 	struct vnode *vn = va->a_vp;
158 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
159 	struct pfs_node *pn = pvd->pvd_pn;
160 	struct vattr *vap = va->a_vap;
161 	struct proc *proc;
162 	int error = 0;
163 
164 	PFS_TRACE((pn->pn_name));
165 
166 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
167 		PFS_RETURN (ENOENT);
168 
169 	VATTR_NULL(vap);
170 	vap->va_type = vn->v_type;
171 	vap->va_fileid = pn->pn_fileno;
172 	vap->va_flags = 0;
173 	vap->va_blocksize = PAGE_SIZE;
174 	vap->va_bytes = vap->va_size = 0;
175 	vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
176 	vap->va_nlink = 1;
177 	nanotime(&vap->va_ctime);
178 	vap->va_atime = vap->va_mtime = vap->va_ctime;
179 
180 	switch (pn->pn_type) {
181 	case pfstype_procdir:
182 	case pfstype_root:
183 	case pfstype_dir:
184 		vap->va_mode = 0555;
185 		break;
186 	case pfstype_file:
187 	case pfstype_symlink:
188 		vap->va_mode = 0444;
189 		break;
190 	default:
191 		printf("shouldn't be here!\n");
192 		vap->va_mode = 0;
193 		break;
194 	}
195 
196 	if (pvd->pvd_pid != NO_PID) {
197 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
198 			PFS_RETURN (ENOENT);
199 		vap->va_uid = proc->p_ucred->cr_ruid;
200 		vap->va_gid = proc->p_ucred->cr_rgid;
201 		if (pn->pn_attr != NULL)
202 			error = (pn->pn_attr)(va->a_td, proc, pn, vap);
203 		PROC_UNLOCK(proc);
204 	} else {
205 		vap->va_uid = 0;
206 		vap->va_gid = 0;
207 	}
208 
209 	PFS_RETURN (error);
210 }
211 
212 /*
213  * Perform an ioctl
214  */
215 static int
216 pfs_ioctl(struct vop_ioctl_args *va)
217 {
218 	struct vnode *vn = va->a_vp;
219 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
220 	struct pfs_node *pn = pvd->pvd_pn;
221 	struct proc *proc = NULL;
222 	int error;
223 
224 	PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
225 
226 	if (vn->v_type != VREG)
227 		PFS_RETURN (EINVAL);
228 
229 	if (pn->pn_ioctl == NULL)
230 		PFS_RETURN (ENOTTY);
231 
232 	/*
233 	 * This is necessary because process' privileges may
234 	 * have changed since the open() call.
235 	 */
236 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
237 		PFS_RETURN (EIO);
238 
239 	/* XXX duplicates bits of pfs_visible() */
240 	if (pvd->pvd_pid != NO_PID) {
241 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
242 			PFS_RETURN (EIO);
243 		_PHOLD(proc);
244 		PROC_UNLOCK(proc);
245 	}
246 
247 	error = (pn->pn_ioctl)(curthread, proc, pn, va->a_command, va->a_data);
248 
249 	if (proc != NULL)
250 		PRELE(proc);
251 
252 	PFS_RETURN (error);
253 }
254 
255 /*
256  * Perform getextattr
257  */
258 static int
259 pfs_getextattr(struct vop_getextattr_args *va)
260 {
261 	struct vnode *vn = va->a_vp;
262 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
263 	struct pfs_node *pn = pvd->pvd_pn;
264 	struct proc *proc = NULL;
265 	int error;
266 
267 	PFS_TRACE((pd->pn_name));
268 
269 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
270 		PFS_RETURN (ENOENT);
271 
272 	if (pn->pn_getextattr == NULL)
273 		PFS_RETURN (EOPNOTSUPP);
274 
275 	/*
276 	 * This is necessary because either process' privileges may
277 	 * have changed since the open() call.
278 	 */
279 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
280 		PFS_RETURN (EIO);
281 
282 	/* XXX duplicates bits of pfs_visible() */
283 	if (pvd->pvd_pid != NO_PID) {
284 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
285 			PFS_RETURN (EIO);
286 		_PHOLD(proc);
287 		PROC_UNLOCK(proc);
288 	}
289 
290 	error = (pn->pn_getextattr)(curthread, proc, pn, va->a_attrnamespace,
291 	    va->a_name, va->a_uio, va->a_size, va->a_cred);
292 
293 	if (proc != NULL)
294 		PRELE(proc);
295 
296 	PFS_RETURN (error);
297 }
298 
299 /*
300  * Look up a file or directory
301  *
302  * XXX NOTE!  pfs_lookup() has been hooked into vop_lookup_desc!  This
303  * will result in a lookup operation for a vnode which may already be
304  * cached, therefore we have to be careful to purge the VFS cache when
305  * reusing a vnode.
306  *
307  * This code will work, but is not really correct.  Normally we would hook
308  * vfs_cache_lookup() into vop_lookup_desc and hook pfs_lookup() into
309  * vop_cachedlookup_desc.
310  */
311 static int
312 pfs_lookup(struct vop_lookup_args *va)
313 {
314 	struct vnode *vn = va->a_dvp;
315 	struct vnode **vpp = va->a_vpp;
316 	struct componentname *cnp = va->a_cnp;
317 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
318 	struct pfs_node *pd = pvd->pvd_pn;
319 	struct pfs_node *pn, *pdn = NULL;
320 	pid_t pid = pvd->pvd_pid;
321 	int lockparent;
322 	int wantparent;
323 	char *pname;
324 	int error, i, namelen;
325 
326 	PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
327 
328 	cnp->cn_flags &= ~PDIRUNLOCK;
329 
330 	if (vn->v_type != VDIR)
331 		PFS_RETURN (ENOTDIR);
332 
333 	/*
334 	 * Don't support DELETE or RENAME.  CREATE is supported so
335 	 * that O_CREAT will work, but the lookup will still fail if
336 	 * the file does not exist.
337 	 */
338 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
339 		PFS_RETURN (EOPNOTSUPP);
340 
341 	/* shortcut: check if the name is too long */
342 	if (cnp->cn_namelen >= PFS_NAMELEN)
343 		PFS_RETURN (ENOENT);
344 
345 	/* check that parent directory is visisble... */
346 	if (!pfs_visible(curthread, pd, pvd->pvd_pid))
347 		PFS_RETURN (ENOENT);
348 
349 	lockparent = cnp->cn_flags & LOCKPARENT;
350 	wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
351 
352 
353 	/* self */
354 	namelen = cnp->cn_namelen;
355 	pname = cnp->cn_nameptr;
356 	if (namelen == 1 && *pname == '.') {
357 		pn = pd;
358 		*vpp = vn;
359 		VREF(vn);
360 		PFS_RETURN (0);
361 	}
362 
363 	/* parent */
364 	if (cnp->cn_flags & ISDOTDOT) {
365 		if (pd->pn_type == pfstype_root)
366 			PFS_RETURN (EIO);
367 		VOP_UNLOCK(vn, 0, cnp->cn_thread);
368 		cnp->cn_flags |= PDIRUNLOCK;
369 
370 		KASSERT(pd->pn_parent, ("non-root directory has no parent"));
371 		/*
372 		 * This one is tricky.  Descendents of procdir nodes
373 		 * inherit their parent's process affinity, but
374 		 * there's no easy reverse mapping.  For simplicity,
375 		 * we assume that if this node is a procdir, its
376 		 * parent isn't (which is correct as long as
377 		 * descendents of procdir nodes are never procdir
378 		 * nodes themselves)
379 		 */
380 		if (pd->pn_type == pfstype_procdir)
381 			pid = NO_PID;
382 		pn = pd->pn_parent;
383 		goto got_pnode;
384 	}
385 
386 	/* named node */
387 	for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
388 		if (pn->pn_type == pfstype_procdir)
389 			pdn = pn;
390 		else if (pn->pn_name[namelen] == '\0'
391 		    && bcmp(pname, pn->pn_name, namelen) == 0)
392 			goto got_pnode;
393 
394 	/* process dependent node */
395 	if ((pn = pdn) != NULL) {
396 		pid = 0;
397 		for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
398 			if ((pid = pid * 10 + pname[i] - '0') > PID_MAX)
399 				break;
400 		if (i == cnp->cn_namelen)
401 			goto got_pnode;
402 	}
403 
404 	PFS_RETURN (ENOENT);
405  got_pnode:
406 	if (pn != pd->pn_parent && !pn->pn_parent)
407 		pn->pn_parent = pd;
408 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
409 		PFS_RETURN (ENOENT);
410 
411 	error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid);
412 	if (error)
413 		PFS_RETURN (error);
414 
415 	if ((cnp->cn_flags & ISDOTDOT) && (cnp->cn_flags & ISLASTCN)
416 	    && lockparent) {
417 		vn_lock(vn, LK_EXCLUSIVE|LK_RETRY, cnp->cn_thread);
418 		cnp->cn_flags &= ~PDIRUNLOCK;
419 	}
420 	if (!((lockparent && (cnp->cn_flags & ISLASTCN)) ||
421 	    (cnp->cn_flags & ISDOTDOT)))
422 		VOP_UNLOCK(vn, 0, cnp->cn_thread);
423 
424 	/*
425 	 * XXX See comment at top of the routine.
426 	 */
427 	if (cnp->cn_flags & MAKEENTRY)
428 		cache_enter(vn, *vpp, cnp);
429 	PFS_RETURN (0);
430 }
431 
432 /*
433  * Open a file or directory.
434  */
435 static int
436 pfs_open(struct vop_open_args *va)
437 {
438 	struct vnode *vn = va->a_vp;
439 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
440 	struct pfs_node *pn = pvd->pvd_pn;
441 	int mode = va->a_mode;
442 
443 	PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
444 
445 	/*
446 	 * check if the file is visible to the caller
447 	 *
448 	 * XXX Not sure if this is necessary, as the VFS system calls
449 	 * XXX pfs_lookup() and pfs_access() first, and pfs_lookup()
450 	 * XXX calls pfs_visible().  There's a race condition here, but
451 	 * XXX calling pfs_visible() from here doesn't really close it,
452 	 * XXX and the only consequence of that race is an EIO further
453 	 * XXX down the line.
454 	 */
455 	if (!pfs_visible(va->a_td, pn, pvd->pvd_pid))
456 		PFS_RETURN (ENOENT);
457 
458 	/* check if the requested mode is permitted */
459 	if (((mode & FREAD) && !(mode & PFS_RD)) ||
460 	    ((mode & FWRITE) && !(mode & PFS_WR)))
461 		PFS_RETURN (EPERM);
462 
463 	/* we don't support locking */
464 	if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
465 		PFS_RETURN (EOPNOTSUPP);
466 
467 	PFS_RETURN (0);
468 }
469 
470 /*
471  * Read from a file
472  */
473 static int
474 pfs_read(struct vop_read_args *va)
475 {
476 	struct vnode *vn = va->a_vp;
477 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
478 	struct pfs_node *pn = pvd->pvd_pn;
479 	struct uio *uio = va->a_uio;
480 	struct proc *proc = NULL;
481 	struct sbuf *sb = NULL;
482 	char *ps;
483 	int error, xlen;
484 
485 	PFS_TRACE((pn->pn_name));
486 
487 	if (vn->v_type != VREG)
488 		PFS_RETURN (EINVAL);
489 
490 	if (!(pn->pn_flags & PFS_RD))
491 		PFS_RETURN (EBADF);
492 
493 	if (pn->pn_func == NULL)
494 		PFS_RETURN (EIO);
495 
496 	/*
497 	 * This is necessary because either process' privileges may
498 	 * have changed since the open() call.
499 	 */
500 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
501 		PFS_RETURN (EIO);
502 
503 	/* XXX duplicates bits of pfs_visible() */
504 	if (pvd->pvd_pid != NO_PID) {
505 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
506 			PFS_RETURN (EIO);
507 		_PHOLD(proc);
508 		PROC_UNLOCK(proc);
509 	}
510 
511 	if (pn->pn_flags & PFS_RAWRD) {
512 		error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
513 		if (proc != NULL)
514 			PRELE(proc);
515 		PFS_RETURN (error);
516 	}
517 
518 	sb = sbuf_new(sb, NULL, uio->uio_offset + uio->uio_resid, 0);
519 	if (sb == NULL) {
520 		if (proc != NULL)
521 			PRELE(proc);
522 		PFS_RETURN (EIO);
523 	}
524 
525 	error = (pn->pn_func)(curthread, proc, pn, sb, uio);
526 
527 	if (proc != NULL)
528 		PRELE(proc);
529 
530 	if (error) {
531 		sbuf_delete(sb);
532 		PFS_RETURN (error);
533 	}
534 
535 	/* XXX we should possibly detect and handle overflows */
536 	sbuf_finish(sb);
537 	ps = sbuf_data(sb) + uio->uio_offset;
538 	xlen = sbuf_len(sb) - uio->uio_offset;
539 	xlen = imin(xlen, uio->uio_resid);
540 	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
541 	sbuf_delete(sb);
542 	PFS_RETURN (error);
543 }
544 
545 /*
546  * Iterate through directory entries
547  */
548 static int
549 pfs_iterate(struct thread *td, pid_t pid, struct pfs_node *pd,
550 	    struct pfs_node **pn, struct proc **p)
551 {
552 	sx_assert(&allproc_lock, SX_LOCKED);
553  again:
554 	if (*pn == NULL) {
555 		/* first node */
556 		*pn = pd->pn_nodes;
557 	} else if ((*pn)->pn_type != pfstype_procdir) {
558 		/* next node */
559 		*pn = (*pn)->pn_next;
560 	}
561 	if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
562 		/* next process */
563 		if (*p == NULL)
564 			*p = LIST_FIRST(&allproc);
565 		else
566 			*p = LIST_NEXT(*p, p_list);
567 		/* out of processes: next node */
568 		if (*p == NULL)
569 			*pn = (*pn)->pn_next;
570 	}
571 
572 	if ((*pn) == NULL)
573 		return (-1);
574 
575 	if (!pfs_visible(td, *pn, *p ? (*p)->p_pid : pid))
576 		goto again;
577 
578 	return (0);
579 }
580 
581 /*
582  * Return directory entries.
583  */
584 static int
585 pfs_readdir(struct vop_readdir_args *va)
586 {
587 	struct vnode *vn = va->a_vp;
588 	struct pfs_info *pi = (struct pfs_info *)vn->v_mount->mnt_data;
589 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
590 	struct pfs_node *pd = pvd->pvd_pn;
591 	pid_t pid = pvd->pvd_pid;
592 	struct pfs_node *pn;
593 	struct dirent entry;
594 	struct uio *uio;
595 	struct proc *p;
596 	off_t offset;
597 	int error, i, resid;
598 
599 	PFS_TRACE((pd->pn_name));
600 
601 	if (vn->v_type != VDIR)
602 		PFS_RETURN (ENOTDIR);
603 	uio = va->a_uio;
604 
605 	/* check if the directory is visible to the caller */
606 	if (!pfs_visible(curthread, pd, pid))
607 		PFS_RETURN (ENOENT);
608 
609 	/* only allow reading entire entries */
610 	offset = uio->uio_offset;
611 	resid = uio->uio_resid;
612 	if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN)
613 		PFS_RETURN (EINVAL);
614 
615 	/* skip unwanted entries */
616 	sx_slock(&allproc_lock);
617 	for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN)
618 		if (pfs_iterate(curthread, pid, pd, &pn, &p) == -1) {
619 			/* nothing left... */
620 			sx_sunlock(&allproc_lock);
621 			PFS_RETURN (0);
622 		}
623 
624 	/* fill in entries */
625 	entry.d_reclen = PFS_DELEN;
626 	while (pfs_iterate(curthread, pid, pd, &pn, &p) != -1 && resid > 0) {
627 		if (!pn->pn_parent)
628 			pn->pn_parent = pd;
629 		if (!pn->pn_fileno)
630 			pfs_fileno_alloc(pi, pn);
631 		if (pid != NO_PID)
632 			entry.d_fileno = pn->pn_fileno * NO_PID + pid;
633 		else
634 			entry.d_fileno = pn->pn_fileno;
635 		/* PFS_DELEN was picked to fit PFS_NAMLEN */
636 		for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
637 			entry.d_name[i] = pn->pn_name[i];
638 		entry.d_name[i] = 0;
639 		entry.d_namlen = i;
640 		switch (pn->pn_type) {
641 		case pfstype_procdir:
642 			KASSERT(p != NULL,
643 			    ("reached procdir node with p == NULL"));
644 			entry.d_fileno = pn->pn_fileno * NO_PID + p->p_pid;
645 			entry.d_namlen = snprintf(entry.d_name,
646 			    PFS_NAMELEN, "%d", p->p_pid);
647 			/* fall through */
648 		case pfstype_root:
649 		case pfstype_dir:
650 		case pfstype_this:
651 		case pfstype_parent:
652 			entry.d_type = DT_DIR;
653 			break;
654 		case pfstype_file:
655 			entry.d_type = DT_REG;
656 			break;
657 		case pfstype_symlink:
658 			entry.d_type = DT_LNK;
659 			break;
660 		default:
661 			sx_sunlock(&allproc_lock);
662 			panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
663 		}
664 		PFS_TRACE((entry.d_name));
665 		if ((error = uiomove(&entry, PFS_DELEN, uio))) {
666 			sx_sunlock(&allproc_lock);
667 			PFS_RETURN (error);
668 		}
669 		offset += PFS_DELEN;
670 		resid -= PFS_DELEN;
671 	}
672 
673 	sx_sunlock(&allproc_lock);
674 	uio->uio_offset += offset;
675 	PFS_RETURN (0);
676 }
677 
678 /*
679  * Read a symbolic link
680  */
681 static int
682 pfs_readlink(struct vop_readlink_args *va)
683 {
684 	struct vnode *vn = va->a_vp;
685 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
686 	struct pfs_node *pn = pvd->pvd_pn;
687 	struct uio *uio = va->a_uio;
688 	struct proc *proc = NULL;
689 	char buf[MAXPATHLEN], *ps;
690 	struct sbuf sb;
691 	int error, xlen;
692 
693 	PFS_TRACE((pn->pn_name));
694 
695 	if (vn->v_type != VLNK)
696 		PFS_RETURN (EINVAL);
697 
698 	if (pn->pn_func == NULL)
699 		PFS_RETURN (EIO);
700 
701 	if (pvd->pvd_pid != NO_PID) {
702 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
703 			PFS_RETURN (EIO);
704 		_PHOLD(proc);
705 		PROC_UNLOCK(proc);
706 	}
707 
708 	/* sbuf_new() can't fail with a static buffer */
709 	sbuf_new(&sb, buf, sizeof buf, 0);
710 
711 	error = (pn->pn_func)(curthread, proc, pn, &sb, NULL);
712 
713 	if (proc != NULL)
714 		PRELE(proc);
715 
716 	if (error) {
717 		sbuf_delete(&sb);
718 		PFS_RETURN (error);
719 	}
720 
721 	/* XXX we should detect and handle overflows */
722 	sbuf_finish(&sb);
723 	ps = sbuf_data(&sb) + uio->uio_offset;
724 	xlen = sbuf_len(&sb) - uio->uio_offset;
725 	xlen = imin(xlen, uio->uio_resid);
726 	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
727 	sbuf_delete(&sb);
728 	PFS_RETURN (error);
729 }
730 
731 /*
732  * Reclaim a vnode
733  */
734 static int
735 pfs_reclaim(struct vop_reclaim_args *va)
736 {
737 	PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
738 
739 	return (pfs_vncache_free(va->a_vp));
740 }
741 
742 /*
743  * Set attributes
744  */
745 static int
746 pfs_setattr(struct vop_setattr_args *va)
747 {
748 	PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
749 
750 	PFS_RETURN (EOPNOTSUPP);
751 }
752 
753 /*
754  * Read from a file
755  */
756 static int
757 pfs_write(struct vop_read_args *va)
758 {
759 	struct vnode *vn = va->a_vp;
760 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
761 	struct pfs_node *pn = pvd->pvd_pn;
762 	struct uio *uio = va->a_uio;
763 	struct proc *proc = NULL;
764 	struct sbuf sb;
765 	int error;
766 
767 	PFS_TRACE((pn->pn_name));
768 
769 	if (vn->v_type != VREG)
770 		PFS_RETURN (EINVAL);
771 
772 	if (!(pn->pn_flags & PFS_WR))
773 		PFS_RETURN (EBADF);
774 
775 	if (pn->pn_func == NULL)
776 		PFS_RETURN (EIO);
777 
778 	/*
779 	 * This is necessary because either process' privileges may
780 	 * have changed since the open() call.
781 	 */
782 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
783 		PFS_RETURN (EIO);
784 
785 	/* XXX duplicates bits of pfs_visible() */
786 	if (pvd->pvd_pid != NO_PID) {
787 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
788 			PFS_RETURN (EIO);
789 		_PHOLD(proc);
790 		PROC_UNLOCK(proc);
791 	}
792 
793 	if (pn->pn_flags & PFS_RAWWR) {
794 		error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
795 		if (proc != NULL)
796 			PRELE(proc);
797 		PFS_RETURN (error);
798 	}
799 
800 	sbuf_uionew(&sb, uio, &error);
801 	if (error)
802 		PFS_RETURN (error);
803 
804 	error = (pn->pn_func)(curthread, proc, pn, &sb, uio);
805 
806 	if (proc != NULL)
807 		PRELE(proc);
808 
809 	sbuf_delete(&sb);
810 	PFS_RETURN (error);
811 }
812 
813 /*
814  * Vnode operations
815  */
816 vop_t **pfs_vnodeop_p;
817 static struct vnodeopv_entry_desc pfs_vnodeop_entries[] = {
818 	{ &vop_default_desc,		(vop_t *)vop_defaultop	},
819 	{ &vop_access_desc,		(vop_t *)pfs_access	},
820 	{ &vop_close_desc,		(vop_t *)pfs_close	},
821 	{ &vop_create_desc,		(vop_t *)vop_eopnotsupp	},
822 	{ &vop_getattr_desc,		(vop_t *)pfs_getattr	},
823 	{ &vop_getextattr_desc,		(vop_t *)pfs_getextattr	},
824 	{ &vop_ioctl_desc,		(vop_t *)pfs_ioctl	},
825 	{ &vop_link_desc,		(vop_t *)vop_eopnotsupp	},
826 	{ &vop_lookup_desc,		(vop_t *)pfs_lookup	},
827 	{ &vop_mkdir_desc,		(vop_t *)vop_eopnotsupp	},
828 	{ &vop_mknod_desc,		(vop_t *)vop_eopnotsupp	},
829 	{ &vop_open_desc,		(vop_t *)pfs_open	},
830 	{ &vop_read_desc,		(vop_t *)pfs_read	},
831 	{ &vop_readdir_desc,		(vop_t *)pfs_readdir	},
832 	{ &vop_readlink_desc,		(vop_t *)pfs_readlink	},
833 	{ &vop_reclaim_desc,		(vop_t *)pfs_reclaim	},
834 	{ &vop_remove_desc,		(vop_t *)vop_eopnotsupp	},
835 	{ &vop_rename_desc,		(vop_t *)vop_eopnotsupp	},
836 	{ &vop_rmdir_desc,		(vop_t *)vop_eopnotsupp	},
837 	{ &vop_setattr_desc,		(vop_t *)pfs_setattr	},
838 	{ &vop_symlink_desc,		(vop_t *)vop_eopnotsupp	},
839 	{ &vop_write_desc,		(vop_t *)pfs_write	},
840 	/* XXX I've probably forgotten a few that need vop_eopnotsupp */
841 	{ NULL,				(vop_t *)NULL		}
842 };
843 
844 static struct vnodeopv_desc pfs_vnodeop_opv_desc =
845 	{ &pfs_vnodeop_p, pfs_vnodeop_entries };
846 
847 VNODEOP_SET(pfs_vnodeop_opv_desc);
848