xref: /freebsd/sys/fs/pseudofs/pseudofs_vnops.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include "opt_pseudofs.h"
33 
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
37 #include <sys/ctype.h>
38 #include <sys/dirent.h>
39 #include <sys/fcntl.h>
40 #include <sys/limits.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mount.h>
44 #include <sys/mutex.h>
45 #include <sys/namei.h>
46 #include <sys/proc.h>
47 #include <sys/sbuf.h>
48 #include <sys/sx.h>
49 #include <sys/sysctl.h>
50 #include <sys/vnode.h>
51 
52 #include <fs/pseudofs/pseudofs.h>
53 #include <fs/pseudofs/pseudofs_internal.h>
54 
55 /*
56  * Returns the fileno, adjusted for target pid
57  */
58 static uint32_t
59 pn_fileno(struct pfs_node *pn, pid_t pid)
60 {
61 
62 	KASSERT(pn->pn_fileno > 0,
63 	    ("%s(): no fileno allocated", __func__));
64 	if (pid != NO_PID)
65 		return (pn->pn_fileno * NO_PID + pid);
66 	return (pn->pn_fileno);
67 }
68 
69 /*
70  * Returns non-zero if given file is visible to given thread.
71  */
72 static int
73 pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc)
74 {
75 	int visible;
76 
77 	if (proc == NULL)
78 		return (0);
79 
80 	PROC_LOCK_ASSERT(proc, MA_OWNED);
81 
82 	visible = ((proc->p_flag & P_WEXIT) == 0);
83 	if (visible)
84 		visible = (p_cansee(td, proc) == 0);
85 	if (visible && pn->pn_vis != NULL)
86 		visible = pn_vis(td, proc, pn);
87 	if (!visible)
88 		return (0);
89 	return (1);
90 }
91 
92 static int
93 pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid, struct proc **p)
94 {
95 	struct proc *proc;
96 
97 	PFS_TRACE(("%s (pid: %d, req: %d)",
98 	    pn->pn_name, pid, td->td_proc->p_pid));
99 
100 	if (p)
101 		*p = NULL;
102 	if (pid == NO_PID)
103 		PFS_RETURN (1);
104 	if ((proc = pfind(pid)) == NULL)
105 		PFS_RETURN (0);
106 	if (pfs_visible_proc(td, pn, proc)) {
107 		if (p)
108 			*p = proc;
109 		else
110 			PROC_UNLOCK(proc);
111 		PFS_RETURN (1);
112 	}
113 	PROC_UNLOCK(proc);
114 	PFS_RETURN (0);
115 }
116 
117 /*
118  * Verify permissions
119  */
120 static int
121 pfs_access(struct vop_access_args *va)
122 {
123 	struct vnode *vn = va->a_vp;
124 	struct pfs_vdata *pvd = vn->v_data;
125 	struct vattr vattr;
126 	int error;
127 
128 	PFS_TRACE(("%s", pvd->pvd_pn->pn_name));
129 	(void)pvd;
130 
131 	error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_td);
132 	if (error)
133 		PFS_RETURN (error);
134 	error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid,
135 	    vattr.va_gid, va->a_mode, va->a_cred, NULL);
136 	PFS_RETURN (error);
137 }
138 
139 /*
140  * Close a file or directory
141  */
142 static int
143 pfs_close(struct vop_close_args *va)
144 {
145 	struct vnode *vn = va->a_vp;
146 	struct pfs_vdata *pvd = vn->v_data;
147 	struct pfs_node *pn = pvd->pvd_pn;
148 	struct proc *proc;
149 	int error;
150 
151 	PFS_TRACE(("%s", pn->pn_name));
152 	pfs_assert_not_owned(pn);
153 
154 	/*
155 	 * Do nothing unless this is the last close and the node has a
156 	 * last-close handler.
157 	 */
158 	if (vrefcnt(vn) > 1 || pn->pn_close == NULL)
159 		PFS_RETURN (0);
160 
161 	if (pvd->pvd_pid != NO_PID) {
162 		proc = pfind(pvd->pvd_pid);
163 	} else {
164 		proc = NULL;
165 	}
166 
167 	error = pn_close(va->a_td, proc, pn);
168 
169 	if (proc != NULL)
170 		PROC_UNLOCK(proc);
171 
172 	PFS_RETURN (error);
173 }
174 
175 /*
176  * Get file attributes
177  */
178 static int
179 pfs_getattr(struct vop_getattr_args *va)
180 {
181 	struct vnode *vn = va->a_vp;
182 	struct pfs_vdata *pvd = vn->v_data;
183 	struct pfs_node *pn = pvd->pvd_pn;
184 	struct vattr *vap = va->a_vap;
185 	struct proc *proc;
186 	int error = 0;
187 
188 	PFS_TRACE(("%s", pn->pn_name));
189 	pfs_assert_not_owned(pn);
190 
191 	if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
192 		PFS_RETURN (ENOENT);
193 
194 	VATTR_NULL(vap);
195 	vap->va_type = vn->v_type;
196 	vap->va_fileid = pn_fileno(pn, pvd->pvd_pid);
197 	vap->va_flags = 0;
198 	vap->va_blocksize = PAGE_SIZE;
199 	vap->va_bytes = vap->va_size = 0;
200 	vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
201 	vap->va_nlink = 1;
202 	nanotime(&vap->va_ctime);
203 	vap->va_atime = vap->va_mtime = vap->va_ctime;
204 
205 	switch (pn->pn_type) {
206 	case pfstype_procdir:
207 	case pfstype_root:
208 	case pfstype_dir:
209 #if 0
210 		pfs_lock(pn);
211 		/* compute link count */
212 		pfs_unlock(pn);
213 #endif
214 		vap->va_mode = 0555;
215 		break;
216 	case pfstype_file:
217 	case pfstype_symlink:
218 		vap->va_mode = 0444;
219 		break;
220 	default:
221 		printf("shouldn't be here!\n");
222 		vap->va_mode = 0;
223 		break;
224 	}
225 
226 	if (proc != NULL) {
227 		vap->va_uid = proc->p_ucred->cr_ruid;
228 		vap->va_gid = proc->p_ucred->cr_rgid;
229 		if (pn->pn_attr != NULL)
230 			error = pn_attr(va->a_td, proc, pn, vap);
231 		PROC_UNLOCK(proc);
232 	} else {
233 		vap->va_uid = 0;
234 		vap->va_gid = 0;
235 	}
236 
237 	PFS_RETURN (error);
238 }
239 
240 /*
241  * Perform an ioctl
242  */
243 static int
244 pfs_ioctl(struct vop_ioctl_args *va)
245 {
246 	struct vnode *vn = va->a_vp;
247 	struct pfs_vdata *pvd = vn->v_data;
248 	struct pfs_node *pn = pvd->pvd_pn;
249 	struct proc *proc;
250 	int error;
251 
252 	PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
253 	pfs_assert_not_owned(pn);
254 
255 	if (vn->v_type != VREG)
256 		PFS_RETURN (EINVAL);
257 
258 	if (pn->pn_ioctl == NULL)
259 		PFS_RETURN (ENOTTY);
260 
261 	/*
262 	 * This is necessary because process' privileges may
263 	 * have changed since the open() call.
264 	 */
265 	if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
266 		PFS_RETURN (EIO);
267 
268 	error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data);
269 
270 	if (proc != NULL)
271 		PROC_UNLOCK(proc);
272 
273 	PFS_RETURN (error);
274 }
275 
276 /*
277  * Perform getextattr
278  */
279 static int
280 pfs_getextattr(struct vop_getextattr_args *va)
281 {
282 	struct vnode *vn = va->a_vp;
283 	struct pfs_vdata *pvd = vn->v_data;
284 	struct pfs_node *pn = pvd->pvd_pn;
285 	struct proc *proc;
286 	int error;
287 
288 	PFS_TRACE(("%s", pn->pn_name));
289 	pfs_assert_not_owned(pn);
290 
291 	/*
292 	 * This is necessary because either process' privileges may
293 	 * have changed since the open() call.
294 	 */
295 	if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
296 		PFS_RETURN (EIO);
297 
298 	if (pn->pn_getextattr == NULL)
299 		error = EOPNOTSUPP;
300 	else
301 		error = pn_getextattr(curthread, proc, pn,
302 		    va->a_attrnamespace, va->a_name, va->a_uio,
303 		    va->a_size, va->a_cred);
304 
305 	if (proc != NULL)
306 		PROC_UNLOCK(proc);
307 
308 	pfs_unlock(pn);
309 	PFS_RETURN (error);
310 }
311 
312 /*
313  * Look up a file or directory
314  */
315 static int
316 pfs_lookup(struct vop_cachedlookup_args *va)
317 {
318 	struct vnode *vn = va->a_dvp;
319 	struct vnode **vpp = va->a_vpp;
320 	struct componentname *cnp = va->a_cnp;
321 	struct pfs_vdata *pvd = vn->v_data;
322 	struct pfs_node *pd = pvd->pvd_pn;
323 	struct pfs_node *pn, *pdn = NULL;
324 	pid_t pid = pvd->pvd_pid;
325 	char *pname;
326 	int error, i, namelen, visible;
327 
328 	PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
329 	pfs_assert_not_owned(pd);
330 
331 	if (vn->v_type != VDIR)
332 		PFS_RETURN (ENOTDIR);
333 
334 	error = VOP_ACCESS(vn, VEXEC, cnp->cn_cred, cnp->cn_thread);
335 	if (error)
336 		PFS_RETURN (error);
337 
338 	/*
339 	 * Don't support DELETE or RENAME.  CREATE is supported so
340 	 * that O_CREAT will work, but the lookup will still fail if
341 	 * the file does not exist.
342 	 */
343 	if ((cnp->cn_flags & ISLASTCN) &&
344 	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
345 		PFS_RETURN (EOPNOTSUPP);
346 
347 	/* shortcut: check if the name is too long */
348 	if (cnp->cn_namelen >= PFS_NAMELEN)
349 		PFS_RETURN (ENOENT);
350 
351 	/* check that parent directory is visible... */
352 	if (!pfs_visible(curthread, pd, pvd->pvd_pid, NULL))
353 		PFS_RETURN (ENOENT);
354 
355 	/* self */
356 	namelen = cnp->cn_namelen;
357 	pname = cnp->cn_nameptr;
358 	if (namelen == 1 && pname[0] == '.') {
359 		pn = pd;
360 		*vpp = vn;
361 		VREF(vn);
362 		PFS_RETURN (0);
363 	}
364 
365 	/* parent */
366 	if (cnp->cn_flags & ISDOTDOT) {
367 		if (pd->pn_type == pfstype_root)
368 			PFS_RETURN (EIO);
369 		VOP_UNLOCK(vn, 0);
370 		KASSERT(pd->pn_parent != NULL,
371 		    ("%s(): non-root directory has no parent", __func__));
372 		/*
373 		 * This one is tricky.  Descendents of procdir nodes
374 		 * inherit their parent's process affinity, but
375 		 * there's no easy reverse mapping.  For simplicity,
376 		 * we assume that if this node is a procdir, its
377 		 * parent isn't (which is correct as long as
378 		 * descendents of procdir nodes are never procdir
379 		 * nodes themselves)
380 		 */
381 		if (pd->pn_type == pfstype_procdir)
382 			pid = NO_PID;
383 		pfs_lock(pd);
384 		pn = pd->pn_parent;
385 		pfs_unlock(pd);
386 		goto got_pnode;
387 	}
388 
389 	pfs_lock(pd);
390 
391 	/* named node */
392 	for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
393 		if (pn->pn_type == pfstype_procdir)
394 			pdn = pn;
395 		else if (pn->pn_name[namelen] == '\0' &&
396 		    bcmp(pname, pn->pn_name, namelen) == 0) {
397 			pfs_unlock(pd);
398 			goto got_pnode;
399 		}
400 
401 	/* process dependent node */
402 	if ((pn = pdn) != NULL) {
403 		pid = 0;
404 		for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
405 			if ((pid = pid * 10 + pname[i] - '0') > PID_MAX)
406 				break;
407 		if (i == cnp->cn_namelen) {
408 			pfs_unlock(pd);
409 			goto got_pnode;
410 		}
411 	}
412 
413 	pfs_unlock(pd);
414 
415 	PFS_RETURN (ENOENT);
416 
417  got_pnode:
418 	pfs_assert_not_owned(pd);
419 	pfs_assert_not_owned(pn);
420 	visible = pfs_visible(curthread, pn, pid, NULL);
421 	if (!visible) {
422 		error = ENOENT;
423 		goto failed;
424 	}
425 
426 	error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid);
427 	if (error)
428 		goto failed;
429 
430 	if (cnp->cn_flags & ISDOTDOT)
431 		vn_lock(vn, LK_EXCLUSIVE|LK_RETRY);
432 	if (cnp->cn_flags & MAKEENTRY)
433 		cache_enter(vn, *vpp, cnp);
434 	PFS_RETURN (0);
435  failed:
436 	if (cnp->cn_flags & ISDOTDOT)
437 		vn_lock(vn, LK_EXCLUSIVE|LK_RETRY);
438 	PFS_RETURN(error);
439 }
440 
441 /*
442  * Open a file or directory.
443  */
444 static int
445 pfs_open(struct vop_open_args *va)
446 {
447 	struct vnode *vn = va->a_vp;
448 	struct pfs_vdata *pvd = vn->v_data;
449 	struct pfs_node *pn = pvd->pvd_pn;
450 	int mode = va->a_mode;
451 
452 	PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
453 	pfs_assert_not_owned(pn);
454 
455 	/* check if the requested mode is permitted */
456 	if (((mode & FREAD) && !(mode & PFS_RD)) ||
457 	    ((mode & FWRITE) && !(mode & PFS_WR)))
458 		PFS_RETURN (EPERM);
459 
460 	/* we don't support locking */
461 	if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
462 		PFS_RETURN (EOPNOTSUPP);
463 
464 	PFS_RETURN (0);
465 }
466 
467 /*
468  * Read from a file
469  */
470 static int
471 pfs_read(struct vop_read_args *va)
472 {
473 	struct vnode *vn = va->a_vp;
474 	struct pfs_vdata *pvd = vn->v_data;
475 	struct pfs_node *pn = pvd->pvd_pn;
476 	struct uio *uio = va->a_uio;
477 	struct proc *proc;
478 	struct sbuf *sb = NULL;
479 	int error;
480 	unsigned int buflen, offset, resid;
481 
482 	PFS_TRACE(("%s", pn->pn_name));
483 	pfs_assert_not_owned(pn);
484 
485 	if (vn->v_type != VREG)
486 		PFS_RETURN (EINVAL);
487 
488 	if (!(pn->pn_flags & PFS_RD))
489 		PFS_RETURN (EBADF);
490 
491 	if (pn->pn_fill == NULL)
492 		PFS_RETURN (EIO);
493 
494 	/*
495 	 * This is necessary because either process' privileges may
496 	 * have changed since the open() call.
497 	 */
498 	if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
499 		PFS_RETURN (EIO);
500 	if (proc != NULL) {
501 		_PHOLD(proc);
502 		PROC_UNLOCK(proc);
503 	}
504 
505 	if (pn->pn_flags & PFS_RAWRD) {
506 		PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
507 		error = pn_fill(curthread, proc, pn, NULL, uio);
508 		PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
509 		if (proc != NULL)
510 			PRELE(proc);
511 		PFS_RETURN (error);
512 	}
513 
514 	/* beaucoup sanity checks so we don't ask for bogus allocation */
515 	if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
516 	    (offset = uio->uio_offset) != uio->uio_offset ||
517 	    (resid = uio->uio_resid) != uio->uio_resid ||
518 	    (buflen = offset + resid + 1) < offset || buflen > INT_MAX) {
519 		if (proc != NULL)
520 			PRELE(proc);
521 		PFS_RETURN (EINVAL);
522 	}
523 	if (buflen > MAXPHYS + 1) {
524 		if (proc != NULL)
525 			PRELE(proc);
526 		PFS_RETURN (EIO);
527 	}
528 
529 	sb = sbuf_new(sb, NULL, buflen, 0);
530 	if (sb == NULL) {
531 		if (proc != NULL)
532 			PRELE(proc);
533 		PFS_RETURN (EIO);
534 	}
535 
536 	error = pn_fill(curthread, proc, pn, sb, uio);
537 
538 	if (proc != NULL)
539 		PRELE(proc);
540 
541 	if (error) {
542 		sbuf_delete(sb);
543 		PFS_RETURN (error);
544 	}
545 
546 	sbuf_finish(sb);
547 	error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
548 	sbuf_delete(sb);
549 	PFS_RETURN (error);
550 }
551 
552 /*
553  * Iterate through directory entries
554  */
555 static int
556 pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd,
557 	    struct pfs_node **pn, struct proc **p)
558 {
559 	int visible;
560 
561 	sx_assert(&allproc_lock, SX_SLOCKED);
562 	pfs_assert_owned(pd);
563  again:
564 	if (*pn == NULL) {
565 		/* first node */
566 		*pn = pd->pn_nodes;
567 	} else if ((*pn)->pn_type != pfstype_procdir) {
568 		/* next node */
569 		*pn = (*pn)->pn_next;
570 	}
571 	if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
572 		/* next process */
573 		if (*p == NULL)
574 			*p = LIST_FIRST(&allproc);
575 		else
576 			*p = LIST_NEXT(*p, p_list);
577 		/* out of processes: next node */
578 		if (*p == NULL)
579 			*pn = (*pn)->pn_next;
580 		else
581 			PROC_LOCK(*p);
582 	}
583 
584 	if ((*pn) == NULL)
585 		return (-1);
586 
587 	if (*p != NULL) {
588 		visible = pfs_visible_proc(td, *pn, *p);
589 		PROC_UNLOCK(*p);
590 	} else if (proc != NULL) {
591 		visible = pfs_visible_proc(td, *pn, proc);
592 	} else {
593 		visible = 1;
594 	}
595 	if (!visible)
596 		goto again;
597 
598 	return (0);
599 }
600 
601 /*
602  * Return directory entries.
603  */
604 static int
605 pfs_readdir(struct vop_readdir_args *va)
606 {
607 	struct vnode *vn = va->a_vp;
608 	struct pfs_vdata *pvd = vn->v_data;
609 	struct pfs_node *pd = pvd->pvd_pn;
610 	pid_t pid = pvd->pvd_pid;
611 	struct proc *p, *proc;
612 	struct pfs_node *pn;
613 	struct dirent *entry;
614 	struct uio *uio;
615 	off_t offset;
616 	int error, i, resid;
617 	char *buf, *ent;
618 
619 	KASSERT(pd->pn_info == vn->v_mount->mnt_data,
620 	    ("%s(): pn_info does not match mountpoint", __func__));
621 	PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid));
622 	pfs_assert_not_owned(pd);
623 
624 	if (vn->v_type != VDIR)
625 		PFS_RETURN (ENOTDIR);
626 	uio = va->a_uio;
627 
628 	/* only allow reading entire entries */
629 	offset = uio->uio_offset;
630 	resid = uio->uio_resid;
631 	if (offset < 0 || offset % PFS_DELEN != 0 ||
632 	    (resid && resid < PFS_DELEN))
633 		PFS_RETURN (EINVAL);
634 	if (resid == 0)
635 		PFS_RETURN (0);
636 
637 	/* can't do this while holding the proc lock... */
638 	buf = malloc(resid, M_IOV, M_WAITOK | M_ZERO);
639 	sx_slock(&allproc_lock);
640 	pfs_lock(pd);
641 
642         /* check if the directory is visible to the caller */
643         if (!pfs_visible(curthread, pd, pid, &proc)) {
644 		sx_sunlock(&allproc_lock);
645 		pfs_unlock(pd);
646 		free(buf, M_IOV);
647                 PFS_RETURN (ENOENT);
648 	}
649 	KASSERT(pid == NO_PID || proc != NULL,
650 	    ("%s(): no process for pid %lu", __func__, (unsigned long)pid));
651 
652 	/* skip unwanted entries */
653 	for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) {
654 		if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) {
655 			/* nothing left... */
656 			if (proc != NULL)
657 				PROC_UNLOCK(proc);
658 			pfs_unlock(pd);
659 			sx_sunlock(&allproc_lock);
660 			free(buf, M_IOV);
661 			PFS_RETURN (0);
662 		}
663 	}
664 
665 	/* fill in entries */
666 	ent = buf;
667 	while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 &&
668 	    resid >= PFS_DELEN) {
669 		entry = (struct dirent *)ent;
670 		entry->d_reclen = PFS_DELEN;
671 		entry->d_fileno = pn_fileno(pn, pid);
672 		/* PFS_DELEN was picked to fit PFS_NAMLEN */
673 		for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
674 			entry->d_name[i] = pn->pn_name[i];
675 		entry->d_name[i] = 0;
676 		entry->d_namlen = i;
677 		switch (pn->pn_type) {
678 		case pfstype_procdir:
679 			KASSERT(p != NULL,
680 			    ("reached procdir node with p == NULL"));
681 			entry->d_namlen = snprintf(entry->d_name,
682 			    PFS_NAMELEN, "%d", p->p_pid);
683 			/* fall through */
684 		case pfstype_root:
685 		case pfstype_dir:
686 		case pfstype_this:
687 		case pfstype_parent:
688 			entry->d_type = DT_DIR;
689 			break;
690 		case pfstype_file:
691 			entry->d_type = DT_REG;
692 			break;
693 		case pfstype_symlink:
694 			entry->d_type = DT_LNK;
695 			break;
696 		default:
697 			panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
698 		}
699 		PFS_TRACE(("%s", entry->d_name));
700 		offset += PFS_DELEN;
701 		resid -= PFS_DELEN;
702 		ent += PFS_DELEN;
703 	}
704 	if (proc != NULL)
705 		PROC_UNLOCK(proc);
706 	pfs_unlock(pd);
707 	sx_sunlock(&allproc_lock);
708 	PFS_TRACE(("%zd bytes", ent - buf));
709 	error = uiomove(buf, ent - buf, uio);
710 	free(buf, M_IOV);
711 	PFS_RETURN (error);
712 }
713 
714 /*
715  * Read a symbolic link
716  */
717 static int
718 pfs_readlink(struct vop_readlink_args *va)
719 {
720 	struct vnode *vn = va->a_vp;
721 	struct pfs_vdata *pvd = vn->v_data;
722 	struct pfs_node *pn = pvd->pvd_pn;
723 	struct uio *uio = va->a_uio;
724 	struct proc *proc = NULL;
725 	char buf[PATH_MAX];
726 	struct sbuf sb;
727 	int error;
728 
729 	PFS_TRACE(("%s", pn->pn_name));
730 	pfs_assert_not_owned(pn);
731 
732 	if (vn->v_type != VLNK)
733 		PFS_RETURN (EINVAL);
734 
735 	if (pn->pn_fill == NULL)
736 		PFS_RETURN (EIO);
737 
738 	if (pvd->pvd_pid != NO_PID) {
739 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
740 			PFS_RETURN (EIO);
741 		if (proc->p_flag & P_WEXIT) {
742 			PROC_UNLOCK(proc);
743 			PFS_RETURN (EIO);
744 		}
745 		_PHOLD(proc);
746 		PROC_UNLOCK(proc);
747 	}
748 
749 	/* sbuf_new() can't fail with a static buffer */
750 	sbuf_new(&sb, buf, sizeof buf, 0);
751 
752 	error = pn_fill(curthread, proc, pn, &sb, NULL);
753 
754 	if (proc != NULL)
755 		PRELE(proc);
756 
757 	if (error) {
758 		sbuf_delete(&sb);
759 		PFS_RETURN (error);
760 	}
761 
762 	sbuf_finish(&sb);
763 	error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
764 	sbuf_delete(&sb);
765 	PFS_RETURN (error);
766 }
767 
768 /*
769  * Reclaim a vnode
770  */
771 static int
772 pfs_reclaim(struct vop_reclaim_args *va)
773 {
774 	struct vnode *vn = va->a_vp;
775 	struct pfs_vdata *pvd = vn->v_data;
776 	struct pfs_node *pn = pvd->pvd_pn;
777 
778 	PFS_TRACE(("%s", pn->pn_name));
779 	pfs_assert_not_owned(pn);
780 
781 	return (pfs_vncache_free(va->a_vp));
782 }
783 
784 /*
785  * Set attributes
786  */
787 static int
788 pfs_setattr(struct vop_setattr_args *va)
789 {
790 	struct vnode *vn = va->a_vp;
791 	struct pfs_vdata *pvd = vn->v_data;
792 	struct pfs_node *pn = pvd->pvd_pn;
793 
794 	PFS_TRACE(("%s", pn->pn_name));
795 	pfs_assert_not_owned(pn);
796 
797 	PFS_RETURN (EOPNOTSUPP);
798 }
799 
800 /*
801  * Write to a file
802  */
803 static int
804 pfs_write(struct vop_write_args *va)
805 {
806 	struct vnode *vn = va->a_vp;
807 	struct pfs_vdata *pvd = vn->v_data;
808 	struct pfs_node *pn = pvd->pvd_pn;
809 	struct uio *uio = va->a_uio;
810 	struct proc *proc;
811 	struct sbuf sb;
812 	int error;
813 
814 	PFS_TRACE(("%s", pn->pn_name));
815 	pfs_assert_not_owned(pn);
816 
817 	if (vn->v_type != VREG)
818 		PFS_RETURN (EINVAL);
819 	KASSERT(pn->pn_type != pfstype_file,
820 	    ("%s(): VREG vnode refers to non-file pfs_node", __func__));
821 
822 	if (!(pn->pn_flags & PFS_WR))
823 		PFS_RETURN (EBADF);
824 
825 	if (pn->pn_fill == NULL)
826 		PFS_RETURN (EIO);
827 
828 	/*
829 	 * This is necessary because either process' privileges may
830 	 * have changed since the open() call.
831 	 */
832 	if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
833 		PFS_RETURN (EIO);
834 	if (proc != NULL) {
835 		_PHOLD(proc);
836 		PROC_UNLOCK(proc);
837 	}
838 
839 	if (pn->pn_flags & PFS_RAWWR) {
840 		pfs_lock(pn);
841 		error = pn_fill(curthread, proc, pn, NULL, uio);
842 		pfs_unlock(pn);
843 		if (proc != NULL)
844 			PRELE(proc);
845 		PFS_RETURN (error);
846 	}
847 
848 	sbuf_uionew(&sb, uio, &error);
849 	if (error) {
850 		if (proc != NULL)
851 			PRELE(proc);
852 		PFS_RETURN (error);
853 	}
854 
855 	error = pn_fill(curthread, proc, pn, &sb, uio);
856 
857 	sbuf_delete(&sb);
858 	if (proc != NULL)
859 		PRELE(proc);
860 	PFS_RETURN (error);
861 }
862 
863 /*
864  * Vnode operations
865  */
866 struct vop_vector pfs_vnodeops = {
867 	.vop_default =		&default_vnodeops,
868 
869 	.vop_access =		pfs_access,
870 	.vop_cachedlookup =	pfs_lookup,
871 	.vop_close =		pfs_close,
872 	.vop_create =		VOP_EOPNOTSUPP,
873 	.vop_getattr =		pfs_getattr,
874 	.vop_getextattr =	pfs_getextattr,
875 	.vop_ioctl =		pfs_ioctl,
876 	.vop_link =		VOP_EOPNOTSUPP,
877 	.vop_lookup =		vfs_cache_lookup,
878 	.vop_mkdir =		VOP_EOPNOTSUPP,
879 	.vop_mknod =		VOP_EOPNOTSUPP,
880 	.vop_open =		pfs_open,
881 	.vop_read =		pfs_read,
882 	.vop_readdir =		pfs_readdir,
883 	.vop_readlink =		pfs_readlink,
884 	.vop_reclaim =		pfs_reclaim,
885 	.vop_remove =		VOP_EOPNOTSUPP,
886 	.vop_rename =		VOP_EOPNOTSUPP,
887 	.vop_rmdir =		VOP_EOPNOTSUPP,
888 	.vop_setattr =		pfs_setattr,
889 	.vop_symlink =		VOP_EOPNOTSUPP,
890 	.vop_write =		pfs_write,
891 	/* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */
892 };
893