]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/pseudofs/pseudofs_vnops.c
add -n option to suppress clearing the build tree and add -DNO_CLEAN
[FreeBSD/FreeBSD.git] / sys / fs / pseudofs / pseudofs_vnops.c
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);
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         vap->va_type = vn->v_type;
195         vap->va_fileid = pn_fileno(pn, pvd->pvd_pid);
196         vap->va_flags = 0;
197         vap->va_blocksize = PAGE_SIZE;
198         vap->va_bytes = vap->va_size = 0;
199         vap->va_filerev = 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(curthread, 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 };