xref: /freebsd/sys/fs/pseudofs/pseudofs_vnops.c (revision e0c27215058b5786c78fcfb3963eebe61a989511)
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 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 	    (cnp->cn_flags & ISDOTDOT)))
416 		VOP_UNLOCK(vn, 0, cnp->cn_thread);
417 
418 	/*
419 	 * XXX See comment at top of the routine.
420 	 */
421 	if (cnp->cn_flags & MAKEENTRY)
422 		cache_enter(vn, *vpp, cnp);
423 	PFS_RETURN (0);
424 }
425 
426 /*
427  * Open a file or directory.
428  */
429 static int
430 pfs_open(struct vop_open_args *va)
431 {
432 	struct vnode *vn = va->a_vp;
433 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
434 	struct pfs_node *pn = pvd->pvd_pn;
435 	int mode = va->a_mode;
436 
437 	PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
438 
439 	/*
440 	 * check if the file is visible to the caller
441 	 *
442 	 * XXX Not sure if this is necessary, as the VFS system calls
443 	 * XXX pfs_lookup() and pfs_access() first, and pfs_lookup()
444 	 * XXX calls pfs_visible().  There's a race condition here, but
445 	 * XXX calling pfs_visible() from here doesn't really close it,
446 	 * XXX and the only consequence of that race is an EIO further
447 	 * XXX down the line.
448 	 */
449 	if (!pfs_visible(va->a_td, pn, pvd->pvd_pid))
450 		PFS_RETURN (ENOENT);
451 
452 	/* check if the requested mode is permitted */
453 	if (((mode & FREAD) && !(mode & PFS_RD)) ||
454 	    ((mode & FWRITE) && !(mode & PFS_WR)))
455 		PFS_RETURN (EPERM);
456 
457 	/* we don't support locking */
458 	if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
459 		PFS_RETURN (EOPNOTSUPP);
460 
461 	PFS_RETURN (0);
462 }
463 
464 /*
465  * Read from a file
466  */
467 static int
468 pfs_read(struct vop_read_args *va)
469 {
470 	struct vnode *vn = va->a_vp;
471 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
472 	struct pfs_node *pn = pvd->pvd_pn;
473 	struct uio *uio = va->a_uio;
474 	struct proc *proc = NULL;
475 	struct sbuf *sb = NULL;
476 	char *ps;
477 	int error, xlen;
478 
479 	PFS_TRACE((pn->pn_name));
480 
481 	if (vn->v_type != VREG)
482 		PFS_RETURN (EINVAL);
483 
484 	if (!(pn->pn_flags & PFS_RD))
485 		PFS_RETURN (EBADF);
486 
487 	if (pn->pn_func == NULL)
488 		PFS_RETURN (EIO);
489 
490 	/*
491 	 * This is necessary because either process' privileges may
492 	 * have changed since the open() call.
493 	 */
494 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
495 		PFS_RETURN (EIO);
496 
497 	/* XXX duplicates bits of pfs_visible() */
498 	if (pvd->pvd_pid != NO_PID) {
499 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
500 			PFS_RETURN (EIO);
501 		_PHOLD(proc);
502 		PROC_UNLOCK(proc);
503 	}
504 
505 	if (pn->pn_flags & PFS_RAWRD) {
506 		error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
507 		if (proc != NULL)
508 			PRELE(proc);
509 		PFS_RETURN (error);
510 	}
511 
512 	sb = sbuf_new(sb, NULL, uio->uio_offset + uio->uio_resid, 0);
513 	if (sb == NULL) {
514 		if (proc != NULL)
515 			PRELE(proc);
516 		PFS_RETURN (EIO);
517 	}
518 
519 	error = (pn->pn_func)(curthread, proc, pn, sb, uio);
520 
521 	if (proc != NULL)
522 		PRELE(proc);
523 
524 	if (error) {
525 		sbuf_delete(sb);
526 		PFS_RETURN (error);
527 	}
528 
529 	/* XXX we should possibly detect and handle overflows */
530 	sbuf_finish(sb);
531 	ps = sbuf_data(sb) + uio->uio_offset;
532 	xlen = sbuf_len(sb) - uio->uio_offset;
533 	xlen = imin(xlen, uio->uio_resid);
534 	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
535 	sbuf_delete(sb);
536 	PFS_RETURN (error);
537 }
538 
539 /*
540  * Iterate through directory entries
541  */
542 static int
543 pfs_iterate(struct thread *td, pid_t pid, struct pfs_node *pd,
544 	    struct pfs_node **pn, struct proc **p)
545 {
546 	if ((*pn) == NULL)
547 		*pn = pd->pn_nodes;
548 	else
549  again:
550 	if ((*pn)->pn_type != pfstype_procdir)
551 		*pn = (*pn)->pn_next;
552 
553 	while (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
554 		if (*p == NULL)
555 			*p = LIST_FIRST(&allproc);
556 		else
557 			*p = LIST_NEXT(*p, p_list);
558 		if (*p != NULL)
559 			break;
560 		*pn = (*pn)->pn_next;
561 	}
562 
563 	if ((*pn) == NULL)
564 		return (-1);
565 
566 	if (!pfs_visible(td, *pn, *p ? (*p)->p_pid : pid))
567 		goto again;
568 
569 	return (0);
570 }
571 
572 /*
573  * Return directory entries.
574  */
575 static int
576 pfs_readdir(struct vop_readdir_args *va)
577 {
578 	struct vnode *vn = va->a_vp;
579 	struct pfs_info *pi = (struct pfs_info *)vn->v_mount->mnt_data;
580 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
581 	struct pfs_node *pd = pvd->pvd_pn;
582 	pid_t pid = pvd->pvd_pid;
583 	struct pfs_node *pn;
584 	struct dirent entry;
585 	struct uio *uio;
586 	struct proc *p;
587 	off_t offset;
588 	int error, i, resid;
589 
590 	PFS_TRACE((pd->pn_name));
591 
592 	if (vn->v_type != VDIR)
593 		PFS_RETURN (ENOTDIR);
594 	uio = va->a_uio;
595 
596 	/* check if the directory is visible to the caller */
597 	if (!pfs_visible(curthread, pd, pid))
598 		PFS_RETURN (ENOENT);
599 
600 	/* only allow reading entire entries */
601 	offset = uio->uio_offset;
602 	resid = uio->uio_resid;
603 	if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN)
604 		PFS_RETURN (EINVAL);
605 
606 	/* skip unwanted entries */
607 	sx_slock(&allproc_lock);
608 	for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN)
609 		if (pfs_iterate(curthread, pid, pd, &pn, &p) == -1) {
610 			/* nothing left... */
611 			sx_sunlock(&allproc_lock);
612 			PFS_RETURN (0);
613 		}
614 
615 	/* fill in entries */
616 	entry.d_reclen = PFS_DELEN;
617 	while (pfs_iterate(curthread, pid, pd, &pn, &p) != -1 && resid > 0) {
618 		if (!pn->pn_parent)
619 			pn->pn_parent = pd;
620 		if (!pn->pn_fileno)
621 			pfs_fileno_alloc(pi, pn);
622 		if (pid != NO_PID)
623 			entry.d_fileno = pn->pn_fileno * NO_PID + pid;
624 		else
625 			entry.d_fileno = pn->pn_fileno;
626 		/* PFS_DELEN was picked to fit PFS_NAMLEN */
627 		for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
628 			entry.d_name[i] = pn->pn_name[i];
629 		entry.d_name[i] = 0;
630 		entry.d_namlen = i;
631 		switch (pn->pn_type) {
632 		case pfstype_procdir:
633 			KASSERT(p != NULL,
634 			    ("reached procdir node with p == NULL"));
635 			entry.d_fileno = pn->pn_fileno * NO_PID + p->p_pid;
636 			entry.d_namlen = snprintf(entry.d_name,
637 			    PFS_NAMELEN, "%d", p->p_pid);
638 			/* fall through */
639 		case pfstype_root:
640 		case pfstype_dir:
641 		case pfstype_this:
642 		case pfstype_parent:
643 			entry.d_type = DT_DIR;
644 			break;
645 		case pfstype_file:
646 			entry.d_type = DT_REG;
647 			break;
648 		case pfstype_symlink:
649 			entry.d_type = DT_LNK;
650 			break;
651 		default:
652 			sx_sunlock(&allproc_lock);
653 			panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
654 		}
655 		PFS_TRACE((entry.d_name));
656 		if ((error = uiomove(&entry, PFS_DELEN, uio))) {
657 			sx_sunlock(&allproc_lock);
658 			PFS_RETURN (error);
659 		}
660 		offset += PFS_DELEN;
661 		resid -= PFS_DELEN;
662 	}
663 
664 	sx_sunlock(&allproc_lock);
665 	uio->uio_offset += offset;
666 	PFS_RETURN (0);
667 }
668 
669 /*
670  * Read a symbolic link
671  */
672 static int
673 pfs_readlink(struct vop_readlink_args *va)
674 {
675 	struct vnode *vn = va->a_vp;
676 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
677 	struct pfs_node *pn = pvd->pvd_pn;
678 	struct uio *uio = va->a_uio;
679 	struct proc *proc = NULL;
680 	char buf[MAXPATHLEN], *ps;
681 	struct sbuf sb;
682 	int error, xlen;
683 
684 	PFS_TRACE((pn->pn_name));
685 
686 	if (vn->v_type != VLNK)
687 		PFS_RETURN (EINVAL);
688 
689 	if (pn->pn_func == NULL)
690 		PFS_RETURN (EIO);
691 
692 	if (pvd->pvd_pid != NO_PID) {
693 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
694 			PFS_RETURN (EIO);
695 		_PHOLD(proc);
696 		PROC_UNLOCK(proc);
697 	}
698 
699 	/* sbuf_new() can't fail with a static buffer */
700 	sbuf_new(&sb, buf, sizeof buf, 0);
701 
702 	error = (pn->pn_func)(curthread, proc, pn, &sb, NULL);
703 
704 	if (proc != NULL)
705 		PRELE(proc);
706 
707 	if (error) {
708 		sbuf_delete(&sb);
709 		PFS_RETURN (error);
710 	}
711 
712 	/* XXX we should detect and handle overflows */
713 	sbuf_finish(&sb);
714 	ps = sbuf_data(&sb) + uio->uio_offset;
715 	xlen = sbuf_len(&sb) - uio->uio_offset;
716 	xlen = imin(xlen, uio->uio_resid);
717 	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
718 	sbuf_delete(&sb);
719 	PFS_RETURN (error);
720 }
721 
722 /*
723  * Reclaim a vnode
724  */
725 static int
726 pfs_reclaim(struct vop_reclaim_args *va)
727 {
728 	PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
729 
730 	return (pfs_vncache_free(va->a_vp));
731 }
732 
733 /*
734  * Set attributes
735  */
736 static int
737 pfs_setattr(struct vop_setattr_args *va)
738 {
739 	PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
740 
741 	PFS_RETURN (EOPNOTSUPP);
742 }
743 
744 /*
745  * Read from a file
746  */
747 static int
748 pfs_write(struct vop_read_args *va)
749 {
750 	struct vnode *vn = va->a_vp;
751 	struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
752 	struct pfs_node *pn = pvd->pvd_pn;
753 	struct uio *uio = va->a_uio;
754 	struct proc *proc = NULL;
755 	struct sbuf sb;
756 	int error;
757 
758 	PFS_TRACE((pn->pn_name));
759 
760 	if (vn->v_type != VREG)
761 		PFS_RETURN (EINVAL);
762 
763 	if (!(pn->pn_flags & PFS_WR))
764 		PFS_RETURN (EBADF);
765 
766 	if (pn->pn_func == NULL)
767 		PFS_RETURN (EIO);
768 
769 	/*
770 	 * This is necessary because either process' privileges may
771 	 * have changed since the open() call.
772 	 */
773 	if (!pfs_visible(curthread, pn, pvd->pvd_pid))
774 		PFS_RETURN (EIO);
775 
776 	/* XXX duplicates bits of pfs_visible() */
777 	if (pvd->pvd_pid != NO_PID) {
778 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
779 			PFS_RETURN (EIO);
780 		_PHOLD(proc);
781 		PROC_UNLOCK(proc);
782 	}
783 
784 	if (pn->pn_flags & PFS_RAWWR) {
785 		error = (pn->pn_func)(curthread, proc, pn, NULL, uio);
786 		if (proc != NULL)
787 			PRELE(proc);
788 		PFS_RETURN (error);
789 	}
790 
791 	sbuf_uionew(&sb, uio, &error);
792 	if (error)
793 		PFS_RETURN (error);
794 
795 	error = (pn->pn_func)(curthread, proc, pn, &sb, uio);
796 
797 	if (proc != NULL)
798 		PRELE(proc);
799 
800 	sbuf_delete(&sb);
801 	PFS_RETURN (error);
802 }
803 
804 /*
805  * Vnode operations
806  */
807 vop_t **pfs_vnodeop_p;
808 static struct vnodeopv_entry_desc pfs_vnodeop_entries[] = {
809 	{ &vop_default_desc,		(vop_t *)vop_defaultop	},
810 	{ &vop_access_desc,		(vop_t *)pfs_access	},
811 	{ &vop_close_desc,		(vop_t *)pfs_close	},
812 	{ &vop_create_desc,		(vop_t *)vop_eopnotsupp	},
813 	{ &vop_getattr_desc,		(vop_t *)pfs_getattr	},
814 	{ &vop_getextattr_desc,		(vop_t *)pfs_getextattr	},
815 	{ &vop_ioctl_desc,		(vop_t *)pfs_ioctl	},
816 	{ &vop_link_desc,		(vop_t *)vop_eopnotsupp	},
817 	{ &vop_lookup_desc,		(vop_t *)pfs_lookup	},
818 	{ &vop_mkdir_desc,		(vop_t *)vop_eopnotsupp	},
819 	{ &vop_mknod_desc,		(vop_t *)vop_eopnotsupp	},
820 	{ &vop_open_desc,		(vop_t *)pfs_open	},
821 	{ &vop_read_desc,		(vop_t *)pfs_read	},
822 	{ &vop_readdir_desc,		(vop_t *)pfs_readdir	},
823 	{ &vop_readlink_desc,		(vop_t *)pfs_readlink	},
824 	{ &vop_reclaim_desc,		(vop_t *)pfs_reclaim	},
825 	{ &vop_remove_desc,		(vop_t *)vop_eopnotsupp	},
826 	{ &vop_rename_desc,		(vop_t *)vop_eopnotsupp	},
827 	{ &vop_rmdir_desc,		(vop_t *)vop_eopnotsupp	},
828 	{ &vop_setattr_desc,		(vop_t *)pfs_setattr	},
829 	{ &vop_symlink_desc,		(vop_t *)vop_eopnotsupp	},
830 	{ &vop_write_desc,		(vop_t *)pfs_write	},
831 	/* XXX I've probably forgotten a few that need vop_eopnotsupp */
832 	{ NULL,				(vop_t *)NULL		}
833 };
834 
835 static struct vnodeopv_desc pfs_vnodeop_opv_desc =
836 	{ &pfs_vnodeop_p, pfs_vnodeop_entries };
837 
838 VNODEOP_SET(pfs_vnodeop_opv_desc);
839