xref: /freebsd/sys/fs/pseudofs/pseudofs_vnops.c (revision f9218d3d4fd34f082473b3a021c6d4d109fb47cf)
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 	VATTR_NULL(vap);
167 	vap->va_type = vn->v_type;
168 	vap->va_fileid = pn->pn_fileno;
169 	vap->va_flags = 0;
170 	vap->va_blocksize = PAGE_SIZE;
171 	vap->va_bytes = vap->va_size = 0;
172 	vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
173 	vap->va_nlink = 1;
174 	nanotime(&vap->va_ctime);
175 	vap->va_atime = vap->va_mtime = vap->va_ctime;
176 
177 	switch (pn->pn_type) {
178 	case pfstype_procdir:
179 	case pfstype_root:
180 	case pfstype_dir:
181 		vap->va_mode = 0555;
182 		break;
183 	case pfstype_file:
184 	case pfstype_symlink:
185 		vap->va_mode = 0444;
186 		break;
187 	default:
188 		printf("shouldn't be here!\n");
189 		vap->va_mode = 0;
190 		break;
191 	}
192 
193 	if (pvd->pvd_pid != NO_PID) {
194 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
195 			PFS_RETURN (ENOENT);
196 		vap->va_uid = proc->p_ucred->cr_ruid;
197 		vap->va_gid = proc->p_ucred->cr_rgid;
198 		if (pn->pn_attr != NULL)
199 			error = (pn->pn_attr)(va->a_td, proc, pn, vap);
200 		PROC_UNLOCK(proc);
201 	} else {
202 		vap->va_uid = 0;
203 		vap->va_gid = 0;
204 	}
205 
206 	PFS_RETURN (error);
207 }
208 
209 /*
210  * Perform an ioctl
211  */
212 static int
213 pfs_ioctl(struct vop_ioctl_args *va)
214 {
215 	struct vnode *vn = va->a_vp;
216 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
217 	struct pfs_node *pn = pvd->pvd_pn;
218 	struct proc *proc = NULL;
219 	int error;
220 
221 	PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
222 
223 	if (vn->v_type != VREG)
224 		PFS_RETURN (EINVAL);
225 
226 	if (pn->pn_ioctl == NULL)
227 		PFS_RETURN (ENOTTY);
228 
229 	/*
230 	 * This is necessary because either process' privileges may
231 	 * have changed since the open() call.
232 	 */
233 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
234 		PFS_RETURN (EIO);
235 
236 	/* XXX duplicates bits of pfs_visible() */
237 	if (pvd->pvd_pid != NO_PID) {
238 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
239 			PFS_RETURN (EIO);
240 		_PHOLD(proc);
241 		PROC_UNLOCK(proc);
242 	}
243 
244 	error = (pn->pn_ioctl)(curthread, proc, pn, va->a_command, va->a_data);
245 
246 	if (proc != NULL)
247 		PRELE(proc);
248 
249 	PFS_RETURN (error);
250 }
251 
252 /*
253  * Perform getextattr
254  */
255 static int
256 pfs_getextattr(struct vop_getextattr_args *va)
257 {
258 	struct vnode *vn = va->a_vp;
259 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
260 	struct pfs_node *pn = pvd->pvd_pn;
261 	struct proc *proc = NULL;
262 	int error;
263 
264 	PFS_TRACE((pd->pn_name));
265 
266 	if (pn->pn_getextattr == NULL)
267 		PFS_RETURN (EOPNOTSUPP);
268 
269 	/*
270 	 * This is necessary because either process' privileges may
271 	 * have changed since the open() call.
272 	 */
273 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
274 		PFS_RETURN (EIO);
275 
276 	/* XXX duplicates bits of pfs_visible() */
277 	if (pvd->pvd_pid != NO_PID) {
278 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
279 			PFS_RETURN (EIO);
280 		_PHOLD(proc);
281 		PROC_UNLOCK(proc);
282 	}
283 
284 	error = (pn->pn_getextattr)(curthread, proc, pn, va->a_attrnamespace,
285 	    va->a_name, va->a_uio, va->a_size, va->a_cred);
286 
287 	if (proc != NULL)
288 		PRELE(proc);
289 
290 	PFS_RETURN (error);
291 }
292 
293 /*
294  * Look up a file or directory
295  *
296  * XXX NOTE!  pfs_lookup() has been hooked into vop_lookup_desc!  This
297  * will result in a lookup operation for a vnode which may already be
298  * cached, therefore we have to be careful to purge the VFS cache when
299  * reusing a vnode.
300  *
301  * This code will work, but is not really correct.  Normally we would hook
302  * vfs_cache_lookup() into vop_lookup_desc and hook pfs_lookup() into
303  * vop_cachedlookup_desc.
304  */
305 static int
306 pfs_lookup(struct vop_lookup_args *va)
307 {
308 	struct vnode *vn = va->a_dvp;
309 	struct vnode **vpp = va->a_vpp;
310 	struct componentname *cnp = va->a_cnp;
311 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
312 	struct pfs_node *pd = pvd->pvd_pn;
313 	struct pfs_node *pn, *pdn = NULL;
314 	pid_t pid = pvd->pvd_pid;
315 	int lockparent;
316 	int wantparent;
317 	char *pname;
318 	int error, i, namelen;
319 
320 	PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
321 
322 	cnp->cn_flags &= ~PDIRUNLOCK;
323 
324 	if (vn->v_type != VDIR)
325 		PFS_RETURN (ENOTDIR);
326 
327 	/*
328 	 * Don't support DELETE or RENAME.  CREATE is supported so
329 	 * that O_CREAT will work, but the lookup will still fail if
330 	 * the file does not exist.
331 	 */
332 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
333 		PFS_RETURN (EOPNOTSUPP);
334 
335 	/* shortcut: check if the name is too long */
336 	if (cnp->cn_namelen >= PFS_NAMELEN)
337 		PFS_RETURN (ENOENT);
338 
339 	/* check that parent directory is visisble... */
340 	if (!pfs_visible(curthread, pd, pvd->pvd_pid))
341 		PFS_RETURN (ENOENT);
342 
343 	lockparent = cnp->cn_flags & LOCKPARENT;
344 	wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
345 
346 
347 	/* self */
348 	namelen = cnp->cn_namelen;
349 	pname = cnp->cn_nameptr;
350 	if (namelen == 1 && *pname == '.') {
351 		pn = pd;
352 		*vpp = vn;
353 		VREF(vn);
354 		PFS_RETURN (0);
355 	}
356 
357 	/* parent */
358 	if (cnp->cn_flags & ISDOTDOT) {
359 		if (pd->pn_type == pfstype_root)
360 			PFS_RETURN (EIO);
361 		VOP_UNLOCK(vn, 0, cnp->cn_thread);
362 		cnp->cn_flags |= PDIRUNLOCK;
363 
364 		KASSERT(pd->pn_parent, ("non-root directory has no parent"));
365 		/*
366 		 * This one is tricky.  Descendents of procdir nodes
367 		 * inherit their parent's process affinity, but
368 		 * there's no easy reverse mapping.  For simplicity,
369 		 * we assume that if this node is a procdir, its
370 		 * parent isn't (which is correct as long as
371 		 * descendents of procdir nodes are never procdir
372 		 * nodes themselves)
373 		 */
374 		if (pd->pn_type == pfstype_procdir)
375 			pid = NO_PID;
376 		pn = pd->pn_parent;
377 		goto got_pnode;
378 	}
379 
380 	/* named node */
381 	for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
382 		if (pn->pn_type == pfstype_procdir)
383 			pdn = pn;
384 		else if (pn->pn_name[namelen] == '\0'
385 		    && bcmp(pname, pn->pn_name, namelen) == 0)
386 			goto got_pnode;
387 
388 	/* process dependent node */
389 	if ((pn = pdn) != NULL) {
390 		pid = 0;
391 		for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
392 			if ((pid = pid * 10 + pname[i] - '0') > PID_MAX)
393 				break;
394 		if (i == cnp->cn_namelen)
395 			goto got_pnode;
396 	}
397 
398 	PFS_RETURN (ENOENT);
399  got_pnode:
400 	if (pn != pd->pn_parent && !pn->pn_parent)
401 		pn->pn_parent = pd;
402 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
403 		PFS_RETURN (ENOENT);
404 
405 	error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid);
406 	if (error)
407 		PFS_RETURN (error);
408 
409 	if ((cnp->cn_flags & ISDOTDOT) && (cnp->cn_flags & ISLASTCN)
410 	    && lockparent) {
411 		vn_lock(vn, LK_EXCLUSIVE|LK_RETRY, cnp->cn_thread);
412 		cnp->cn_flags &= ~PDIRUNLOCK;
413 	}
414 	if (!lockparent || !(cnp->cn_flags & ISLASTCN))
415 		VOP_UNLOCK(vn, 0, cnp->cn_thread);
416 
417 	/*
418 	 * XXX See comment at top of the routine.
419 	 */
420 	if (cnp->cn_flags & MAKEENTRY)
421 		cache_enter(vn, *vpp, cnp);
422 	PFS_RETURN (0);
423 }
424 
425 /*
426  * Open a file or directory.
427  */
428 static int
429 pfs_open(struct vop_open_args *va)
430 {
431 	struct vnode *vn = va->a_vp;
432 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
433 	struct pfs_node *pn = pvd->pvd_pn;
434 	int mode = va->a_mode;
435 
436 	PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
437 
438 	/*
439 	 * check if the file is visible to the caller
440 	 *
441 	 * XXX Not sure if this is necessary, as the VFS system calls
442 	 * XXX pfs_lookup() and pfs_access() first, and pfs_lookup()
443 	 * XXX calls pfs_visible().  There's a race condition here, but
444 	 * XXX calling pfs_visible() from here doesn't really close it,
445 	 * XXX and the only consequence of that race is an EIO further
446 	 * XXX down the line.
447 	 */
448 	if (!pfs_visible(va->a_td, pn, pvd->pvd_pid))
449 		PFS_RETURN (ENOENT);
450 
451 	/* check if the requested mode is permitted */
452 	if (((mode & FREAD) && !(mode & PFS_RD)) ||
453 	    ((mode & FWRITE) && !(mode & PFS_WR)))
454 		PFS_RETURN (EPERM);
455 
456 	/* we don't support locking */
457 	if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
458 		PFS_RETURN (EOPNOTSUPP);
459 
460 	PFS_RETURN (0);
461 }
462 
463 /*
464  * Read from a file
465  */
466 static int
467 pfs_read(struct vop_read_args *va)
468 {
469 	struct vnode *vn = va->a_vp;
470 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
471 	struct pfs_node *pn = pvd->pvd_pn;
472 	struct uio *uio = va->a_uio;
473 	struct proc *proc = NULL;
474 	struct sbuf *sb = NULL;
475 	char *ps;
476 	int error, xlen;
477 
478 	PFS_TRACE((pn->pn_name));
479 
480 	if (vn->v_type != VREG)
481 		PFS_RETURN (EINVAL);
482 
483 	if (!(pn->pn_flags & PFS_RD))
484 		PFS_RETURN (EBADF);
485 
486 	if (pn->pn_func == NULL)
487 		PFS_RETURN (EIO);
488 
489 	/*
490 	 * This is necessary because either process' privileges may
491 	 * have changed since the open() call.
492 	 */
493 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
494 		PFS_RETURN (EIO);
495 
496 	/* XXX duplicates bits of pfs_visible() */
497 	if (pvd->pvd_pid != NO_PID) {
498 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
499 			PFS_RETURN (EIO);
500 		_PHOLD(proc);
501 		PROC_UNLOCK(proc);
502 	}
503 
504 	if (pn->pn_flags & PFS_RAWRD) {
505 		error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
506 		if (proc != NULL)
507 			PRELE(proc);
508 		PFS_RETURN (error);
509 	}
510 
511 	sb = sbuf_new(sb, NULL, uio->uio_offset + uio->uio_resid, 0);
512 	if (sb == NULL) {
513 		if (proc != NULL)
514 			PRELE(proc);
515 		PFS_RETURN (EIO);
516 	}
517 
518 	error = (pn->pn_func)(curthread, proc, pn, sb, uio);
519 
520 	if (proc != NULL)
521 		PRELE(proc);
522 
523 	if (error) {
524 		sbuf_delete(sb);
525 		PFS_RETURN (error);
526 	}
527 
528 	/* XXX we should possibly detect and handle overflows */
529 	sbuf_finish(sb);
530 	ps = sbuf_data(sb) + uio->uio_offset;
531 	xlen = sbuf_len(sb) - uio->uio_offset;
532 	xlen = imin(xlen, uio->uio_resid);
533 	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
534 	sbuf_delete(sb);
535 	PFS_RETURN (error);
536 }
537 
538 /*
539  * Iterate through directory entries
540  */
541 static int
542 pfs_iterate(struct thread *td, pid_t pid, struct pfs_node *pd,
543 	    struct pfs_node **pn, struct proc **p)
544 {
545 	if ((*pn) == NULL)
546 		*pn = pd->pn_nodes;
547 	else
548  again:
549 	if ((*pn)->pn_type != pfstype_procdir)
550 		*pn = (*pn)->pn_next;
551 
552 	while (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
553 		if (*p == NULL)
554 			*p = LIST_FIRST(&allproc);
555 		else
556 			*p = LIST_NEXT(*p, p_list);
557 		if (*p != NULL)
558 			break;
559 		*pn = (*pn)->pn_next;
560 	}
561 
562 	if ((*pn) == NULL)
563 		return (-1);
564 
565 	if (!pfs_visible(td, *pn, *p ? (*p)->p_pid : pid))
566 		goto again;
567 
568 	return (0);
569 }
570 
571 /*
572  * Return directory entries.
573  */
574 static int
575 pfs_readdir(struct vop_readdir_args *va)
576 {
577 	struct vnode *vn = va->a_vp;
578 	struct pfs_info *pi = (struct pfs_info *)vn->v_mount->mnt_data;
579 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
580 	struct pfs_node *pd = pvd->pvd_pn;
581 	pid_t pid = pvd->pvd_pid;
582 	struct pfs_node *pn;
583 	struct dirent entry;
584 	struct uio *uio;
585 	struct proc *p;
586 	off_t offset;
587 	int error, i, resid;
588 
589 	PFS_TRACE((pd->pn_name));
590 
591 	if (vn->v_type != VDIR)
592 		PFS_RETURN (ENOTDIR);
593 	uio = va->a_uio;
594 
595 	/* check if the directory is visible to the caller */
596 	if (!pfs_visible(curthread, pd, pid))
597 		PFS_RETURN (ENOENT);
598 
599 	/* only allow reading entire entries */
600 	offset = uio->uio_offset;
601 	resid = uio->uio_resid;
602 	if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN)
603 		PFS_RETURN (EINVAL);
604 
605 	/* skip unwanted entries */
606 	sx_slock(&allproc_lock);
607 	for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN)
608 		if (pfs_iterate(curthread, pid, pd, &pn, &p) == -1) {
609 			/* nothing left... */
610 			sx_sunlock(&allproc_lock);
611 			PFS_RETURN (0);
612 		}
613 
614 	/* fill in entries */
615 	entry.d_reclen = PFS_DELEN;
616 	while (pfs_iterate(curthread, pid, pd, &pn, &p) != -1 && resid > 0) {
617 		if (!pn->pn_parent)
618 			pn->pn_parent = pd;
619 		if (!pn->pn_fileno)
620 			pfs_fileno_alloc(pi, pn);
621 		if (pid != NO_PID)
622 			entry.d_fileno = pn->pn_fileno * NO_PID + pid;
623 		else
624 			entry.d_fileno = pn->pn_fileno;
625 		/* PFS_DELEN was picked to fit PFS_NAMLEN */
626 		for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
627 			entry.d_name[i] = pn->pn_name[i];
628 		entry.d_name[i] = 0;
629 		entry.d_namlen = i;
630 		switch (pn->pn_type) {
631 		case pfstype_procdir:
632 			KASSERT(p != NULL,
633 			    ("reached procdir node with p == NULL"));
634 			entry.d_fileno = pn->pn_fileno * NO_PID + p->p_pid;
635 			entry.d_namlen = snprintf(entry.d_name,
636 			    PFS_NAMELEN, "%d", p->p_pid);
637 			/* fall through */
638 		case pfstype_root:
639 		case pfstype_dir:
640 		case pfstype_this:
641 		case pfstype_parent:
642 			entry.d_type = DT_DIR;
643 			break;
644 		case pfstype_file:
645 			entry.d_type = DT_REG;
646 			break;
647 		case pfstype_symlink:
648 			entry.d_type = DT_LNK;
649 			break;
650 		default:
651 			sx_sunlock(&allproc_lock);
652 			panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
653 		}
654 		PFS_TRACE((entry.d_name));
655 		if ((error = uiomove(&entry, PFS_DELEN, uio))) {
656 			sx_sunlock(&allproc_lock);
657 			PFS_RETURN (error);
658 		}
659 		offset += PFS_DELEN;
660 		resid -= PFS_DELEN;
661 	}
662 
663 	sx_sunlock(&allproc_lock);
664 	uio->uio_offset += offset;
665 	PFS_RETURN (0);
666 }
667 
668 /*
669  * Read a symbolic link
670  */
671 static int
672 pfs_readlink(struct vop_readlink_args *va)
673 {
674 	struct vnode *vn = va->a_vp;
675 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
676 	struct pfs_node *pn = pvd->pvd_pn;
677 	struct uio *uio = va->a_uio;
678 	struct proc *proc = NULL;
679 	char buf[MAXPATHLEN], *ps;
680 	struct sbuf sb;
681 	int error, xlen;
682 
683 	PFS_TRACE((pn->pn_name));
684 
685 	if (vn->v_type != VLNK)
686 		PFS_RETURN (EINVAL);
687 
688 	if (pn->pn_func == NULL)
689 		PFS_RETURN (EIO);
690 
691 	if (pvd->pvd_pid != NO_PID) {
692 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
693 			PFS_RETURN (EIO);
694 		_PHOLD(proc);
695 		PROC_UNLOCK(proc);
696 	}
697 
698 	/* sbuf_new() can't fail with a static buffer */
699 	sbuf_new(&sb, buf, sizeof buf, 0);
700 
701 	error = (pn->pn_func)(curthread, proc, pn, &sb, NULL);
702 
703 	if (proc != NULL)
704 		PRELE(proc);
705 
706 	if (error) {
707 		sbuf_delete(&sb);
708 		PFS_RETURN (error);
709 	}
710 
711 	/* XXX we should detect and handle overflows */
712 	sbuf_finish(&sb);
713 	ps = sbuf_data(&sb) + uio->uio_offset;
714 	xlen = sbuf_len(&sb) - uio->uio_offset;
715 	xlen = imin(xlen, uio->uio_resid);
716 	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
717 	sbuf_delete(&sb);
718 	PFS_RETURN (error);
719 }
720 
721 /*
722  * Reclaim a vnode
723  */
724 static int
725 pfs_reclaim(struct vop_reclaim_args *va)
726 {
727 	PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
728 
729 	return (pfs_vncache_free(va->a_vp));
730 }
731 
732 /*
733  * Set attributes
734  */
735 static int
736 pfs_setattr(struct vop_setattr_args *va)
737 {
738 	PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
739 
740 	PFS_RETURN (EOPNOTSUPP);
741 }
742 
743 /*
744  * Read from a file
745  */
746 static int
747 pfs_write(struct vop_read_args *va)
748 {
749 	struct vnode *vn = va->a_vp;
750 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
751 	struct pfs_node *pn = pvd->pvd_pn;
752 	struct uio *uio = va->a_uio;
753 	struct proc *proc = NULL;
754 	struct sbuf sb;
755 	int error;
756 
757 	PFS_TRACE((pn->pn_name));
758 
759 	if (vn->v_type != VREG)
760 		PFS_RETURN (EINVAL);
761 
762 	if (!(pn->pn_flags & PFS_WR))
763 		PFS_RETURN (EBADF);
764 
765 	if (pn->pn_func == NULL)
766 		PFS_RETURN (EIO);
767 
768 	/*
769 	 * This is necessary because either process' privileges may
770 	 * have changed since the open() call.
771 	 */
772 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
773 		PFS_RETURN (EIO);
774 
775 	/* XXX duplicates bits of pfs_visible() */
776 	if (pvd->pvd_pid != NO_PID) {
777 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
778 			PFS_RETURN (EIO);
779 		_PHOLD(proc);
780 		PROC_UNLOCK(proc);
781 	}
782 
783 	if (pn->pn_flags & PFS_RAWWR) {
784 		error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
785 		if (proc != NULL)
786 			PRELE(proc);
787 		PFS_RETURN (error);
788 	}
789 
790 	sbuf_uionew(&sb, uio, &error);
791 	if (error)
792 		PFS_RETURN (error);
793 
794 	error = (pn->pn_func)(curthread, proc, pn, &sb, uio);
795 
796 	if (proc != NULL)
797 		PRELE(proc);
798 
799 	sbuf_delete(&sb);
800 	PFS_RETURN (error);
801 }
802 
803 /*
804  * Vnode operations
805  */
806 vop_t **pfs_vnodeop_p;
807 static struct vnodeopv_entry_desc pfs_vnodeop_entries[] = {
808 	{ &vop_default_desc,		(vop_t *)vop_defaultop	},
809 	{ &vop_access_desc,		(vop_t *)pfs_access	},
810 	{ &vop_close_desc,		(vop_t *)pfs_close	},
811 	{ &vop_create_desc,		(vop_t *)vop_eopnotsupp	},
812 	{ &vop_getattr_desc,		(vop_t *)pfs_getattr	},
813 	{ &vop_getextattr_desc,		(vop_t *)pfs_getextattr	},
814 	{ &vop_ioctl_desc,		(vop_t *)pfs_ioctl	},
815 	{ &vop_link_desc,		(vop_t *)vop_eopnotsupp	},
816 	{ &vop_lookup_desc,		(vop_t *)pfs_lookup	},
817 	{ &vop_mkdir_desc,		(vop_t *)vop_eopnotsupp	},
818 	{ &vop_mknod_desc,		(vop_t *)vop_eopnotsupp	},
819 	{ &vop_open_desc,		(vop_t *)pfs_open	},
820 	{ &vop_read_desc,		(vop_t *)pfs_read	},
821 	{ &vop_readdir_desc,		(vop_t *)pfs_readdir	},
822 	{ &vop_readlink_desc,		(vop_t *)pfs_readlink	},
823 	{ &vop_reclaim_desc,		(vop_t *)pfs_reclaim	},
824 	{ &vop_remove_desc,		(vop_t *)vop_eopnotsupp	},
825 	{ &vop_rename_desc,		(vop_t *)vop_eopnotsupp	},
826 	{ &vop_rmdir_desc,		(vop_t *)vop_eopnotsupp	},
827 	{ &vop_setattr_desc,		(vop_t *)pfs_setattr	},
828 	{ &vop_symlink_desc,		(vop_t *)vop_eopnotsupp	},
829 	{ &vop_write_desc,		(vop_t *)pfs_write	},
830 	/* XXX I've probably forgotten a few that need vop_eopnotsupp */
831 	{ NULL,				(vop_t *)NULL		}
832 };
833 
834 static struct vnodeopv_desc pfs_vnodeop_opv_desc =
835 	{ &pfs_vnodeop_p, pfs_vnodeop_entries };
836 
837 VNODEOP_SET(pfs_vnodeop_opv_desc);
838