]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/pseudofs/pseudofs_vnops.c
libarchive: merge from vendor branch
[FreeBSD/FreeBSD.git] / sys / fs / pseudofs / pseudofs_vnops.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer
12  *    in this position and unchanged.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "opt_pseudofs.h"
35
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/systm.h>
39 #include <sys/ctype.h>
40 #include <sys/dirent.h>
41 #include <sys/fcntl.h>
42 #include <sys/limits.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/mount.h>
46 #include <sys/mutex.h>
47 #include <sys/namei.h>
48 #include <sys/proc.h>
49 #include <sys/sbuf.h>
50 #include <sys/sx.h>
51 #include <sys/sysctl.h>
52 #include <sys/vnode.h>
53
54 #include <fs/pseudofs/pseudofs.h>
55 #include <fs/pseudofs/pseudofs_internal.h>
56
57 #define KASSERT_PN_IS_DIR(pn)                                           \
58         KASSERT((pn)->pn_type == pfstype_root ||                        \
59             (pn)->pn_type == pfstype_dir ||                             \
60             (pn)->pn_type == pfstype_procdir,                           \
61             ("%s(): VDIR vnode refers to non-directory pfs_node", __func__))
62
63 #define KASSERT_PN_IS_FILE(pn)                                          \
64         KASSERT((pn)->pn_type == pfstype_file,                          \
65             ("%s(): VREG vnode refers to non-file pfs_node", __func__))
66
67 #define KASSERT_PN_IS_LINK(pn)                                          \
68         KASSERT((pn)->pn_type == pfstype_symlink,                       \
69             ("%s(): VLNK vnode refers to non-link pfs_node", __func__))
70
71 #define PFS_MAXBUFSIZ           1024 * 1024
72
73 /*
74  * Returns the fileno, adjusted for target pid
75  */
76 static uint32_t
77 pn_fileno(struct pfs_node *pn, pid_t pid)
78 {
79
80         KASSERT(pn->pn_fileno > 0,
81             ("%s(): no fileno allocated", __func__));
82         if (pid != NO_PID)
83                 return (pn->pn_fileno * NO_PID + pid);
84         return (pn->pn_fileno);
85 }
86
87 /*
88  * Returns non-zero if given file is visible to given thread.
89  */
90 static int
91 pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc)
92 {
93
94         if (proc == NULL)
95                 return (0);
96
97         PROC_LOCK_ASSERT(proc, MA_OWNED);
98
99         if ((proc->p_flag & P_WEXIT) != 0)
100                 return (0);
101         if (p_cansee(td, proc) != 0)
102                 return (0);
103         return (pn_vis(td, proc, pn));
104 }
105
106 static int
107 pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid,
108     struct proc **p)
109 {
110         struct proc *proc;
111
112         PFS_TRACE(("%s (pid: %d, req: %d)",
113             pn->pn_name, pid, td->td_proc->p_pid));
114
115         if (p)
116                 *p = NULL;
117         if (pid == NO_PID)
118                 PFS_RETURN (pn_vis(td, NULL, pn));
119         proc = pfind(pid);
120         if (proc == NULL)
121                 PFS_RETURN (0);
122         if (pfs_visible_proc(td, pn, proc)) {
123                 if (p)
124                         *p = proc;
125                 else
126                         PROC_UNLOCK(proc);
127                 PFS_RETURN (1);
128         }
129         PROC_UNLOCK(proc);
130         PFS_RETURN (0);
131 }
132
133 static int
134 pfs_lookup_proc(pid_t pid, struct proc **p)
135 {
136         struct proc *proc;
137
138         proc = pfind(pid);
139         if (proc == NULL)
140                 return (0);
141         if ((proc->p_flag & P_WEXIT) != 0) {
142                 PROC_UNLOCK(proc);
143                 return (0);
144         }
145         _PHOLD(proc);
146         PROC_UNLOCK(proc);
147         *p = proc;
148         return (1);
149 }
150
151 /*
152  * Verify permissions
153  */
154 static int
155 pfs_access(struct vop_access_args *va)
156 {
157         struct vnode *vn = va->a_vp;
158         struct pfs_vdata *pvd = vn->v_data;
159         struct vattr vattr;
160         int error;
161
162         PFS_TRACE(("%s", pvd->pvd_pn->pn_name));
163         (void)pvd;
164
165         error = VOP_GETATTR(vn, &vattr, va->a_cred);
166         if (error)
167                 PFS_RETURN (error);
168         error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, vattr.va_gid,
169             va->a_accmode, va->a_cred);
170         PFS_RETURN (error);
171 }
172
173 /*
174  * Close a file or directory
175  */
176 static int
177 pfs_close(struct vop_close_args *va)
178 {
179         struct vnode *vn = va->a_vp;
180         struct pfs_vdata *pvd = vn->v_data;
181         struct pfs_node *pn = pvd->pvd_pn;
182         struct proc *proc;
183         int error;
184
185         PFS_TRACE(("%s", pn->pn_name));
186         pfs_assert_not_owned(pn);
187
188         /*
189          * Do nothing unless this is the last close and the node has a
190          * last-close handler.
191          */
192         if (vrefcnt(vn) > 1 || pn->pn_close == NULL)
193                 PFS_RETURN (0);
194
195         if (pvd->pvd_pid != NO_PID) {
196                 proc = pfind(pvd->pvd_pid);
197         } else {
198                 proc = NULL;
199         }
200
201         error = pn_close(va->a_td, proc, pn);
202
203         if (proc != NULL)
204                 PROC_UNLOCK(proc);
205
206         PFS_RETURN (error);
207 }
208
209 /*
210  * Get file attributes
211  */
212 static int
213 pfs_getattr(struct vop_getattr_args *va)
214 {
215         struct vnode *vn = va->a_vp;
216         struct pfs_vdata *pvd = vn->v_data;
217         struct pfs_node *pn = pvd->pvd_pn;
218         struct vattr *vap = va->a_vap;
219         struct proc *proc;
220         int error = 0;
221
222         PFS_TRACE(("%s", pn->pn_name));
223         pfs_assert_not_owned(pn);
224
225         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
226                 PFS_RETURN (ENOENT);
227
228         vap->va_type = vn->v_type;
229         vap->va_fileid = pn_fileno(pn, pvd->pvd_pid);
230         vap->va_flags = 0;
231         vap->va_blocksize = PAGE_SIZE;
232         vap->va_bytes = vap->va_size = 0;
233         vap->va_filerev = 0;
234         vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
235         vap->va_nlink = 1;
236         nanotime(&vap->va_ctime);
237         vap->va_atime = vap->va_mtime = vap->va_ctime;
238
239         switch (pn->pn_type) {
240         case pfstype_procdir:
241         case pfstype_root:
242         case pfstype_dir:
243 #if 0
244                 pfs_lock(pn);
245                 /* compute link count */
246                 pfs_unlock(pn);
247 #endif
248                 vap->va_mode = 0555;
249                 break;
250         case pfstype_file:
251         case pfstype_symlink:
252                 vap->va_mode = 0444;
253                 break;
254         default:
255                 printf("shouldn't be here!\n");
256                 vap->va_mode = 0;
257                 break;
258         }
259
260         if (proc != NULL) {
261                 vap->va_uid = proc->p_ucred->cr_ruid;
262                 vap->va_gid = proc->p_ucred->cr_rgid;
263         } else {
264                 vap->va_uid = 0;
265                 vap->va_gid = 0;
266         }
267
268         if (pn->pn_attr != NULL)
269                 error = pn_attr(curthread, proc, pn, vap);
270
271         if(proc != NULL)
272                 PROC_UNLOCK(proc);
273
274         PFS_RETURN (error);
275 }
276
277 /*
278  * Perform an ioctl
279  */
280 static int
281 pfs_ioctl(struct vop_ioctl_args *va)
282 {
283         struct vnode *vn;
284         struct pfs_vdata *pvd;
285         struct pfs_node *pn;
286         struct proc *proc;
287         int error;
288
289         vn = va->a_vp;
290         vn_lock(vn, LK_SHARED | LK_RETRY);
291         if (VN_IS_DOOMED(vn)) {
292                 VOP_UNLOCK(vn);
293                 return (EBADF);
294         }
295         pvd = vn->v_data;
296         pn = pvd->pvd_pn;
297
298         PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
299         pfs_assert_not_owned(pn);
300
301         if (vn->v_type != VREG) {
302                 VOP_UNLOCK(vn);
303                 PFS_RETURN (EINVAL);
304         }
305         KASSERT_PN_IS_FILE(pn);
306
307         if (pn->pn_ioctl == NULL) {
308                 VOP_UNLOCK(vn);
309                 PFS_RETURN (ENOTTY);
310         }
311
312         /*
313          * This is necessary because process' privileges may
314          * have changed since the open() call.
315          */
316         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) {
317                 VOP_UNLOCK(vn);
318                 PFS_RETURN (EIO);
319         }
320
321         error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data);
322
323         if (proc != NULL)
324                 PROC_UNLOCK(proc);
325
326         VOP_UNLOCK(vn);
327         PFS_RETURN (error);
328 }
329
330 /*
331  * Perform getextattr
332  */
333 static int
334 pfs_getextattr(struct vop_getextattr_args *va)
335 {
336         struct vnode *vn = va->a_vp;
337         struct pfs_vdata *pvd = vn->v_data;
338         struct pfs_node *pn = pvd->pvd_pn;
339         struct proc *proc;
340         int error;
341
342         PFS_TRACE(("%s", pn->pn_name));
343         pfs_assert_not_owned(pn);
344
345         /*
346          * This is necessary because either process' privileges may
347          * have changed since the open() call.
348          */
349         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
350                 PFS_RETURN (EIO);
351
352         if (pn->pn_getextattr == NULL)
353                 error = EOPNOTSUPP;
354         else
355                 error = pn_getextattr(curthread, proc, pn,
356                     va->a_attrnamespace, va->a_name, va->a_uio,
357                     va->a_size, va->a_cred);
358
359         if (proc != NULL)
360                 PROC_UNLOCK(proc);
361
362         PFS_RETURN (error);
363 }
364
365 /*
366  * Convert a vnode to its component name
367  */
368 static int
369 pfs_vptocnp(struct vop_vptocnp_args *ap)
370 {
371         struct vnode *vp = ap->a_vp;
372         struct vnode **dvp = ap->a_vpp;
373         struct pfs_vdata *pvd = vp->v_data;
374         struct pfs_node *pd = pvd->pvd_pn;
375         struct pfs_node *pn;
376         struct mount *mp;
377         char *buf = ap->a_buf;
378         size_t *buflen = ap->a_buflen;
379         char pidbuf[PFS_NAMELEN];
380         pid_t pid = pvd->pvd_pid;
381         int len, i, error, locked;
382
383         i = *buflen;
384         error = 0;
385
386         pfs_lock(pd);
387
388         if (vp->v_type == VDIR && pd->pn_type == pfstype_root) {
389                 *dvp = vp;
390                 vhold(*dvp);
391                 pfs_unlock(pd);
392                 PFS_RETURN (0);
393         } else if (vp->v_type == VDIR && pd->pn_type == pfstype_procdir) {
394                 len = snprintf(pidbuf, sizeof(pidbuf), "%d", pid);
395                 i -= len;
396                 if (i < 0) {
397                         error = ENOMEM;
398                         goto failed;
399                 }
400                 bcopy(pidbuf, buf + i, len);
401         } else {
402                 len = strlen(pd->pn_name);
403                 i -= len;
404                 if (i < 0) {
405                         error = ENOMEM;
406                         goto failed;
407                 }
408                 bcopy(pd->pn_name, buf + i, len);
409         }
410
411         pn = pd->pn_parent;
412         pfs_unlock(pd);
413
414         mp = vp->v_mount;
415         error = vfs_busy(mp, 0);
416         if (error)
417                 return (error);
418
419         /*
420          * vp is held by caller.
421          */
422         locked = VOP_ISLOCKED(vp);
423         VOP_UNLOCK(vp);
424
425         error = pfs_vncache_alloc(mp, dvp, pn, pid);
426         if (error) {
427                 vn_lock(vp, locked | LK_RETRY);
428                 vfs_unbusy(mp);
429                 PFS_RETURN(error);
430         }
431
432         *buflen = i;
433         VOP_UNLOCK(*dvp);
434         vn_lock(vp, locked | LK_RETRY);
435         vfs_unbusy(mp);
436
437         PFS_RETURN (0);
438 failed:
439         pfs_unlock(pd);
440         PFS_RETURN(error);
441 }
442
443 /*
444  * Look up a file or directory
445  */
446 static int
447 pfs_lookup(struct vop_cachedlookup_args *va)
448 {
449         struct vnode *vn = va->a_dvp;
450         struct vnode **vpp = va->a_vpp;
451         struct componentname *cnp = va->a_cnp;
452         struct pfs_vdata *pvd = vn->v_data;
453         struct pfs_node *pd = pvd->pvd_pn;
454         struct pfs_node *pn, *pdn = NULL;
455         struct mount *mp;
456         pid_t pid = pvd->pvd_pid;
457         char *pname;
458         int error, i, namelen, visible;
459
460         PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
461         pfs_assert_not_owned(pd);
462
463         if (vn->v_type != VDIR)
464                 PFS_RETURN (ENOTDIR);
465         KASSERT_PN_IS_DIR(pd);
466
467         /*
468          * Don't support DELETE or RENAME.  CREATE is supported so
469          * that O_CREAT will work, but the lookup will still fail if
470          * the file does not exist.
471          */
472         if ((cnp->cn_flags & ISLASTCN) &&
473             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
474                 PFS_RETURN (EOPNOTSUPP);
475
476         /* shortcut: check if the name is too long */
477         if (cnp->cn_namelen >= PFS_NAMELEN)
478                 PFS_RETURN (ENOENT);
479
480         /* check that parent directory is visible... */
481         if (!pfs_visible(curthread, pd, pvd->pvd_pid, NULL))
482                 PFS_RETURN (ENOENT);
483
484         /* self */
485         namelen = cnp->cn_namelen;
486         pname = cnp->cn_nameptr;
487         if (namelen == 1 && pname[0] == '.') {
488                 pn = pd;
489                 *vpp = vn;
490                 VREF(vn);
491                 PFS_RETURN (0);
492         }
493
494         mp = vn->v_mount;
495
496         /* parent */
497         if (cnp->cn_flags & ISDOTDOT) {
498                 if (pd->pn_type == pfstype_root)
499                         PFS_RETURN (EIO);
500                 error = vfs_busy(mp, MBF_NOWAIT);
501                 if (error != 0) {
502                         vfs_ref(mp);
503                         VOP_UNLOCK(vn);
504                         error = vfs_busy(mp, 0);
505                         vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
506                         vfs_rel(mp);
507                         if (error != 0)
508                                 PFS_RETURN(ENOENT);
509                         if (VN_IS_DOOMED(vn)) {
510                                 vfs_unbusy(mp);
511                                 PFS_RETURN(ENOENT);
512                         }
513                 }
514                 VOP_UNLOCK(vn);
515                 KASSERT(pd->pn_parent != NULL,
516                     ("%s(): non-root directory has no parent", __func__));
517                 /*
518                  * This one is tricky.  Descendents of procdir nodes
519                  * inherit their parent's process affinity, but
520                  * there's no easy reverse mapping.  For simplicity,
521                  * we assume that if this node is a procdir, its
522                  * parent isn't (which is correct as long as
523                  * descendents of procdir nodes are never procdir
524                  * nodes themselves)
525                  */
526                 if (pd->pn_type == pfstype_procdir)
527                         pid = NO_PID;
528                 pfs_lock(pd);
529                 pn = pd->pn_parent;
530                 pfs_unlock(pd);
531                 goto got_pnode;
532         }
533
534         pfs_lock(pd);
535
536         /* named node */
537         for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
538                 if (pn->pn_type == pfstype_procdir)
539                         pdn = pn;
540                 else if (strncmp(pname, pn->pn_name, namelen) == 0 &&
541                     pn->pn_name[namelen] == '\0') {
542                         pfs_unlock(pd);
543                         goto got_pnode;
544                 }
545
546         /* process dependent node */
547         if ((pn = pdn) != NULL) {
548                 pid = 0;
549                 for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
550                         if ((pid = pid * 10 + pname[i] - '0') > PID_MAX)
551                                 break;
552                 if (i == cnp->cn_namelen) {
553                         pfs_unlock(pd);
554                         goto got_pnode;
555                 }
556         }
557
558         pfs_unlock(pd);
559
560         PFS_RETURN (ENOENT);
561
562  got_pnode:
563         pfs_assert_not_owned(pd);
564         pfs_assert_not_owned(pn);
565         visible = pfs_visible(curthread, pn, pid, NULL);
566         if (!visible) {
567                 error = ENOENT;
568                 goto failed;
569         }
570
571         error = pfs_vncache_alloc(mp, vpp, pn, pid);
572         if (error)
573                 goto failed;
574
575         if (cnp->cn_flags & ISDOTDOT) {
576                 vfs_unbusy(mp);
577                 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
578                 if (VN_IS_DOOMED(vn)) {
579                         vput(*vpp);
580                         *vpp = NULL;
581                         PFS_RETURN(ENOENT);
582                 }
583         }
584         if (cnp->cn_flags & MAKEENTRY && !VN_IS_DOOMED(vn))
585                 cache_enter(vn, *vpp, cnp);
586         PFS_RETURN (0);
587  failed:
588         if (cnp->cn_flags & ISDOTDOT) {
589                 vfs_unbusy(mp);
590                 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
591                 *vpp = NULL;
592         }
593         PFS_RETURN(error);
594 }
595
596 /*
597  * Open a file or directory.
598  */
599 static int
600 pfs_open(struct vop_open_args *va)
601 {
602         struct vnode *vn = va->a_vp;
603         struct pfs_vdata *pvd = vn->v_data;
604         struct pfs_node *pn = pvd->pvd_pn;
605         int mode = va->a_mode;
606
607         PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
608         pfs_assert_not_owned(pn);
609
610         /* check if the requested mode is permitted */
611         if (((mode & FREAD) && !(mode & PFS_RD)) ||
612             ((mode & FWRITE) && !(mode & PFS_WR)))
613                 PFS_RETURN (EPERM);
614
615         /* we don't support locking */
616         if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
617                 PFS_RETURN (EOPNOTSUPP);
618
619         PFS_RETURN (0);
620 }
621
622 struct sbuf_seek_helper {
623         off_t           skip_bytes;
624         struct uio      *uio;
625 };
626
627 static int
628 pfs_sbuf_uio_drain(void *arg, const char *data, int len)
629 {
630         struct sbuf_seek_helper *ssh;
631         struct uio *uio;
632         int error, skipped;
633
634         ssh = arg;
635         uio = ssh->uio;
636         skipped = 0;
637
638         /* Need to discard first uio_offset bytes. */
639         if (ssh->skip_bytes > 0) {
640                 if (ssh->skip_bytes >= len) {
641                         ssh->skip_bytes -= len;
642                         return (len);
643                 }
644
645                 data += ssh->skip_bytes;
646                 len -= ssh->skip_bytes;
647                 skipped = ssh->skip_bytes;
648                 ssh->skip_bytes = 0;
649         }
650
651         error = uiomove(__DECONST(void *, data), len, uio);
652         if (error != 0)
653                 return (-error);
654
655         /*
656          * The fill function has more to emit, but the reader is finished.
657          * This is similar to the truncated read case for non-draining PFS
658          * sbufs, and should be handled appropriately in fill-routines.
659          */
660         if (uio->uio_resid == 0)
661                 return (-ENOBUFS);
662
663         return (skipped + len);
664 }
665
666 /*
667  * Read from a file
668  */
669 static int
670 pfs_read(struct vop_read_args *va)
671 {
672         struct vnode *vn = va->a_vp;
673         struct pfs_vdata *pvd = vn->v_data;
674         struct pfs_node *pn = pvd->pvd_pn;
675         struct uio *uio = va->a_uio;
676         struct proc *proc;
677         struct sbuf *sb = NULL;
678         int error, locked;
679         off_t buflen, buflim;
680         struct sbuf_seek_helper ssh;
681
682         PFS_TRACE(("%s", pn->pn_name));
683         pfs_assert_not_owned(pn);
684
685         if (vn->v_type != VREG)
686                 PFS_RETURN (EINVAL);
687         KASSERT_PN_IS_FILE(pn);
688
689         if (!(pn->pn_flags & PFS_RD))
690                 PFS_RETURN (EBADF);
691
692         if (pn->pn_fill == NULL)
693                 PFS_RETURN (EIO);
694
695         /*
696          * This is necessary because either process' privileges may
697          * have changed since the open() call.
698          */
699         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
700                 PFS_RETURN (EIO);
701         if (proc != NULL) {
702                 _PHOLD(proc);
703                 PROC_UNLOCK(proc);
704         }
705
706         vhold(vn);
707         locked = VOP_ISLOCKED(vn);
708         VOP_UNLOCK(vn);
709
710         if (pn->pn_flags & PFS_RAWRD) {
711                 PFS_TRACE(("%zd resid", uio->uio_resid));
712                 error = pn_fill(curthread, proc, pn, NULL, uio);
713                 PFS_TRACE(("%zd resid", uio->uio_resid));
714                 goto ret;
715         }
716
717         if (uio->uio_resid < 0 || uio->uio_offset < 0 ||
718             uio->uio_resid > OFF_MAX - uio->uio_offset) {
719                 error = EINVAL;
720                 goto ret;
721         }
722         buflen = uio->uio_offset + uio->uio_resid + 1;
723         if (pn->pn_flags & PFS_AUTODRAIN)
724                 /*
725                  * We can use a smaller buffer if we can stream output to the
726                  * consumer.
727                  */
728                 buflim = PAGE_SIZE;
729         else
730                 buflim = PFS_MAXBUFSIZ;
731         if (buflen > buflim)
732                 buflen = buflim;
733
734         sb = sbuf_new(sb, NULL, buflen, 0);
735         if (sb == NULL) {
736                 error = EIO;
737                 goto ret;
738         }
739
740         if (pn->pn_flags & PFS_AUTODRAIN) {
741                 ssh.skip_bytes = uio->uio_offset;
742                 ssh.uio = uio;
743                 sbuf_set_drain(sb, pfs_sbuf_uio_drain, &ssh);
744         }
745
746         error = pn_fill(curthread, proc, pn, sb, uio);
747
748         if (error) {
749                 sbuf_delete(sb);
750                 goto ret;
751         }
752
753         /*
754          * XXX: If the buffer overflowed, sbuf_len() will not return
755          * the data length. Then just use the full length because an
756          * overflowed sbuf must be full.
757          */
758         error = sbuf_finish(sb);
759         if ((pn->pn_flags & PFS_AUTODRAIN)) {
760                 /*
761                  * ENOBUFS just indicates early termination of the fill
762                  * function as the caller's buffer was already filled.  Squash
763                  * to zero.
764                  */
765                 if (uio->uio_resid == 0 && error == ENOBUFS)
766                         error = 0;
767         } else {
768                 if (error == 0)
769                         buflen = sbuf_len(sb);
770                 else
771                         /* The trailing byte is not valid. */
772                         buflen--;
773                 error = uiomove_frombuf(sbuf_data(sb), buflen, uio);
774         }
775         sbuf_delete(sb);
776 ret:
777         vn_lock(vn, locked | LK_RETRY);
778         vdrop(vn);
779         if (proc != NULL)
780                 PRELE(proc);
781         PFS_RETURN (error);
782 }
783
784 /*
785  * Iterate through directory entries
786  */
787 static int
788 pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd,
789             struct pfs_node **pn, struct proc **p)
790 {
791         int visible;
792
793         sx_assert(&allproc_lock, SX_SLOCKED);
794         pfs_assert_owned(pd);
795  again:
796         if (*pn == NULL) {
797                 /* first node */
798                 *pn = pd->pn_nodes;
799         } else if ((*pn)->pn_type != pfstype_procdir) {
800                 /* next node */
801                 *pn = (*pn)->pn_next;
802         }
803         if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
804                 /* next process */
805                 if (*p == NULL)
806                         *p = LIST_FIRST(&allproc);
807                 else
808                         *p = LIST_NEXT(*p, p_list);
809                 /* out of processes: next node */
810                 if (*p == NULL)
811                         *pn = (*pn)->pn_next;
812                 else
813                         PROC_LOCK(*p);
814         }
815
816         if ((*pn) == NULL)
817                 return (-1);
818
819         if (*p != NULL) {
820                 visible = pfs_visible_proc(td, *pn, *p);
821                 PROC_UNLOCK(*p);
822         } else if (proc != NULL) {
823                 visible = pfs_visible_proc(td, *pn, proc);
824         } else {
825                 visible = pn_vis(td, NULL, *pn);
826         }
827         if (!visible)
828                 goto again;
829
830         return (0);
831 }
832
833 /* Directory entry list */
834 struct pfsentry {
835         STAILQ_ENTRY(pfsentry)  link;
836         struct dirent           entry;
837 };
838 STAILQ_HEAD(pfsdirentlist, pfsentry);
839
840 /*
841  * Return directory entries.
842  */
843 static int
844 pfs_readdir(struct vop_readdir_args *va)
845 {
846         struct vnode *vn = va->a_vp;
847         struct pfs_vdata *pvd = vn->v_data;
848         struct pfs_node *pd = pvd->pvd_pn;
849         pid_t pid = pvd->pvd_pid;
850         struct proc *p, *proc;
851         struct pfs_node *pn;
852         struct uio *uio;
853         struct pfsentry *pfsent, *pfsent2;
854         struct pfsdirentlist lst;
855         off_t offset;
856         int error, i, resid;
857
858         STAILQ_INIT(&lst);
859         error = 0;
860         KASSERT(pd->pn_info == vn->v_mount->mnt_data,
861             ("%s(): pn_info does not match mountpoint", __func__));
862         PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid));
863         pfs_assert_not_owned(pd);
864
865         if (vn->v_type != VDIR)
866                 PFS_RETURN (ENOTDIR);
867         KASSERT_PN_IS_DIR(pd);
868         uio = va->a_uio;
869
870         /* only allow reading entire entries */
871         offset = uio->uio_offset;
872         resid = uio->uio_resid;
873         if (offset < 0 || offset % PFS_DELEN != 0 ||
874             (resid && resid < PFS_DELEN))
875                 PFS_RETURN (EINVAL);
876         if (resid == 0)
877                 PFS_RETURN (0);
878
879         proc = NULL;
880         if (pid != NO_PID && !pfs_lookup_proc(pid, &proc))
881                 PFS_RETURN (ENOENT);
882
883         sx_slock(&allproc_lock);
884         pfs_lock(pd);
885
886         KASSERT(pid == NO_PID || proc != NULL,
887             ("%s(): no process for pid %lu", __func__, (unsigned long)pid));
888
889         if (pid != NO_PID) {
890                 PROC_LOCK(proc);
891
892                 /* check if the directory is visible to the caller */
893                 if (!pfs_visible_proc(curthread, pd, proc)) {
894                         _PRELE(proc);
895                         PROC_UNLOCK(proc);
896                         pfs_unlock(pd);
897                         sx_sunlock(&allproc_lock);
898                         PFS_RETURN (ENOENT);
899                 }
900         }
901
902         /* skip unwanted entries */
903         for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) {
904                 if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) {
905                         /* nothing left... */
906                         if (proc != NULL) {
907                                 _PRELE(proc);
908                                 PROC_UNLOCK(proc);
909                         }
910                         pfs_unlock(pd);
911                         sx_sunlock(&allproc_lock);
912                         PFS_RETURN (0);
913                 }
914         }
915
916         /* fill in entries */
917         while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 &&
918             resid >= PFS_DELEN) {
919                 if ((pfsent = malloc(sizeof(struct pfsentry), M_IOV,
920                     M_NOWAIT | M_ZERO)) == NULL) {
921                         error = ENOMEM;
922                         break;
923                 }
924                 pfsent->entry.d_reclen = PFS_DELEN;
925                 pfsent->entry.d_fileno = pn_fileno(pn, pid);
926                 /* PFS_DELEN was picked to fit PFS_NAMLEN */
927                 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
928                         pfsent->entry.d_name[i] = pn->pn_name[i];
929                 pfsent->entry.d_namlen = i;
930                 /* NOTE: d_off is the offset of the *next* entry. */
931                 pfsent->entry.d_off = offset + PFS_DELEN;
932                 switch (pn->pn_type) {
933                 case pfstype_procdir:
934                         KASSERT(p != NULL,
935                             ("reached procdir node with p == NULL"));
936                         pfsent->entry.d_namlen = snprintf(pfsent->entry.d_name,
937                             PFS_NAMELEN, "%d", p->p_pid);
938                         /* fall through */
939                 case pfstype_root:
940                 case pfstype_dir:
941                 case pfstype_this:
942                 case pfstype_parent:
943                         pfsent->entry.d_type = DT_DIR;
944                         break;
945                 case pfstype_file:
946                         pfsent->entry.d_type = DT_REG;
947                         break;
948                 case pfstype_symlink:
949                         pfsent->entry.d_type = DT_LNK;
950                         break;
951                 default:
952                         panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
953                 }
954                 PFS_TRACE(("%s", pfsent->entry.d_name));
955                 dirent_terminate(&pfsent->entry);
956                 STAILQ_INSERT_TAIL(&lst, pfsent, link);
957                 offset += PFS_DELEN;
958                 resid -= PFS_DELEN;
959         }
960         if (proc != NULL) {
961                 _PRELE(proc);
962                 PROC_UNLOCK(proc);
963         }
964         pfs_unlock(pd);
965         sx_sunlock(&allproc_lock);
966         i = 0;
967         STAILQ_FOREACH_SAFE(pfsent, &lst, link, pfsent2) {
968                 if (error == 0)
969                         error = uiomove(&pfsent->entry, PFS_DELEN, uio);
970                 free(pfsent, M_IOV);
971                 i++;
972         }
973         PFS_TRACE(("%ju bytes", (uintmax_t)(i * PFS_DELEN)));
974         PFS_RETURN (error);
975 }
976
977 /*
978  * Read a symbolic link
979  */
980 static int
981 pfs_readlink(struct vop_readlink_args *va)
982 {
983         struct vnode *vn = va->a_vp;
984         struct pfs_vdata *pvd = vn->v_data;
985         struct pfs_node *pn = pvd->pvd_pn;
986         struct uio *uio = va->a_uio;
987         struct proc *proc = NULL;
988         char buf[PATH_MAX];
989         struct sbuf sb;
990         int error, locked;
991
992         PFS_TRACE(("%s", pn->pn_name));
993         pfs_assert_not_owned(pn);
994
995         if (vn->v_type != VLNK)
996                 PFS_RETURN (EINVAL);
997         KASSERT_PN_IS_LINK(pn);
998
999         if (pn->pn_fill == NULL)
1000                 PFS_RETURN (EIO);
1001
1002         if (pvd->pvd_pid != NO_PID) {
1003                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
1004                         PFS_RETURN (EIO);
1005                 if (proc->p_flag & P_WEXIT) {
1006                         PROC_UNLOCK(proc);
1007                         PFS_RETURN (EIO);
1008                 }
1009                 _PHOLD(proc);
1010                 PROC_UNLOCK(proc);
1011         }
1012         vhold(vn);
1013         locked = VOP_ISLOCKED(vn);
1014         VOP_UNLOCK(vn);
1015
1016         /* sbuf_new() can't fail with a static buffer */
1017         sbuf_new(&sb, buf, sizeof buf, 0);
1018
1019         error = pn_fill(curthread, proc, pn, &sb, NULL);
1020
1021         if (proc != NULL)
1022                 PRELE(proc);
1023         vn_lock(vn, locked | LK_RETRY);
1024         vdrop(vn);
1025
1026         if (error) {
1027                 sbuf_delete(&sb);
1028                 PFS_RETURN (error);
1029         }
1030
1031         if (sbuf_finish(&sb) != 0) {
1032                 sbuf_delete(&sb);
1033                 PFS_RETURN (ENAMETOOLONG);
1034         }
1035
1036         error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
1037         sbuf_delete(&sb);
1038         PFS_RETURN (error);
1039 }
1040
1041 /*
1042  * Reclaim a vnode
1043  */
1044 static int
1045 pfs_reclaim(struct vop_reclaim_args *va)
1046 {
1047         struct vnode *vn = va->a_vp;
1048         struct pfs_vdata *pvd = vn->v_data;
1049         struct pfs_node *pn = pvd->pvd_pn;
1050
1051         PFS_TRACE(("%s", pn->pn_name));
1052         pfs_assert_not_owned(pn);
1053
1054         return (pfs_vncache_free(va->a_vp));
1055 }
1056
1057 /*
1058  * Set attributes
1059  */
1060 static int
1061 pfs_setattr(struct vop_setattr_args *va)
1062 {
1063         struct vnode *vn = va->a_vp;
1064         struct pfs_vdata *pvd = vn->v_data;
1065         struct pfs_node *pn = pvd->pvd_pn;
1066
1067         PFS_TRACE(("%s", pn->pn_name));
1068         pfs_assert_not_owned(pn);
1069
1070         /* Silently ignore unchangeable attributes. */
1071         PFS_RETURN (0);
1072 }
1073
1074 /*
1075  * Write to a file
1076  */
1077 static int
1078 pfs_write(struct vop_write_args *va)
1079 {
1080         struct vnode *vn = va->a_vp;
1081         struct pfs_vdata *pvd = vn->v_data;
1082         struct pfs_node *pn = pvd->pvd_pn;
1083         struct uio *uio = va->a_uio;
1084         struct proc *proc;
1085         struct sbuf sb;
1086         int error;
1087
1088         PFS_TRACE(("%s", pn->pn_name));
1089         pfs_assert_not_owned(pn);
1090
1091         if (vn->v_type != VREG)
1092                 PFS_RETURN (EINVAL);
1093         KASSERT_PN_IS_FILE(pn);
1094
1095         if (!(pn->pn_flags & PFS_WR))
1096                 PFS_RETURN (EBADF);
1097
1098         if (pn->pn_fill == NULL)
1099                 PFS_RETURN (EIO);
1100
1101         if (uio->uio_resid > PFS_MAXBUFSIZ)
1102                 PFS_RETURN (EIO);
1103
1104         /*
1105          * This is necessary because either process' privileges may
1106          * have changed since the open() call.
1107          */
1108         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
1109                 PFS_RETURN (EIO);
1110         if (proc != NULL) {
1111                 _PHOLD(proc);
1112                 PROC_UNLOCK(proc);
1113         }
1114
1115         if (pn->pn_flags & PFS_RAWWR) {
1116                 error = pn_fill(curthread, proc, pn, NULL, uio);
1117                 if (proc != NULL)
1118                         PRELE(proc);
1119                 PFS_RETURN (error);
1120         }
1121
1122         sbuf_uionew(&sb, uio, &error);
1123         if (error) {
1124                 if (proc != NULL)
1125                         PRELE(proc);
1126                 PFS_RETURN (error);
1127         }
1128
1129         error = pn_fill(curthread, proc, pn, &sb, uio);
1130
1131         sbuf_delete(&sb);
1132         if (proc != NULL)
1133                 PRELE(proc);
1134         PFS_RETURN (error);
1135 }
1136
1137 /*
1138  * Vnode operations
1139  */
1140 struct vop_vector pfs_vnodeops = {
1141         .vop_default =          &default_vnodeops,
1142
1143         .vop_access =           pfs_access,
1144         .vop_cachedlookup =     pfs_lookup,
1145         .vop_close =            pfs_close,
1146         .vop_create =           VOP_EOPNOTSUPP,
1147         .vop_getattr =          pfs_getattr,
1148         .vop_getextattr =       pfs_getextattr,
1149         .vop_ioctl =            pfs_ioctl,
1150         .vop_link =             VOP_EOPNOTSUPP,
1151         .vop_lookup =           vfs_cache_lookup,
1152         .vop_mkdir =            VOP_EOPNOTSUPP,
1153         .vop_mknod =            VOP_EOPNOTSUPP,
1154         .vop_open =             pfs_open,
1155         .vop_read =             pfs_read,
1156         .vop_readdir =          pfs_readdir,
1157         .vop_readlink =         pfs_readlink,
1158         .vop_reclaim =          pfs_reclaim,
1159         .vop_remove =           VOP_EOPNOTSUPP,
1160         .vop_rename =           VOP_EOPNOTSUPP,
1161         .vop_rmdir =            VOP_EOPNOTSUPP,
1162         .vop_setattr =          pfs_setattr,
1163         .vop_symlink =          VOP_EOPNOTSUPP,
1164         .vop_vptocnp =          pfs_vptocnp,
1165         .vop_write =            pfs_write,
1166         .vop_add_writecount =   vop_stdadd_writecount_nomsync,
1167         /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */
1168 };
1169 VFS_VOP_VECTOR_REGISTER(pfs_vnodeops);