]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/fs/pseudofs/pseudofs_vnops.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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, 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         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(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, cnp->cn_thread);
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, cnp->cn_thread);
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, cnp->cn_thread);
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, locked;
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         vhold(vn);
506         locked = VOP_ISLOCKED(vn, curthread);
507         VOP_UNLOCK(vn, 0, curthread);
508
509         if (pn->pn_flags & PFS_RAWRD) {
510                 PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
511                 error = pn_fill(curthread, proc, pn, NULL, uio);
512                 PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
513                 goto ret;
514         }
515
516         /* beaucoup sanity checks so we don't ask for bogus allocation */
517         if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
518             (offset = uio->uio_offset) != uio->uio_offset ||
519             (resid = uio->uio_resid) != uio->uio_resid ||
520             (buflen = offset + resid + 1) < offset || buflen > INT_MAX) {
521                 if (proc != NULL)
522                         PRELE(proc);
523                 error = EINVAL;
524                 goto ret;
525         }
526         if (buflen > MAXPHYS + 1) {
527                 error = EIO;
528                 goto ret;
529         }
530
531         sb = sbuf_new(sb, NULL, buflen, 0);
532         if (sb == NULL) {
533                 error = EIO;
534                 goto ret;
535         }
536
537         error = pn_fill(curthread, proc, pn, sb, uio);
538
539         if (error) {
540                 sbuf_delete(sb);
541                 goto ret;
542         }
543
544         sbuf_finish(sb);
545         error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
546         sbuf_delete(sb);
547 ret:
548         vn_lock(vn, locked | LK_RETRY, curthread);
549         vdrop(vn);
550         if (proc != NULL)
551                 PRELE(proc);
552         PFS_RETURN (error);
553 }
554
555 /*
556  * Iterate through directory entries
557  */
558 static int
559 pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd,
560             struct pfs_node **pn, struct proc **p)
561 {
562         int visible;
563
564         sx_assert(&allproc_lock, SX_SLOCKED);
565         pfs_assert_owned(pd);
566  again:
567         if (*pn == NULL) {
568                 /* first node */
569                 *pn = pd->pn_nodes;
570         } else if ((*pn)->pn_type != pfstype_procdir) {
571                 /* next node */
572                 *pn = (*pn)->pn_next;
573         }
574         if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
575                 /* next process */
576                 if (*p == NULL)
577                         *p = LIST_FIRST(&allproc);
578                 else
579                         *p = LIST_NEXT(*p, p_list);
580                 /* out of processes: next node */
581                 if (*p == NULL)
582                         *pn = (*pn)->pn_next;
583                 else
584                         PROC_LOCK(*p);
585         }
586
587         if ((*pn) == NULL)
588                 return (-1);
589
590         if (*p != NULL) {
591                 visible = pfs_visible_proc(td, *pn, *p);
592                 PROC_UNLOCK(*p);
593         } else if (proc != NULL) {
594                 visible = pfs_visible_proc(td, *pn, proc);
595         } else {
596                 visible = 1;
597         }
598         if (!visible)
599                 goto again;
600
601         return (0);
602 }
603
604 /*
605  * Return directory entries.
606  */
607 static int
608 pfs_readdir(struct vop_readdir_args *va)
609 {
610         struct vnode *vn = va->a_vp;
611         struct pfs_vdata *pvd = vn->v_data;
612         struct pfs_node *pd = pvd->pvd_pn;
613         pid_t pid = pvd->pvd_pid;
614         struct proc *p, *proc;
615         struct pfs_node *pn;
616         struct dirent *entry;
617         struct uio *uio;
618         off_t offset;
619         int error, i, resid;
620         char *buf, *ent;
621
622         KASSERT(pd->pn_info == vn->v_mount->mnt_data,
623             ("%s(): pn_info does not match mountpoint", __func__));
624         PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid));
625         pfs_assert_not_owned(pd);
626
627         if (vn->v_type != VDIR)
628                 PFS_RETURN (ENOTDIR);
629         uio = va->a_uio;
630
631         /* only allow reading entire entries */
632         offset = uio->uio_offset;
633         resid = uio->uio_resid;
634         if (offset < 0 || offset % PFS_DELEN != 0 ||
635             (resid && resid < PFS_DELEN))
636                 PFS_RETURN (EINVAL);
637         if (resid == 0)
638                 PFS_RETURN (0);
639
640         /* can't do this while holding the proc lock... */
641         buf = malloc(resid, M_IOV, M_WAITOK | M_ZERO);
642         sx_slock(&allproc_lock);
643         pfs_lock(pd);
644
645         /* check if the directory is visible to the caller */
646         if (!pfs_visible(curthread, pd, pid, &proc)) {
647                 sx_sunlock(&allproc_lock);
648                 pfs_unlock(pd);
649                 free(buf, M_IOV);
650                 PFS_RETURN (ENOENT);
651         }
652         KASSERT(pid == NO_PID || proc != NULL,
653             ("%s(): no process for pid %lu", __func__, (unsigned long)pid));
654
655         /* skip unwanted entries */
656         for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) {
657                 if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) {
658                         /* nothing left... */
659                         if (proc != NULL)
660                                 PROC_UNLOCK(proc);
661                         pfs_unlock(pd);
662                         sx_sunlock(&allproc_lock);
663                         free(buf, M_IOV);
664                         PFS_RETURN (0);
665                 }
666         }
667
668         /* fill in entries */
669         ent = buf;
670         while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 &&
671             resid >= PFS_DELEN) {
672                 entry = (struct dirent *)ent;
673                 entry->d_reclen = PFS_DELEN;
674                 entry->d_fileno = pn_fileno(pn, pid);
675                 /* PFS_DELEN was picked to fit PFS_NAMLEN */
676                 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
677                         entry->d_name[i] = pn->pn_name[i];
678                 entry->d_name[i] = 0;
679                 entry->d_namlen = i;
680                 switch (pn->pn_type) {
681                 case pfstype_procdir:
682                         KASSERT(p != NULL,
683                             ("reached procdir node with p == NULL"));
684                         entry->d_namlen = snprintf(entry->d_name,
685                             PFS_NAMELEN, "%d", p->p_pid);
686                         /* fall through */
687                 case pfstype_root:
688                 case pfstype_dir:
689                 case pfstype_this:
690                 case pfstype_parent:
691                         entry->d_type = DT_DIR;
692                         break;
693                 case pfstype_file:
694                         entry->d_type = DT_REG;
695                         break;
696                 case pfstype_symlink:
697                         entry->d_type = DT_LNK;
698                         break;
699                 default:
700                         panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
701                 }
702                 PFS_TRACE(("%s", entry->d_name));
703                 offset += PFS_DELEN;
704                 resid -= PFS_DELEN;
705                 ent += PFS_DELEN;
706         }
707         if (proc != NULL)
708                 PROC_UNLOCK(proc);
709         pfs_unlock(pd);
710         sx_sunlock(&allproc_lock);
711         PFS_TRACE(("%zd bytes", ent - buf));
712         error = uiomove(buf, ent - buf, uio);
713         free(buf, M_IOV);
714         PFS_RETURN (error);
715 }
716
717 /*
718  * Read a symbolic link
719  */
720 static int
721 pfs_readlink(struct vop_readlink_args *va)
722 {
723         struct vnode *vn = va->a_vp;
724         struct pfs_vdata *pvd = vn->v_data;
725         struct pfs_node *pn = pvd->pvd_pn;
726         struct uio *uio = va->a_uio;
727         struct proc *proc = NULL;
728         char buf[PATH_MAX];
729         struct sbuf sb;
730         int error;
731
732         PFS_TRACE(("%s", pn->pn_name));
733         pfs_assert_not_owned(pn);
734
735         if (vn->v_type != VLNK)
736                 PFS_RETURN (EINVAL);
737
738         if (pn->pn_fill == NULL)
739                 PFS_RETURN (EIO);
740
741         if (pvd->pvd_pid != NO_PID) {
742                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
743                         PFS_RETURN (EIO);
744                 if (proc->p_flag & P_WEXIT) {
745                         PROC_UNLOCK(proc);
746                         PFS_RETURN (EIO);
747                 }
748                 _PHOLD(proc);
749                 PROC_UNLOCK(proc);
750         }
751
752         /* sbuf_new() can't fail with a static buffer */
753         sbuf_new(&sb, buf, sizeof buf, 0);
754
755         error = pn_fill(curthread, proc, pn, &sb, NULL);
756
757         if (proc != NULL)
758                 PRELE(proc);
759
760         if (error) {
761                 sbuf_delete(&sb);
762                 PFS_RETURN (error);
763         }
764
765         sbuf_finish(&sb);
766         error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
767         sbuf_delete(&sb);
768         PFS_RETURN (error);
769 }
770
771 /*
772  * Reclaim a vnode
773  */
774 static int
775 pfs_reclaim(struct vop_reclaim_args *va)
776 {
777         struct vnode *vn = va->a_vp;
778         struct pfs_vdata *pvd = vn->v_data;
779         struct pfs_node *pn = pvd->pvd_pn;
780
781         PFS_TRACE(("%s", pn->pn_name));
782         pfs_assert_not_owned(pn);
783
784         return (pfs_vncache_free(va->a_vp));
785 }
786
787 /*
788  * Set attributes
789  */
790 static int
791 pfs_setattr(struct vop_setattr_args *va)
792 {
793         struct vnode *vn = va->a_vp;
794         struct pfs_vdata *pvd = vn->v_data;
795         struct pfs_node *pn = pvd->pvd_pn;
796
797         PFS_TRACE(("%s", pn->pn_name));
798         pfs_assert_not_owned(pn);
799
800         PFS_RETURN (EOPNOTSUPP);
801 }
802
803 /*
804  * Write to a file
805  */
806 static int
807 pfs_write(struct vop_write_args *va)
808 {
809         struct vnode *vn = va->a_vp;
810         struct pfs_vdata *pvd = vn->v_data;
811         struct pfs_node *pn = pvd->pvd_pn;
812         struct uio *uio = va->a_uio;
813         struct proc *proc;
814         struct sbuf sb;
815         int error;
816
817         PFS_TRACE(("%s", pn->pn_name));
818         pfs_assert_not_owned(pn);
819
820         if (vn->v_type != VREG)
821                 PFS_RETURN (EINVAL);
822         KASSERT(pn->pn_type != pfstype_file,
823             ("%s(): VREG vnode refers to non-file pfs_node", __func__));
824
825         if (!(pn->pn_flags & PFS_WR))
826                 PFS_RETURN (EBADF);
827
828         if (pn->pn_fill == NULL)
829                 PFS_RETURN (EIO);
830
831         /*
832          * This is necessary because either process' privileges may
833          * have changed since the open() call.
834          */
835         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
836                 PFS_RETURN (EIO);
837         if (proc != NULL) {
838                 _PHOLD(proc);
839                 PROC_UNLOCK(proc);
840         }
841
842         if (pn->pn_flags & PFS_RAWWR) {
843                 pfs_lock(pn);
844                 error = pn_fill(curthread, proc, pn, NULL, uio);
845                 pfs_unlock(pn);
846                 if (proc != NULL)
847                         PRELE(proc);
848                 PFS_RETURN (error);
849         }
850
851         sbuf_uionew(&sb, uio, &error);
852         if (error) {
853                 if (proc != NULL)
854                         PRELE(proc);
855                 PFS_RETURN (error);
856         }
857
858         error = pn_fill(curthread, proc, pn, &sb, uio);
859
860         sbuf_delete(&sb);
861         if (proc != NULL)
862                 PRELE(proc);
863         PFS_RETURN (error);
864 }
865
866 /*
867  * Vnode operations
868  */
869 struct vop_vector pfs_vnodeops = {
870         .vop_default =          &default_vnodeops,
871
872         .vop_access =           pfs_access,
873         .vop_cachedlookup =     pfs_lookup,
874         .vop_close =            pfs_close,
875         .vop_create =           VOP_EOPNOTSUPP,
876         .vop_getattr =          pfs_getattr,
877         .vop_getextattr =       pfs_getextattr,
878         .vop_ioctl =            pfs_ioctl,
879         .vop_link =             VOP_EOPNOTSUPP,
880         .vop_lookup =           vfs_cache_lookup,
881         .vop_mkdir =            VOP_EOPNOTSUPP,
882         .vop_mknod =            VOP_EOPNOTSUPP,
883         .vop_open =             pfs_open,
884         .vop_read =             pfs_read,
885         .vop_readdir =          pfs_readdir,
886         .vop_readlink =         pfs_readlink,
887         .vop_reclaim =          pfs_reclaim,
888         .vop_remove =           VOP_EOPNOTSUPP,
889         .vop_rename =           VOP_EOPNOTSUPP,
890         .vop_rmdir =            VOP_EOPNOTSUPP,
891         .vop_setattr =          pfs_setattr,
892         .vop_symlink =          VOP_EOPNOTSUPP,
893         .vop_write =            pfs_write,
894         /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */
895 };