19733a808SDag-Erling Smørgrav /*-
2d63027b6SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
3d63027b6SPedro F. Giffuni *
4*e738085bSDag-Erling Smørgrav * Copyright (c) 2001 Dag-Erling Smørgrav
59733a808SDag-Erling Smørgrav * All rights reserved.
69733a808SDag-Erling Smørgrav *
79733a808SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without
89733a808SDag-Erling Smørgrav * modification, are permitted provided that the following conditions
99733a808SDag-Erling Smørgrav * are met:
109733a808SDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright
119733a808SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer
129733a808SDag-Erling Smørgrav * in this position and unchanged.
139733a808SDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright
149733a808SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the
159733a808SDag-Erling Smørgrav * documentation and/or other materials provided with the distribution.
169733a808SDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote products
179733a808SDag-Erling Smørgrav * derived from this software without specific prior written permission.
189733a808SDag-Erling Smørgrav *
199733a808SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
209733a808SDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
219733a808SDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
229733a808SDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
239733a808SDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
249733a808SDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
259733a808SDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
269733a808SDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
279733a808SDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
289733a808SDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
299733a808SDag-Erling Smørgrav */
309733a808SDag-Erling Smørgrav
31de52d21aSDag-Erling Smørgrav #include <sys/cdefs.h>
32de52d21aSDag-Erling Smørgrav #include "opt_pseudofs.h"
33de52d21aSDag-Erling Smørgrav
349733a808SDag-Erling Smørgrav #include <sys/param.h>
359733a808SDag-Erling Smørgrav #include <sys/kernel.h>
369733a808SDag-Erling Smørgrav #include <sys/systm.h>
379733a808SDag-Erling Smørgrav #include <sys/ctype.h>
389733a808SDag-Erling Smørgrav #include <sys/dirent.h>
397d8f809fSDag-Erling Smørgrav #include <sys/fcntl.h>
408b7358caSJacques Vidrine #include <sys/limits.h>
4121ceb6efSDag-Erling Smørgrav #include <sys/lock.h>
42bc593ccdSDag-Erling Smørgrav #include <sys/malloc.h>
439733a808SDag-Erling Smørgrav #include <sys/mount.h>
441e4ebf4eSDag-Erling Smørgrav #include <sys/mutex.h>
459733a808SDag-Erling Smørgrav #include <sys/namei.h>
469733a808SDag-Erling Smørgrav #include <sys/proc.h>
479733a808SDag-Erling Smørgrav #include <sys/sbuf.h>
489733a808SDag-Erling Smørgrav #include <sys/sx.h>
499733a808SDag-Erling Smørgrav #include <sys/sysctl.h>
509733a808SDag-Erling Smørgrav #include <sys/vnode.h>
519733a808SDag-Erling Smørgrav
529733a808SDag-Erling Smørgrav #include <fs/pseudofs/pseudofs.h>
539733a808SDag-Erling Smørgrav #include <fs/pseudofs/pseudofs_internal.h>
549733a808SDag-Erling Smørgrav
5559fc1b06SDag-Erling Smørgrav #define KASSERT_PN_IS_DIR(pn) \
5659fc1b06SDag-Erling Smørgrav KASSERT((pn)->pn_type == pfstype_root || \
5759fc1b06SDag-Erling Smørgrav (pn)->pn_type == pfstype_dir || \
5859fc1b06SDag-Erling Smørgrav (pn)->pn_type == pfstype_procdir, \
5959fc1b06SDag-Erling Smørgrav ("%s(): VDIR vnode refers to non-directory pfs_node", __func__))
6059fc1b06SDag-Erling Smørgrav
6159fc1b06SDag-Erling Smørgrav #define KASSERT_PN_IS_FILE(pn) \
6259fc1b06SDag-Erling Smørgrav KASSERT((pn)->pn_type == pfstype_file, \
6359fc1b06SDag-Erling Smørgrav ("%s(): VREG vnode refers to non-file pfs_node", __func__))
6459fc1b06SDag-Erling Smørgrav
6559fc1b06SDag-Erling Smørgrav #define KASSERT_PN_IS_LINK(pn) \
6659fc1b06SDag-Erling Smørgrav KASSERT((pn)->pn_type == pfstype_symlink, \
6759fc1b06SDag-Erling Smørgrav ("%s(): VLNK vnode refers to non-link pfs_node", __func__))
6859fc1b06SDag-Erling Smørgrav
69ce764cbdSEdward Tomasz Napierala #define PFS_MAXBUFSIZ 1024 * 1024
70ce764cbdSEdward Tomasz Napierala
719733a808SDag-Erling Smørgrav /*
72388596dfSDag-Erling Smørgrav * Returns the fileno, adjusted for target pid
73f61bc4eaSDag-Erling Smørgrav */
74f61bc4eaSDag-Erling Smørgrav static uint32_t
pn_fileno(struct pfs_node * pn,pid_t pid)75388596dfSDag-Erling Smørgrav pn_fileno(struct pfs_node *pn, pid_t pid)
76f61bc4eaSDag-Erling Smørgrav {
77388596dfSDag-Erling Smørgrav
78388596dfSDag-Erling Smørgrav KASSERT(pn->pn_fileno > 0,
79388596dfSDag-Erling Smørgrav ("%s(): no fileno allocated", __func__));
80f61bc4eaSDag-Erling Smørgrav if (pid != NO_PID)
81f61bc4eaSDag-Erling Smørgrav return (pn->pn_fileno * NO_PID + pid);
82f61bc4eaSDag-Erling Smørgrav return (pn->pn_fileno);
83f61bc4eaSDag-Erling Smørgrav }
84f61bc4eaSDag-Erling Smørgrav
85f61bc4eaSDag-Erling Smørgrav /*
86388596dfSDag-Erling Smørgrav * Returns non-zero if given file is visible to given thread.
87198bc14bSDag-Erling Smørgrav */
88198bc14bSDag-Erling Smørgrav static int
pfs_visible_proc(struct thread * td,struct pfs_node * pn,struct proc * proc)89388596dfSDag-Erling Smørgrav pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc)
90388596dfSDag-Erling Smørgrav {
91388596dfSDag-Erling Smørgrav
92388596dfSDag-Erling Smørgrav if (proc == NULL)
93388596dfSDag-Erling Smørgrav return (0);
94388596dfSDag-Erling Smørgrav
95388596dfSDag-Erling Smørgrav PROC_LOCK_ASSERT(proc, MA_OWNED);
96388596dfSDag-Erling Smørgrav
97a32ed5ecSDmitry Chagin if ((proc->p_flag & P_WEXIT) != 0)
98388596dfSDag-Erling Smørgrav return (0);
99a32ed5ecSDmitry Chagin if (p_cansee(td, proc) != 0)
100a32ed5ecSDmitry Chagin return (0);
101a32ed5ecSDmitry Chagin return (pn_vis(td, proc, pn));
102388596dfSDag-Erling Smørgrav }
103388596dfSDag-Erling Smørgrav
104388596dfSDag-Erling Smørgrav static int
pfs_visible(struct thread * td,struct pfs_node * pn,pid_t pid,struct proc ** p)105ffc161dfSKonstantin Belousov pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid,
10653011553SMateusz Guzik struct proc **p)
107198bc14bSDag-Erling Smørgrav {
108198bc14bSDag-Erling Smørgrav struct proc *proc;
109198bc14bSDag-Erling Smørgrav
110198bc14bSDag-Erling Smørgrav PFS_TRACE(("%s (pid: %d, req: %d)",
111198bc14bSDag-Erling Smørgrav pn->pn_name, pid, td->td_proc->p_pid));
112b84ce334SDag-Erling Smørgrav
113f8e3eeb5SJohn Baldwin if (p)
114f8e3eeb5SJohn Baldwin *p = NULL;
115388596dfSDag-Erling Smørgrav if (pid == NO_PID)
116405c0c04SDmitry Chagin PFS_RETURN (pn_vis(td, NULL, pn));
11753011553SMateusz Guzik proc = pfind(pid);
118ffc161dfSKonstantin Belousov if (proc == NULL)
119388596dfSDag-Erling Smørgrav PFS_RETURN (0);
120388596dfSDag-Erling Smørgrav if (pfs_visible_proc(td, pn, proc)) {
121388596dfSDag-Erling Smørgrav if (p)
122388596dfSDag-Erling Smørgrav *p = proc;
123388596dfSDag-Erling Smørgrav else
124388596dfSDag-Erling Smørgrav PROC_UNLOCK(proc);
125388596dfSDag-Erling Smørgrav PFS_RETURN (1);
126388596dfSDag-Erling Smørgrav }
127388596dfSDag-Erling Smørgrav PROC_UNLOCK(proc);
128388596dfSDag-Erling Smørgrav PFS_RETURN (0);
129198bc14bSDag-Erling Smørgrav }
130198bc14bSDag-Erling Smørgrav
131f5791174SMateusz Guzik static int
pfs_lookup_proc(pid_t pid,struct proc ** p)132f5791174SMateusz Guzik pfs_lookup_proc(pid_t pid, struct proc **p)
133f5791174SMateusz Guzik {
134f5791174SMateusz Guzik struct proc *proc;
135f5791174SMateusz Guzik
136f5791174SMateusz Guzik proc = pfind(pid);
137f5791174SMateusz Guzik if (proc == NULL)
138f5791174SMateusz Guzik return (0);
139f5791174SMateusz Guzik if ((proc->p_flag & P_WEXIT) != 0) {
140f5791174SMateusz Guzik PROC_UNLOCK(proc);
141f5791174SMateusz Guzik return (0);
142f5791174SMateusz Guzik }
143f5791174SMateusz Guzik _PHOLD(proc);
144f5791174SMateusz Guzik PROC_UNLOCK(proc);
145f5791174SMateusz Guzik *p = proc;
146f5791174SMateusz Guzik return (1);
147f5791174SMateusz Guzik }
148f5791174SMateusz Guzik
149198bc14bSDag-Erling Smørgrav /*
1509733a808SDag-Erling Smørgrav * Verify permissions
1519733a808SDag-Erling Smørgrav */
1529733a808SDag-Erling Smørgrav static int
pfs_access(struct vop_access_args * va)1539733a808SDag-Erling Smørgrav pfs_access(struct vop_access_args *va)
1549733a808SDag-Erling Smørgrav {
1559733a808SDag-Erling Smørgrav struct vnode *vn = va->a_vp;
156388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
1579733a808SDag-Erling Smørgrav struct vattr vattr;
1589733a808SDag-Erling Smørgrav int error;
1599733a808SDag-Erling Smørgrav
160388596dfSDag-Erling Smørgrav PFS_TRACE(("%s", pvd->pvd_pn->pn_name));
1618edf8ae1SDag-Erling Smørgrav (void)pvd;
16280a3cef8SDag-Erling Smørgrav
1630359a12eSAttilio Rao error = VOP_GETATTR(vn, &vattr, va->a_cred);
1649733a808SDag-Erling Smørgrav if (error)
165198bc14bSDag-Erling Smørgrav PFS_RETURN (error);
166d292b194SMateusz Guzik error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, vattr.va_gid,
167d292b194SMateusz Guzik va->a_accmode, va->a_cred);
168198bc14bSDag-Erling Smørgrav PFS_RETURN (error);
1699733a808SDag-Erling Smørgrav }
1709733a808SDag-Erling Smørgrav
1719733a808SDag-Erling Smørgrav /*
1729733a808SDag-Erling Smørgrav * Close a file or directory
1739733a808SDag-Erling Smørgrav */
1749733a808SDag-Erling Smørgrav static int
pfs_close(struct vop_close_args * va)1759733a808SDag-Erling Smørgrav pfs_close(struct vop_close_args *va)
1769733a808SDag-Erling Smørgrav {
17798c7e22cSDag-Erling Smørgrav struct vnode *vn = va->a_vp;
178388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
17998c7e22cSDag-Erling Smørgrav struct pfs_node *pn = pvd->pvd_pn;
18098c7e22cSDag-Erling Smørgrav struct proc *proc;
18198c7e22cSDag-Erling Smørgrav int error;
18298c7e22cSDag-Erling Smørgrav
183388596dfSDag-Erling Smørgrav PFS_TRACE(("%s", pn->pn_name));
184388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
18598c7e22cSDag-Erling Smørgrav
18698c7e22cSDag-Erling Smørgrav /*
18798c7e22cSDag-Erling Smørgrav * Do nothing unless this is the last close and the node has a
18898c7e22cSDag-Erling Smørgrav * last-close handler.
18998c7e22cSDag-Erling Smørgrav */
1904d93c0beSJeff Roberson if (vrefcnt(vn) > 1 || pn->pn_close == NULL)
1917d8f809fSDag-Erling Smørgrav PFS_RETURN (0);
19298c7e22cSDag-Erling Smørgrav
193388596dfSDag-Erling Smørgrav if (pvd->pvd_pid != NO_PID) {
19498c7e22cSDag-Erling Smørgrav proc = pfind(pvd->pvd_pid);
195388596dfSDag-Erling Smørgrav } else {
19698c7e22cSDag-Erling Smørgrav proc = NULL;
197388596dfSDag-Erling Smørgrav }
19898c7e22cSDag-Erling Smørgrav
199388596dfSDag-Erling Smørgrav error = pn_close(va->a_td, proc, pn);
20098c7e22cSDag-Erling Smørgrav
20198c7e22cSDag-Erling Smørgrav if (proc != NULL)
20298c7e22cSDag-Erling Smørgrav PROC_UNLOCK(proc);
20398c7e22cSDag-Erling Smørgrav
20498c7e22cSDag-Erling Smørgrav PFS_RETURN (error);
2059733a808SDag-Erling Smørgrav }
2069733a808SDag-Erling Smørgrav
2079733a808SDag-Erling Smørgrav /*
2089733a808SDag-Erling Smørgrav * Get file attributes
2099733a808SDag-Erling Smørgrav */
2109733a808SDag-Erling Smørgrav static int
pfs_getattr(struct vop_getattr_args * va)2119733a808SDag-Erling Smørgrav pfs_getattr(struct vop_getattr_args *va)
2129733a808SDag-Erling Smørgrav {
2139733a808SDag-Erling Smørgrav struct vnode *vn = va->a_vp;
214388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
215649ad985SDag-Erling Smørgrav struct pfs_node *pn = pvd->pvd_pn;
2169733a808SDag-Erling Smørgrav struct vattr *vap = va->a_vap;
21780a3cef8SDag-Erling Smørgrav struct proc *proc;
21880a3cef8SDag-Erling Smørgrav int error = 0;
21980a3cef8SDag-Erling Smørgrav
220388596dfSDag-Erling Smørgrav PFS_TRACE(("%s", pn->pn_name));
221388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
2229733a808SDag-Erling Smørgrav
22353011553SMateusz Guzik if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
224134ce0f9SDag-Erling Smørgrav PFS_RETURN (ENOENT);
225134ce0f9SDag-Erling Smørgrav
2269733a808SDag-Erling Smørgrav vap->va_type = vn->v_type;
227388596dfSDag-Erling Smørgrav vap->va_fileid = pn_fileno(pn, pvd->pvd_pid);
2289733a808SDag-Erling Smørgrav vap->va_flags = 0;
2299733a808SDag-Erling Smørgrav vap->va_blocksize = PAGE_SIZE;
2309733a808SDag-Erling Smørgrav vap->va_bytes = vap->va_size = 0;
231caf8aec8SKonstantin Belousov vap->va_filerev = 0;
2329733a808SDag-Erling Smørgrav vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
2339733a808SDag-Erling Smørgrav vap->va_nlink = 1;
2349733a808SDag-Erling Smørgrav nanotime(&vap->va_ctime);
2359733a808SDag-Erling Smørgrav vap->va_atime = vap->va_mtime = vap->va_ctime;
2369733a808SDag-Erling Smørgrav
23780a3cef8SDag-Erling Smørgrav switch (pn->pn_type) {
23880a3cef8SDag-Erling Smørgrav case pfstype_procdir:
23980a3cef8SDag-Erling Smørgrav case pfstype_root:
24080a3cef8SDag-Erling Smørgrav case pfstype_dir:
241388596dfSDag-Erling Smørgrav #if 0
242388596dfSDag-Erling Smørgrav pfs_lock(pn);
243388596dfSDag-Erling Smørgrav /* compute link count */
244388596dfSDag-Erling Smørgrav pfs_unlock(pn);
245388596dfSDag-Erling Smørgrav #endif
24680a3cef8SDag-Erling Smørgrav vap->va_mode = 0555;
24780a3cef8SDag-Erling Smørgrav break;
24880a3cef8SDag-Erling Smørgrav case pfstype_file:
24980a3cef8SDag-Erling Smørgrav case pfstype_symlink:
2507d8f809fSDag-Erling Smørgrav vap->va_mode = 0444;
25180a3cef8SDag-Erling Smørgrav break;
25280a3cef8SDag-Erling Smørgrav default:
25380a3cef8SDag-Erling Smørgrav printf("shouldn't be here!\n");
25480a3cef8SDag-Erling Smørgrav vap->va_mode = 0;
25580a3cef8SDag-Erling Smørgrav break;
25680a3cef8SDag-Erling Smørgrav }
25780a3cef8SDag-Erling Smørgrav
258f8e3eeb5SJohn Baldwin if (proc != NULL) {
25980a3cef8SDag-Erling Smørgrav vap->va_uid = proc->p_ucred->cr_ruid;
26080a3cef8SDag-Erling Smørgrav vap->va_gid = proc->p_ucred->cr_rgid;
26180a3cef8SDag-Erling Smørgrav } else {
26280a3cef8SDag-Erling Smørgrav vap->va_uid = 0;
26380a3cef8SDag-Erling Smørgrav vap->va_gid = 0;
26480a3cef8SDag-Erling Smørgrav }
26580a3cef8SDag-Erling Smørgrav
266655fcdaaSDag-Erling Smørgrav if (pn->pn_attr != NULL)
267655fcdaaSDag-Erling Smørgrav error = pn_attr(curthread, proc, pn, vap);
268655fcdaaSDag-Erling Smørgrav
269655fcdaaSDag-Erling Smørgrav if(proc != NULL)
270655fcdaaSDag-Erling Smørgrav PROC_UNLOCK(proc);
271655fcdaaSDag-Erling Smørgrav
27280a3cef8SDag-Erling Smørgrav PFS_RETURN (error);
2739733a808SDag-Erling Smørgrav }
2749733a808SDag-Erling Smørgrav
2759733a808SDag-Erling Smørgrav /*
27618319000SDag-Erling Smørgrav * Perform an ioctl
27718319000SDag-Erling Smørgrav */
27818319000SDag-Erling Smørgrav static int
pfs_ioctl(struct vop_ioctl_args * va)27918319000SDag-Erling Smørgrav pfs_ioctl(struct vop_ioctl_args *va)
28018319000SDag-Erling Smørgrav {
281c4df27d5SKonstantin Belousov struct vnode *vn;
282c4df27d5SKonstantin Belousov struct pfs_vdata *pvd;
283c4df27d5SKonstantin Belousov struct pfs_node *pn;
284f8e3eeb5SJohn Baldwin struct proc *proc;
28518319000SDag-Erling Smørgrav int error;
28618319000SDag-Erling Smørgrav
287c4df27d5SKonstantin Belousov vn = va->a_vp;
288c4df27d5SKonstantin Belousov vn_lock(vn, LK_SHARED | LK_RETRY);
289abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vn)) {
290b249ce48SMateusz Guzik VOP_UNLOCK(vn);
291c4df27d5SKonstantin Belousov return (EBADF);
292c4df27d5SKonstantin Belousov }
293c4df27d5SKonstantin Belousov pvd = vn->v_data;
294c4df27d5SKonstantin Belousov pn = pvd->pvd_pn;
295c4df27d5SKonstantin Belousov
296c07f9fc1SDag-Erling Smørgrav PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
297388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
29818319000SDag-Erling Smørgrav
299c4df27d5SKonstantin Belousov if (vn->v_type != VREG) {
300b249ce48SMateusz Guzik VOP_UNLOCK(vn);
30118319000SDag-Erling Smørgrav PFS_RETURN (EINVAL);
302c4df27d5SKonstantin Belousov }
30359fc1b06SDag-Erling Smørgrav KASSERT_PN_IS_FILE(pn);
30418319000SDag-Erling Smørgrav
305c4df27d5SKonstantin Belousov if (pn->pn_ioctl == NULL) {
306b249ce48SMateusz Guzik VOP_UNLOCK(vn);
30718319000SDag-Erling Smørgrav PFS_RETURN (ENOTTY);
308c4df27d5SKonstantin Belousov }
30918319000SDag-Erling Smørgrav
31018319000SDag-Erling Smørgrav /*
311efe0afa9SJohn-Mark Gurney * This is necessary because process' privileges may
31218319000SDag-Erling Smørgrav * have changed since the open() call.
31318319000SDag-Erling Smørgrav */
31453011553SMateusz Guzik if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) {
315b249ce48SMateusz Guzik VOP_UNLOCK(vn);
31618319000SDag-Erling Smørgrav PFS_RETURN (EIO);
317c4df27d5SKonstantin Belousov }
31818319000SDag-Erling Smørgrav
319388596dfSDag-Erling Smørgrav error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data);
32018319000SDag-Erling Smørgrav
32118319000SDag-Erling Smørgrav if (proc != NULL)
322388596dfSDag-Erling Smørgrav PROC_UNLOCK(proc);
32318319000SDag-Erling Smørgrav
324b249ce48SMateusz Guzik VOP_UNLOCK(vn);
32518319000SDag-Erling Smørgrav PFS_RETURN (error);
32618319000SDag-Erling Smørgrav }
32718319000SDag-Erling Smørgrav
32818319000SDag-Erling Smørgrav /*
32941a35633SBrian Feldman * Perform getextattr
33041a35633SBrian Feldman */
33141a35633SBrian Feldman static int
pfs_getextattr(struct vop_getextattr_args * va)33241a35633SBrian Feldman pfs_getextattr(struct vop_getextattr_args *va)
33341a35633SBrian Feldman {
33441a35633SBrian Feldman struct vnode *vn = va->a_vp;
335388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
33641a35633SBrian Feldman struct pfs_node *pn = pvd->pvd_pn;
337f8e3eeb5SJohn Baldwin struct proc *proc;
33841a35633SBrian Feldman int error;
33941a35633SBrian Feldman
340388596dfSDag-Erling Smørgrav PFS_TRACE(("%s", pn->pn_name));
341388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
34241a35633SBrian Feldman
34341a35633SBrian Feldman /*
34441a35633SBrian Feldman * This is necessary because either process' privileges may
34541a35633SBrian Feldman * have changed since the open() call.
34641a35633SBrian Feldman */
34753011553SMateusz Guzik if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
34841a35633SBrian Feldman PFS_RETURN (EIO);
34941a35633SBrian Feldman
350388596dfSDag-Erling Smørgrav if (pn->pn_getextattr == NULL)
351388596dfSDag-Erling Smørgrav error = EOPNOTSUPP;
352388596dfSDag-Erling Smørgrav else
353388596dfSDag-Erling Smørgrav error = pn_getextattr(curthread, proc, pn,
354388596dfSDag-Erling Smørgrav va->a_attrnamespace, va->a_name, va->a_uio,
355388596dfSDag-Erling Smørgrav va->a_size, va->a_cred);
35641a35633SBrian Feldman
35741a35633SBrian Feldman if (proc != NULL)
358388596dfSDag-Erling Smørgrav PROC_UNLOCK(proc);
35941a35633SBrian Feldman
36041a35633SBrian Feldman PFS_RETURN (error);
36141a35633SBrian Feldman }
36241a35633SBrian Feldman
36341a35633SBrian Feldman /*
364e7f54c1bSJoe Marcus Clarke * Convert a vnode to its component name
365e7f54c1bSJoe Marcus Clarke */
366e7f54c1bSJoe Marcus Clarke static int
pfs_vptocnp(struct vop_vptocnp_args * ap)367e7f54c1bSJoe Marcus Clarke pfs_vptocnp(struct vop_vptocnp_args *ap)
368e7f54c1bSJoe Marcus Clarke {
369e7f54c1bSJoe Marcus Clarke struct vnode *vp = ap->a_vp;
370e7f54c1bSJoe Marcus Clarke struct vnode **dvp = ap->a_vpp;
371e7f54c1bSJoe Marcus Clarke struct pfs_vdata *pvd = vp->v_data;
372e7f54c1bSJoe Marcus Clarke struct pfs_node *pd = pvd->pvd_pn;
373e7f54c1bSJoe Marcus Clarke struct pfs_node *pn;
374e7f54c1bSJoe Marcus Clarke struct mount *mp;
375e7f54c1bSJoe Marcus Clarke char *buf = ap->a_buf;
37645757984SMateusz Guzik size_t *buflen = ap->a_buflen;
377e7f54c1bSJoe Marcus Clarke char pidbuf[PFS_NAMELEN];
378e7f54c1bSJoe Marcus Clarke pid_t pid = pvd->pvd_pid;
379e7f54c1bSJoe Marcus Clarke int len, i, error, locked;
380e7f54c1bSJoe Marcus Clarke
381e7f54c1bSJoe Marcus Clarke i = *buflen;
382e7f54c1bSJoe Marcus Clarke error = 0;
383e7f54c1bSJoe Marcus Clarke
384e7f54c1bSJoe Marcus Clarke pfs_lock(pd);
385e7f54c1bSJoe Marcus Clarke
386e7f54c1bSJoe Marcus Clarke if (vp->v_type == VDIR && pd->pn_type == pfstype_root) {
387e7f54c1bSJoe Marcus Clarke *dvp = vp;
388e7f54c1bSJoe Marcus Clarke vhold(*dvp);
389e7f54c1bSJoe Marcus Clarke pfs_unlock(pd);
390e7f54c1bSJoe Marcus Clarke PFS_RETURN (0);
391e7f54c1bSJoe Marcus Clarke } else if (vp->v_type == VDIR && pd->pn_type == pfstype_procdir) {
392e7f54c1bSJoe Marcus Clarke len = snprintf(pidbuf, sizeof(pidbuf), "%d", pid);
393e7f54c1bSJoe Marcus Clarke i -= len;
394e7f54c1bSJoe Marcus Clarke if (i < 0) {
395e7f54c1bSJoe Marcus Clarke error = ENOMEM;
396e7f54c1bSJoe Marcus Clarke goto failed;
397e7f54c1bSJoe Marcus Clarke }
398e7f54c1bSJoe Marcus Clarke bcopy(pidbuf, buf + i, len);
399e7f54c1bSJoe Marcus Clarke } else {
40026088b9dSDag-Erling Smørgrav len = strlen(pd->pn_name);
40126088b9dSDag-Erling Smørgrav i -= len;
402e7f54c1bSJoe Marcus Clarke if (i < 0) {
403e7f54c1bSJoe Marcus Clarke error = ENOMEM;
404e7f54c1bSJoe Marcus Clarke goto failed;
405e7f54c1bSJoe Marcus Clarke }
40626088b9dSDag-Erling Smørgrav bcopy(pd->pn_name, buf + i, len);
407e7f54c1bSJoe Marcus Clarke }
408e7f54c1bSJoe Marcus Clarke
409e7f54c1bSJoe Marcus Clarke pn = pd->pn_parent;
410e7f54c1bSJoe Marcus Clarke pfs_unlock(pd);
411e7f54c1bSJoe Marcus Clarke
412e7f54c1bSJoe Marcus Clarke mp = vp->v_mount;
413e7f54c1bSJoe Marcus Clarke error = vfs_busy(mp, 0);
414e7f54c1bSJoe Marcus Clarke if (error)
415e7f54c1bSJoe Marcus Clarke return (error);
416e7f54c1bSJoe Marcus Clarke
417e7f54c1bSJoe Marcus Clarke /*
418e7f54c1bSJoe Marcus Clarke * vp is held by caller.
419e7f54c1bSJoe Marcus Clarke */
420e7f54c1bSJoe Marcus Clarke locked = VOP_ISLOCKED(vp);
421b249ce48SMateusz Guzik VOP_UNLOCK(vp);
422e7f54c1bSJoe Marcus Clarke
423e7f54c1bSJoe Marcus Clarke error = pfs_vncache_alloc(mp, dvp, pn, pid);
424e7f54c1bSJoe Marcus Clarke if (error) {
425e7f54c1bSJoe Marcus Clarke vn_lock(vp, locked | LK_RETRY);
426e7f54c1bSJoe Marcus Clarke vfs_unbusy(mp);
427e7f54c1bSJoe Marcus Clarke PFS_RETURN(error);
428e7f54c1bSJoe Marcus Clarke }
429e7f54c1bSJoe Marcus Clarke
430e7f54c1bSJoe Marcus Clarke *buflen = i;
431b249ce48SMateusz Guzik VOP_UNLOCK(*dvp);
432e7f54c1bSJoe Marcus Clarke vn_lock(vp, locked | LK_RETRY);
433e7f54c1bSJoe Marcus Clarke vfs_unbusy(mp);
434e7f54c1bSJoe Marcus Clarke
435e7f54c1bSJoe Marcus Clarke PFS_RETURN (0);
436e7f54c1bSJoe Marcus Clarke failed:
437e7f54c1bSJoe Marcus Clarke pfs_unlock(pd);
438e7f54c1bSJoe Marcus Clarke PFS_RETURN(error);
439e7f54c1bSJoe Marcus Clarke }
440e7f54c1bSJoe Marcus Clarke
441e7f54c1bSJoe Marcus Clarke /*
4429733a808SDag-Erling Smørgrav * Look up a file or directory
4439733a808SDag-Erling Smørgrav */
4449733a808SDag-Erling Smørgrav static int
pfs_lookup(struct vop_cachedlookup_args * va)4450e3b5c73SDag-Erling Smørgrav pfs_lookup(struct vop_cachedlookup_args *va)
4469733a808SDag-Erling Smørgrav {
447649ad985SDag-Erling Smørgrav struct vnode *vn = va->a_dvp;
4489733a808SDag-Erling Smørgrav struct vnode **vpp = va->a_vpp;
4499733a808SDag-Erling Smørgrav struct componentname *cnp = va->a_cnp;
450388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
451649ad985SDag-Erling Smørgrav struct pfs_node *pd = pvd->pvd_pn;
452649ad985SDag-Erling Smørgrav struct pfs_node *pn, *pdn = NULL;
45331452ff7SKonstantin Belousov struct mount *mp;
454649ad985SDag-Erling Smørgrav pid_t pid = pvd->pvd_pid;
4559733a808SDag-Erling Smørgrav char *pname;
456388596dfSDag-Erling Smørgrav int error, i, namelen, visible;
4579733a808SDag-Erling Smørgrav
45880a3cef8SDag-Erling Smørgrav PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
459388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pd);
46080a3cef8SDag-Erling Smørgrav
461649ad985SDag-Erling Smørgrav if (vn->v_type != VDIR)
46280a3cef8SDag-Erling Smørgrav PFS_RETURN (ENOTDIR);
46359fc1b06SDag-Erling Smørgrav KASSERT_PN_IS_DIR(pd);
4649733a808SDag-Erling Smørgrav
46580a3cef8SDag-Erling Smørgrav /*
46680a3cef8SDag-Erling Smørgrav * Don't support DELETE or RENAME. CREATE is supported so
46780a3cef8SDag-Erling Smørgrav * that O_CREAT will work, but the lookup will still fail if
46880a3cef8SDag-Erling Smørgrav * the file does not exist.
46980a3cef8SDag-Erling Smørgrav */
4700e3b5c73SDag-Erling Smørgrav if ((cnp->cn_flags & ISLASTCN) &&
4710e3b5c73SDag-Erling Smørgrav (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
4727d8f809fSDag-Erling Smørgrav PFS_RETURN (EOPNOTSUPP);
4739733a808SDag-Erling Smørgrav
47480a3cef8SDag-Erling Smørgrav /* shortcut: check if the name is too long */
4759733a808SDag-Erling Smørgrav if (cnp->cn_namelen >= PFS_NAMELEN)
47680a3cef8SDag-Erling Smørgrav PFS_RETURN (ENOENT);
47780a3cef8SDag-Erling Smørgrav
478f8e3eeb5SJohn Baldwin /* check that parent directory is visible... */
47953011553SMateusz Guzik if (!pfs_visible(curthread, pd, pvd->pvd_pid, NULL))
48080a3cef8SDag-Erling Smørgrav PFS_RETURN (ENOENT);
4819733a808SDag-Erling Smørgrav
4829733a808SDag-Erling Smørgrav /* self */
483649ad985SDag-Erling Smørgrav namelen = cnp->cn_namelen;
4849733a808SDag-Erling Smørgrav pname = cnp->cn_nameptr;
4850e3b5c73SDag-Erling Smørgrav if (namelen == 1 && pname[0] == '.') {
4869733a808SDag-Erling Smørgrav pn = pd;
487649ad985SDag-Erling Smørgrav *vpp = vn;
488649ad985SDag-Erling Smørgrav VREF(vn);
489198bc14bSDag-Erling Smørgrav PFS_RETURN (0);
4909733a808SDag-Erling Smørgrav }
4919733a808SDag-Erling Smørgrav
49231452ff7SKonstantin Belousov mp = vn->v_mount;
49331452ff7SKonstantin Belousov
4949733a808SDag-Erling Smørgrav /* parent */
4959733a808SDag-Erling Smørgrav if (cnp->cn_flags & ISDOTDOT) {
4969733a808SDag-Erling Smørgrav if (pd->pn_type == pfstype_root)
49780a3cef8SDag-Erling Smørgrav PFS_RETURN (EIO);
49831452ff7SKonstantin Belousov error = vfs_busy(mp, MBF_NOWAIT);
49931452ff7SKonstantin Belousov if (error != 0) {
50031452ff7SKonstantin Belousov vfs_ref(mp);
501b249ce48SMateusz Guzik VOP_UNLOCK(vn);
50231452ff7SKonstantin Belousov error = vfs_busy(mp, 0);
50331452ff7SKonstantin Belousov vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
50431452ff7SKonstantin Belousov vfs_rel(mp);
50531452ff7SKonstantin Belousov if (error != 0)
50631452ff7SKonstantin Belousov PFS_RETURN(ENOENT);
507abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vn)) {
50831452ff7SKonstantin Belousov vfs_unbusy(mp);
50931452ff7SKonstantin Belousov PFS_RETURN(ENOENT);
51031452ff7SKonstantin Belousov }
51131452ff7SKonstantin Belousov }
512b249ce48SMateusz Guzik VOP_UNLOCK(vn);
513388596dfSDag-Erling Smørgrav KASSERT(pd->pn_parent != NULL,
514388596dfSDag-Erling Smørgrav ("%s(): non-root directory has no parent", __func__));
515649ad985SDag-Erling Smørgrav /*
516649ad985SDag-Erling Smørgrav * This one is tricky. Descendents of procdir nodes
517649ad985SDag-Erling Smørgrav * inherit their parent's process affinity, but
518649ad985SDag-Erling Smørgrav * there's no easy reverse mapping. For simplicity,
519649ad985SDag-Erling Smørgrav * we assume that if this node is a procdir, its
520649ad985SDag-Erling Smørgrav * parent isn't (which is correct as long as
521649ad985SDag-Erling Smørgrav * descendents of procdir nodes are never procdir
522649ad985SDag-Erling Smørgrav * nodes themselves)
523649ad985SDag-Erling Smørgrav */
524649ad985SDag-Erling Smørgrav if (pd->pn_type == pfstype_procdir)
525649ad985SDag-Erling Smørgrav pid = NO_PID;
526388596dfSDag-Erling Smørgrav pfs_lock(pd);
527198bc14bSDag-Erling Smørgrav pn = pd->pn_parent;
528388596dfSDag-Erling Smørgrav pfs_unlock(pd);
529198bc14bSDag-Erling Smørgrav goto got_pnode;
5309733a808SDag-Erling Smørgrav }
5319733a808SDag-Erling Smørgrav
532388596dfSDag-Erling Smørgrav pfs_lock(pd);
533388596dfSDag-Erling Smørgrav
534649ad985SDag-Erling Smørgrav /* named node */
53533802b9eSDag-Erling Smørgrav for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
536649ad985SDag-Erling Smørgrav if (pn->pn_type == pfstype_procdir)
537649ad985SDag-Erling Smørgrav pdn = pn;
538fc915f1bSMark Johnston else if (strncmp(pname, pn->pn_name, namelen) == 0 &&
539fc915f1bSMark Johnston pn->pn_name[namelen] == '\0') {
540388596dfSDag-Erling Smørgrav pfs_unlock(pd);
5419733a808SDag-Erling Smørgrav goto got_pnode;
542388596dfSDag-Erling Smørgrav }
5439733a808SDag-Erling Smørgrav
544649ad985SDag-Erling Smørgrav /* process dependent node */
545649ad985SDag-Erling Smørgrav if ((pn = pdn) != NULL) {
546649ad985SDag-Erling Smørgrav pid = 0;
547649ad985SDag-Erling Smørgrav for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
548649ad985SDag-Erling Smørgrav if ((pid = pid * 10 + pname[i] - '0') > PID_MAX)
5499733a808SDag-Erling Smørgrav break;
550388596dfSDag-Erling Smørgrav if (i == cnp->cn_namelen) {
551388596dfSDag-Erling Smørgrav pfs_unlock(pd);
5529733a808SDag-Erling Smørgrav goto got_pnode;
5539733a808SDag-Erling Smørgrav }
554388596dfSDag-Erling Smørgrav }
555388596dfSDag-Erling Smørgrav
556388596dfSDag-Erling Smørgrav pfs_unlock(pd);
5579733a808SDag-Erling Smørgrav
5587d8f809fSDag-Erling Smørgrav PFS_RETURN (ENOENT);
559388596dfSDag-Erling Smørgrav
5609733a808SDag-Erling Smørgrav got_pnode:
561388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pd);
562388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
56353011553SMateusz Guzik visible = pfs_visible(curthread, pn, pid, NULL);
564388596dfSDag-Erling Smørgrav if (!visible) {
565eddcb03dSJeff Roberson error = ENOENT;
566eddcb03dSJeff Roberson goto failed;
567eddcb03dSJeff Roberson }
568922b974aSJeff Roberson
56931452ff7SKonstantin Belousov error = pfs_vncache_alloc(mp, vpp, pn, pid);
5709733a808SDag-Erling Smørgrav if (error)
571eddcb03dSJeff Roberson goto failed;
572922b974aSJeff Roberson
57331452ff7SKonstantin Belousov if (cnp->cn_flags & ISDOTDOT) {
57431452ff7SKonstantin Belousov vfs_unbusy(mp);
575cb05b60aSAttilio Rao vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
576abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vn)) {
57731452ff7SKonstantin Belousov vput(*vpp);
57831452ff7SKonstantin Belousov *vpp = NULL;
57931452ff7SKonstantin Belousov PFS_RETURN(ENOENT);
58031452ff7SKonstantin Belousov }
58131452ff7SKonstantin Belousov }
582abd80ddbSMateusz Guzik if (cnp->cn_flags & MAKEENTRY && !VN_IS_DOOMED(vn))
583649ad985SDag-Erling Smørgrav cache_enter(vn, *vpp, cnp);
58480a3cef8SDag-Erling Smørgrav PFS_RETURN (0);
585eddcb03dSJeff Roberson failed:
58631452ff7SKonstantin Belousov if (cnp->cn_flags & ISDOTDOT) {
58731452ff7SKonstantin Belousov vfs_unbusy(mp);
588cb05b60aSAttilio Rao vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
58931452ff7SKonstantin Belousov *vpp = NULL;
59031452ff7SKonstantin Belousov }
591eddcb03dSJeff Roberson PFS_RETURN(error);
5929733a808SDag-Erling Smørgrav }
5939733a808SDag-Erling Smørgrav
5949733a808SDag-Erling Smørgrav /*
5959733a808SDag-Erling Smørgrav * Open a file or directory.
5969733a808SDag-Erling Smørgrav */
5979733a808SDag-Erling Smørgrav static int
pfs_open(struct vop_open_args * va)5989733a808SDag-Erling Smørgrav pfs_open(struct vop_open_args *va)
5999733a808SDag-Erling Smørgrav {
60080a3cef8SDag-Erling Smørgrav struct vnode *vn = va->a_vp;
601388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
60280a3cef8SDag-Erling Smørgrav struct pfs_node *pn = pvd->pvd_pn;
6037d8f809fSDag-Erling Smørgrav int mode = va->a_mode;
60480a3cef8SDag-Erling Smørgrav
6057d8f809fSDag-Erling Smørgrav PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
606388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
607198bc14bSDag-Erling Smørgrav
6087d8f809fSDag-Erling Smørgrav /* check if the requested mode is permitted */
6097d8f809fSDag-Erling Smørgrav if (((mode & FREAD) && !(mode & PFS_RD)) ||
6107d8f809fSDag-Erling Smørgrav ((mode & FWRITE) && !(mode & PFS_WR)))
6117d8f809fSDag-Erling Smørgrav PFS_RETURN (EPERM);
6127d8f809fSDag-Erling Smørgrav
6137d8f809fSDag-Erling Smørgrav /* we don't support locking */
6147d8f809fSDag-Erling Smørgrav if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
6157d8f809fSDag-Erling Smørgrav PFS_RETURN (EOPNOTSUPP);
61680a3cef8SDag-Erling Smørgrav
617198bc14bSDag-Erling Smørgrav PFS_RETURN (0);
6189733a808SDag-Erling Smørgrav }
6199733a808SDag-Erling Smørgrav
62020172854SConrad Meyer struct sbuf_seek_helper {
62120172854SConrad Meyer off_t skip_bytes;
62220172854SConrad Meyer struct uio *uio;
62320172854SConrad Meyer };
62420172854SConrad Meyer
62520172854SConrad Meyer static int
pfs_sbuf_uio_drain(void * arg,const char * data,int len)62620172854SConrad Meyer pfs_sbuf_uio_drain(void *arg, const char *data, int len)
62720172854SConrad Meyer {
62820172854SConrad Meyer struct sbuf_seek_helper *ssh;
62920172854SConrad Meyer struct uio *uio;
63020172854SConrad Meyer int error, skipped;
63120172854SConrad Meyer
63220172854SConrad Meyer ssh = arg;
63320172854SConrad Meyer uio = ssh->uio;
63420172854SConrad Meyer skipped = 0;
63520172854SConrad Meyer
63620172854SConrad Meyer /* Need to discard first uio_offset bytes. */
63720172854SConrad Meyer if (ssh->skip_bytes > 0) {
63820172854SConrad Meyer if (ssh->skip_bytes >= len) {
63920172854SConrad Meyer ssh->skip_bytes -= len;
64020172854SConrad Meyer return (len);
64120172854SConrad Meyer }
64220172854SConrad Meyer
64320172854SConrad Meyer data += ssh->skip_bytes;
64420172854SConrad Meyer len -= ssh->skip_bytes;
64520172854SConrad Meyer skipped = ssh->skip_bytes;
64620172854SConrad Meyer ssh->skip_bytes = 0;
64720172854SConrad Meyer }
64820172854SConrad Meyer
64920172854SConrad Meyer error = uiomove(__DECONST(void *, data), len, uio);
65020172854SConrad Meyer if (error != 0)
65120172854SConrad Meyer return (-error);
65220172854SConrad Meyer
65320172854SConrad Meyer /*
65420172854SConrad Meyer * The fill function has more to emit, but the reader is finished.
65520172854SConrad Meyer * This is similar to the truncated read case for non-draining PFS
65620172854SConrad Meyer * sbufs, and should be handled appropriately in fill-routines.
65720172854SConrad Meyer */
65820172854SConrad Meyer if (uio->uio_resid == 0)
65920172854SConrad Meyer return (-ENOBUFS);
66020172854SConrad Meyer
66120172854SConrad Meyer return (skipped + len);
66220172854SConrad Meyer }
66320172854SConrad Meyer
6649733a808SDag-Erling Smørgrav /*
6659733a808SDag-Erling Smørgrav * Read from a file
6669733a808SDag-Erling Smørgrav */
6679733a808SDag-Erling Smørgrav static int
pfs_read(struct vop_read_args * va)6689733a808SDag-Erling Smørgrav pfs_read(struct vop_read_args *va)
6699733a808SDag-Erling Smørgrav {
6709733a808SDag-Erling Smørgrav struct vnode *vn = va->a_vp;
671388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
672649ad985SDag-Erling Smørgrav struct pfs_node *pn = pvd->pvd_pn;
6739733a808SDag-Erling Smørgrav struct uio *uio = va->a_uio;
674f8e3eeb5SJohn Baldwin struct proc *proc;
67531f73b3fSDag-Erling Smørgrav struct sbuf *sb = NULL;
676505d02eeSKonstantin Belousov int error, locked;
67720172854SConrad Meyer off_t buflen, buflim;
67820172854SConrad Meyer struct sbuf_seek_helper ssh;
6799733a808SDag-Erling Smørgrav
680388596dfSDag-Erling Smørgrav PFS_TRACE(("%s", pn->pn_name));
681388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
68280a3cef8SDag-Erling Smørgrav
6839733a808SDag-Erling Smørgrav if (vn->v_type != VREG)
6847d8f809fSDag-Erling Smørgrav PFS_RETURN (EINVAL);
68559fc1b06SDag-Erling Smørgrav KASSERT_PN_IS_FILE(pn);
6869733a808SDag-Erling Smørgrav
6877d8f809fSDag-Erling Smørgrav if (!(pn->pn_flags & PFS_RD))
6887d8f809fSDag-Erling Smørgrav PFS_RETURN (EBADF);
6898712e867SDag-Erling Smørgrav
690388596dfSDag-Erling Smørgrav if (pn->pn_fill == NULL)
69118319000SDag-Erling Smørgrav PFS_RETURN (EIO);
69233802b9eSDag-Erling Smørgrav
693198bc14bSDag-Erling Smørgrav /*
694198bc14bSDag-Erling Smørgrav * This is necessary because either process' privileges may
695198bc14bSDag-Erling Smørgrav * have changed since the open() call.
696198bc14bSDag-Erling Smørgrav */
69753011553SMateusz Guzik if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
698198bc14bSDag-Erling Smørgrav PFS_RETURN (EIO);
699f8e3eeb5SJohn Baldwin if (proc != NULL) {
700649ad985SDag-Erling Smørgrav _PHOLD(proc);
701649ad985SDag-Erling Smørgrav PROC_UNLOCK(proc);
702649ad985SDag-Erling Smørgrav }
7039733a808SDag-Erling Smørgrav
704505d02eeSKonstantin Belousov vhold(vn);
705505d02eeSKonstantin Belousov locked = VOP_ISLOCKED(vn);
706b249ce48SMateusz Guzik VOP_UNLOCK(vn);
707505d02eeSKonstantin Belousov
7088712e867SDag-Erling Smørgrav if (pn->pn_flags & PFS_RAWRD) {
7099f80ce04SKonstantin Belousov PFS_TRACE(("%zd resid", uio->uio_resid));
710388596dfSDag-Erling Smørgrav error = pn_fill(curthread, proc, pn, NULL, uio);
7119f80ce04SKonstantin Belousov PFS_TRACE(("%zd resid", uio->uio_resid));
712505d02eeSKonstantin Belousov goto ret;
7138712e867SDag-Erling Smørgrav }
7148712e867SDag-Erling Smørgrav
715587430f2SKonstantin Belousov if (uio->uio_resid < 0 || uio->uio_offset < 0 ||
716587430f2SKonstantin Belousov uio->uio_resid > OFF_MAX - uio->uio_offset) {
717505d02eeSKonstantin Belousov error = EINVAL;
718505d02eeSKonstantin Belousov goto ret;
7198b7358caSJacques Vidrine }
72020172854SConrad Meyer buflen = uio->uio_offset + uio->uio_resid + 1;
72120172854SConrad Meyer if (pn->pn_flags & PFS_AUTODRAIN)
72220172854SConrad Meyer /*
72320172854SConrad Meyer * We can use a smaller buffer if we can stream output to the
72420172854SConrad Meyer * consumer.
72520172854SConrad Meyer */
72620172854SConrad Meyer buflim = PAGE_SIZE;
72720172854SConrad Meyer else
72820172854SConrad Meyer buflim = PFS_MAXBUFSIZ;
72920172854SConrad Meyer if (buflen > buflim)
73020172854SConrad Meyer buflen = buflim;
731388596dfSDag-Erling Smørgrav
73220172854SConrad Meyer sb = sbuf_new(sb, NULL, buflen, 0);
733649ad985SDag-Erling Smørgrav if (sb == NULL) {
734505d02eeSKonstantin Belousov error = EIO;
735505d02eeSKonstantin Belousov goto ret;
736649ad985SDag-Erling Smørgrav }
737649ad985SDag-Erling Smørgrav
73820172854SConrad Meyer if (pn->pn_flags & PFS_AUTODRAIN) {
73920172854SConrad Meyer ssh.skip_bytes = uio->uio_offset;
74020172854SConrad Meyer ssh.uio = uio;
74120172854SConrad Meyer sbuf_set_drain(sb, pfs_sbuf_uio_drain, &ssh);
74220172854SConrad Meyer }
74320172854SConrad Meyer
744388596dfSDag-Erling Smørgrav error = pn_fill(curthread, proc, pn, sb, uio);
745649ad985SDag-Erling Smørgrav
746b27acc8dSDag-Erling Smørgrav if (error) {
747b27acc8dSDag-Erling Smørgrav sbuf_delete(sb);
748505d02eeSKonstantin Belousov goto ret;
749b27acc8dSDag-Erling Smørgrav }
750b27acc8dSDag-Erling Smørgrav
751d467c947SJaakko Heinonen /*
752d467c947SJaakko Heinonen * XXX: If the buffer overflowed, sbuf_len() will not return
753d467c947SJaakko Heinonen * the data length. Then just use the full length because an
754d467c947SJaakko Heinonen * overflowed sbuf must be full.
755d467c947SJaakko Heinonen */
75620172854SConrad Meyer error = sbuf_finish(sb);
75720172854SConrad Meyer if ((pn->pn_flags & PFS_AUTODRAIN)) {
75820172854SConrad Meyer /*
75920172854SConrad Meyer * ENOBUFS just indicates early termination of the fill
76020172854SConrad Meyer * function as the caller's buffer was already filled. Squash
76120172854SConrad Meyer * to zero.
76220172854SConrad Meyer */
76320172854SConrad Meyer if (uio->uio_resid == 0 && error == ENOBUFS)
76420172854SConrad Meyer error = 0;
76520172854SConrad Meyer } else {
76620172854SConrad Meyer if (error == 0)
767d467c947SJaakko Heinonen buflen = sbuf_len(sb);
76820172854SConrad Meyer else
76920172854SConrad Meyer /* The trailing byte is not valid. */
77020172854SConrad Meyer buflen--;
771d467c947SJaakko Heinonen error = uiomove_frombuf(sbuf_data(sb), buflen, uio);
77220172854SConrad Meyer }
77331f73b3fSDag-Erling Smørgrav sbuf_delete(sb);
774505d02eeSKonstantin Belousov ret:
775505d02eeSKonstantin Belousov vn_lock(vn, locked | LK_RETRY);
776505d02eeSKonstantin Belousov vdrop(vn);
777505d02eeSKonstantin Belousov if (proc != NULL)
778505d02eeSKonstantin Belousov PRELE(proc);
7797d8f809fSDag-Erling Smørgrav PFS_RETURN (error);
7809733a808SDag-Erling Smørgrav }
7819733a808SDag-Erling Smørgrav
7829733a808SDag-Erling Smørgrav /*
783649ad985SDag-Erling Smørgrav * Iterate through directory entries
784649ad985SDag-Erling Smørgrav */
785649ad985SDag-Erling Smørgrav static int
pfs_iterate(struct thread * td,struct proc * proc,struct pfs_node * pd,struct pfs_node ** pn,struct proc ** p)786388596dfSDag-Erling Smørgrav pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd,
78733802b9eSDag-Erling Smørgrav struct pfs_node **pn, struct proc **p)
788649ad985SDag-Erling Smørgrav {
789388596dfSDag-Erling Smørgrav int visible;
790388596dfSDag-Erling Smørgrav
791f8e3eeb5SJohn Baldwin sx_assert(&allproc_lock, SX_SLOCKED);
792388596dfSDag-Erling Smørgrav pfs_assert_owned(pd);
793198bc14bSDag-Erling Smørgrav again:
794653fae17SDag-Erling Smørgrav if (*pn == NULL) {
795653fae17SDag-Erling Smørgrav /* first node */
796653fae17SDag-Erling Smørgrav *pn = pd->pn_nodes;
797653fae17SDag-Erling Smørgrav } else if ((*pn)->pn_type != pfstype_procdir) {
798653fae17SDag-Erling Smørgrav /* next node */
79933802b9eSDag-Erling Smørgrav *pn = (*pn)->pn_next;
800653fae17SDag-Erling Smørgrav }
801653fae17SDag-Erling Smørgrav if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
802653fae17SDag-Erling Smørgrav /* next process */
803649ad985SDag-Erling Smørgrav if (*p == NULL)
804649ad985SDag-Erling Smørgrav *p = LIST_FIRST(&allproc);
805649ad985SDag-Erling Smørgrav else
806649ad985SDag-Erling Smørgrav *p = LIST_NEXT(*p, p_list);
807653fae17SDag-Erling Smørgrav /* out of processes: next node */
808653fae17SDag-Erling Smørgrav if (*p == NULL)
80933802b9eSDag-Erling Smørgrav *pn = (*pn)->pn_next;
810388596dfSDag-Erling Smørgrav else
811388596dfSDag-Erling Smørgrav PROC_LOCK(*p);
812649ad985SDag-Erling Smørgrav }
813649ad985SDag-Erling Smørgrav
81433802b9eSDag-Erling Smørgrav if ((*pn) == NULL)
815649ad985SDag-Erling Smørgrav return (-1);
816649ad985SDag-Erling Smørgrav
817388596dfSDag-Erling Smørgrav if (*p != NULL) {
818388596dfSDag-Erling Smørgrav visible = pfs_visible_proc(td, *pn, *p);
819388596dfSDag-Erling Smørgrav PROC_UNLOCK(*p);
820388596dfSDag-Erling Smørgrav } else if (proc != NULL) {
821388596dfSDag-Erling Smørgrav visible = pfs_visible_proc(td, *pn, proc);
822388596dfSDag-Erling Smørgrav } else {
823405c0c04SDmitry Chagin visible = pn_vis(td, NULL, *pn);
824388596dfSDag-Erling Smørgrav }
825388596dfSDag-Erling Smørgrav if (!visible)
826198bc14bSDag-Erling Smørgrav goto again;
827198bc14bSDag-Erling Smørgrav
828649ad985SDag-Erling Smørgrav return (0);
829649ad985SDag-Erling Smørgrav }
830649ad985SDag-Erling Smørgrav
83150546f8fSPeter Holm /* Directory entry list */
83250546f8fSPeter Holm struct pfsentry {
83350546f8fSPeter Holm STAILQ_ENTRY(pfsentry) link;
83450546f8fSPeter Holm struct dirent entry;
83550546f8fSPeter Holm };
83650546f8fSPeter Holm STAILQ_HEAD(pfsdirentlist, pfsentry);
83750546f8fSPeter Holm
838649ad985SDag-Erling Smørgrav /*
8399733a808SDag-Erling Smørgrav * Return directory entries.
8409733a808SDag-Erling Smørgrav */
8419733a808SDag-Erling Smørgrav static int
pfs_readdir(struct vop_readdir_args * va)8429733a808SDag-Erling Smørgrav pfs_readdir(struct vop_readdir_args *va)
8439733a808SDag-Erling Smørgrav {
8449733a808SDag-Erling Smørgrav struct vnode *vn = va->a_vp;
845388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
846649ad985SDag-Erling Smørgrav struct pfs_node *pd = pvd->pvd_pn;
847198bc14bSDag-Erling Smørgrav pid_t pid = pvd->pvd_pid;
848388596dfSDag-Erling Smørgrav struct proc *p, *proc;
849649ad985SDag-Erling Smørgrav struct pfs_node *pn;
8509733a808SDag-Erling Smørgrav struct uio *uio;
85150546f8fSPeter Holm struct pfsentry *pfsent, *pfsent2;
85250546f8fSPeter Holm struct pfsdirentlist lst;
8539733a808SDag-Erling Smørgrav off_t offset;
8549733a808SDag-Erling Smørgrav int error, i, resid;
8559733a808SDag-Erling Smørgrav
85650546f8fSPeter Holm STAILQ_INIT(&lst);
85750546f8fSPeter Holm error = 0;
858f61bc4eaSDag-Erling Smørgrav KASSERT(pd->pn_info == vn->v_mount->mnt_data,
859388596dfSDag-Erling Smørgrav ("%s(): pn_info does not match mountpoint", __func__));
860388596dfSDag-Erling Smørgrav PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid));
861388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pd);
86280a3cef8SDag-Erling Smørgrav
8639733a808SDag-Erling Smørgrav if (vn->v_type != VDIR)
8647d8f809fSDag-Erling Smørgrav PFS_RETURN (ENOTDIR);
86559fc1b06SDag-Erling Smørgrav KASSERT_PN_IS_DIR(pd);
8669733a808SDag-Erling Smørgrav uio = va->a_uio;
8679733a808SDag-Erling Smørgrav
8689733a808SDag-Erling Smørgrav /* only allow reading entire entries */
8699733a808SDag-Erling Smørgrav offset = uio->uio_offset;
8709733a808SDag-Erling Smørgrav resid = uio->uio_resid;
871bc593ccdSDag-Erling Smørgrav if (offset < 0 || offset % PFS_DELEN != 0 ||
872bc593ccdSDag-Erling Smørgrav (resid && resid < PFS_DELEN))
8737d8f809fSDag-Erling Smørgrav PFS_RETURN (EINVAL);
874bc593ccdSDag-Erling Smørgrav if (resid == 0)
875bc593ccdSDag-Erling Smørgrav PFS_RETURN (0);
876195a6b21SDag-Erling Smørgrav
877f99c5e8dSKyle Evans proc = NULL;
878f99c5e8dSKyle Evans if (pid != NO_PID && !pfs_lookup_proc(pid, &proc))
879f5791174SMateusz Guzik PFS_RETURN (ENOENT);
880f5791174SMateusz Guzik
881649ad985SDag-Erling Smørgrav sx_slock(&allproc_lock);
882388596dfSDag-Erling Smørgrav pfs_lock(pd);
883f99c5e8dSKyle Evans
884f99c5e8dSKyle Evans KASSERT(pid == NO_PID || proc != NULL,
885f99c5e8dSKyle Evans ("%s(): no process for pid %lu", __func__, (unsigned long)pid));
886f99c5e8dSKyle Evans
887f99c5e8dSKyle Evans if (pid != NO_PID) {
888f5791174SMateusz Guzik PROC_LOCK(proc);
889388596dfSDag-Erling Smørgrav
890388596dfSDag-Erling Smørgrav /* check if the directory is visible to the caller */
891f5791174SMateusz Guzik if (!pfs_visible_proc(curthread, pd, proc)) {
892f5791174SMateusz Guzik _PRELE(proc);
893f5791174SMateusz Guzik PROC_UNLOCK(proc);
894388596dfSDag-Erling Smørgrav pfs_unlock(pd);
895b8bb73abSDag-Erling Smørgrav sx_sunlock(&allproc_lock);
896388596dfSDag-Erling Smørgrav PFS_RETURN (ENOENT);
897388596dfSDag-Erling Smørgrav }
898f99c5e8dSKyle Evans }
899388596dfSDag-Erling Smørgrav
900388596dfSDag-Erling Smørgrav /* skip unwanted entries */
901388596dfSDag-Erling Smørgrav for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) {
902388596dfSDag-Erling Smørgrav if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) {
903388596dfSDag-Erling Smørgrav /* nothing left... */
904f5791174SMateusz Guzik if (proc != NULL) {
905f5791174SMateusz Guzik _PRELE(proc);
906388596dfSDag-Erling Smørgrav PROC_UNLOCK(proc);
907f5791174SMateusz Guzik }
908388596dfSDag-Erling Smørgrav pfs_unlock(pd);
909388596dfSDag-Erling Smørgrav sx_sunlock(&allproc_lock);
91033802b9eSDag-Erling Smørgrav PFS_RETURN (0);
91133802b9eSDag-Erling Smørgrav }
912388596dfSDag-Erling Smørgrav }
9139733a808SDag-Erling Smørgrav
9149733a808SDag-Erling Smørgrav /* fill in entries */
915388596dfSDag-Erling Smørgrav while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 &&
916bc593ccdSDag-Erling Smørgrav resid >= PFS_DELEN) {
91750546f8fSPeter Holm if ((pfsent = malloc(sizeof(struct pfsentry), M_IOV,
91850546f8fSPeter Holm M_NOWAIT | M_ZERO)) == NULL) {
91950546f8fSPeter Holm error = ENOMEM;
92050546f8fSPeter Holm break;
92150546f8fSPeter Holm }
92250546f8fSPeter Holm pfsent->entry.d_reclen = PFS_DELEN;
92350546f8fSPeter Holm pfsent->entry.d_fileno = pn_fileno(pn, pid);
9249733a808SDag-Erling Smørgrav /* PFS_DELEN was picked to fit PFS_NAMLEN */
9259733a808SDag-Erling Smørgrav for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
92650546f8fSPeter Holm pfsent->entry.d_name[i] = pn->pn_name[i];
92750546f8fSPeter Holm pfsent->entry.d_namlen = i;
9281c4ca778SKonstantin Belousov /* NOTE: d_off is the offset of the *next* entry. */
9291c4ca778SKonstantin Belousov pfsent->entry.d_off = offset + PFS_DELEN;
9309733a808SDag-Erling Smørgrav switch (pn->pn_type) {
931649ad985SDag-Erling Smørgrav case pfstype_procdir:
932649ad985SDag-Erling Smørgrav KASSERT(p != NULL,
933649ad985SDag-Erling Smørgrav ("reached procdir node with p == NULL"));
93450546f8fSPeter Holm pfsent->entry.d_namlen = snprintf(pfsent->entry.d_name,
935649ad985SDag-Erling Smørgrav PFS_NAMELEN, "%d", p->p_pid);
936649ad985SDag-Erling Smørgrav /* fall through */
9379733a808SDag-Erling Smørgrav case pfstype_root:
9389733a808SDag-Erling Smørgrav case pfstype_dir:
9399733a808SDag-Erling Smørgrav case pfstype_this:
9409733a808SDag-Erling Smørgrav case pfstype_parent:
94150546f8fSPeter Holm pfsent->entry.d_type = DT_DIR;
9429733a808SDag-Erling Smørgrav break;
9439733a808SDag-Erling Smørgrav case pfstype_file:
94450546f8fSPeter Holm pfsent->entry.d_type = DT_REG;
9459733a808SDag-Erling Smørgrav break;
9469733a808SDag-Erling Smørgrav case pfstype_symlink:
94750546f8fSPeter Holm pfsent->entry.d_type = DT_LNK;
9489733a808SDag-Erling Smørgrav break;
9499733a808SDag-Erling Smørgrav default:
9509733a808SDag-Erling Smørgrav panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
9519733a808SDag-Erling Smørgrav }
95250546f8fSPeter Holm PFS_TRACE(("%s", pfsent->entry.d_name));
9536d2e2df7SMark Johnston dirent_terminate(&pfsent->entry);
95450546f8fSPeter Holm STAILQ_INSERT_TAIL(&lst, pfsent, link);
9559733a808SDag-Erling Smørgrav offset += PFS_DELEN;
9569733a808SDag-Erling Smørgrav resid -= PFS_DELEN;
9579733a808SDag-Erling Smørgrav }
958f5791174SMateusz Guzik if (proc != NULL) {
959f5791174SMateusz Guzik _PRELE(proc);
960388596dfSDag-Erling Smørgrav PROC_UNLOCK(proc);
961f5791174SMateusz Guzik }
962388596dfSDag-Erling Smørgrav pfs_unlock(pd);
9639733a808SDag-Erling Smørgrav sx_sunlock(&allproc_lock);
96450546f8fSPeter Holm i = 0;
96550546f8fSPeter Holm STAILQ_FOREACH_SAFE(pfsent, &lst, link, pfsent2) {
96650546f8fSPeter Holm if (error == 0)
96750546f8fSPeter Holm error = uiomove(&pfsent->entry, PFS_DELEN, uio);
96850546f8fSPeter Holm free(pfsent, M_IOV);
96950546f8fSPeter Holm i++;
97050546f8fSPeter Holm }
9716bfe4532SEnji Cooper PFS_TRACE(("%ju bytes", (uintmax_t)(i * PFS_DELEN)));
972195a6b21SDag-Erling Smørgrav PFS_RETURN (error);
9739733a808SDag-Erling Smørgrav }
9749733a808SDag-Erling Smørgrav
9759733a808SDag-Erling Smørgrav /*
9769733a808SDag-Erling Smørgrav * Read a symbolic link
9779733a808SDag-Erling Smørgrav */
9789733a808SDag-Erling Smørgrav static int
pfs_readlink(struct vop_readlink_args * va)9799733a808SDag-Erling Smørgrav pfs_readlink(struct vop_readlink_args *va)
9809733a808SDag-Erling Smørgrav {
9819733a808SDag-Erling Smørgrav struct vnode *vn = va->a_vp;
982388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
983649ad985SDag-Erling Smørgrav struct pfs_node *pn = pvd->pvd_pn;
9849733a808SDag-Erling Smørgrav struct uio *uio = va->a_uio;
985649ad985SDag-Erling Smørgrav struct proc *proc = NULL;
986388596dfSDag-Erling Smørgrav char buf[PATH_MAX];
9879733a808SDag-Erling Smørgrav struct sbuf sb;
988b00098d1SKonstantin Belousov int error, locked;
9899733a808SDag-Erling Smørgrav
990388596dfSDag-Erling Smørgrav PFS_TRACE(("%s", pn->pn_name));
991388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
99280a3cef8SDag-Erling Smørgrav
9939733a808SDag-Erling Smørgrav if (vn->v_type != VLNK)
9947d8f809fSDag-Erling Smørgrav PFS_RETURN (EINVAL);
99559fc1b06SDag-Erling Smørgrav KASSERT_PN_IS_LINK(pn);
9969733a808SDag-Erling Smørgrav
997388596dfSDag-Erling Smørgrav if (pn->pn_fill == NULL)
99818319000SDag-Erling Smørgrav PFS_RETURN (EIO);
99933802b9eSDag-Erling Smørgrav
1000649ad985SDag-Erling Smørgrav if (pvd->pvd_pid != NO_PID) {
1001649ad985SDag-Erling Smørgrav if ((proc = pfind(pvd->pvd_pid)) == NULL)
10027d8f809fSDag-Erling Smørgrav PFS_RETURN (EIO);
100306ad42b2SJohn Baldwin if (proc->p_flag & P_WEXIT) {
100406ad42b2SJohn Baldwin PROC_UNLOCK(proc);
100506ad42b2SJohn Baldwin PFS_RETURN (EIO);
100606ad42b2SJohn Baldwin }
1007649ad985SDag-Erling Smørgrav _PHOLD(proc);
1008649ad985SDag-Erling Smørgrav PROC_UNLOCK(proc);
1009649ad985SDag-Erling Smørgrav }
1010b00098d1SKonstantin Belousov vhold(vn);
1011b00098d1SKonstantin Belousov locked = VOP_ISLOCKED(vn);
1012b249ce48SMateusz Guzik VOP_UNLOCK(vn);
1013649ad985SDag-Erling Smørgrav
10149733a808SDag-Erling Smørgrav /* sbuf_new() can't fail with a static buffer */
10159733a808SDag-Erling Smørgrav sbuf_new(&sb, buf, sizeof buf, 0);
10169733a808SDag-Erling Smørgrav
1017388596dfSDag-Erling Smørgrav error = pn_fill(curthread, proc, pn, &sb, NULL);
1018649ad985SDag-Erling Smørgrav
1019649ad985SDag-Erling Smørgrav if (proc != NULL)
1020649ad985SDag-Erling Smørgrav PRELE(proc);
1021b00098d1SKonstantin Belousov vn_lock(vn, locked | LK_RETRY);
1022b00098d1SKonstantin Belousov vdrop(vn);
10239733a808SDag-Erling Smørgrav
1024b27acc8dSDag-Erling Smørgrav if (error) {
1025b27acc8dSDag-Erling Smørgrav sbuf_delete(&sb);
10267d8f809fSDag-Erling Smørgrav PFS_RETURN (error);
1027b27acc8dSDag-Erling Smørgrav }
1028b27acc8dSDag-Erling Smørgrav
10299cb24e3cSJaakko Heinonen if (sbuf_finish(&sb) != 0) {
10309cb24e3cSJaakko Heinonen sbuf_delete(&sb);
10319cb24e3cSJaakko Heinonen PFS_RETURN (ENAMETOOLONG);
10329cb24e3cSJaakko Heinonen }
10339cb24e3cSJaakko Heinonen
10348b7358caSJacques Vidrine error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
10359733a808SDag-Erling Smørgrav sbuf_delete(&sb);
10367d8f809fSDag-Erling Smørgrav PFS_RETURN (error);
10379733a808SDag-Erling Smørgrav }
10389733a808SDag-Erling Smørgrav
10399733a808SDag-Erling Smørgrav /*
10409733a808SDag-Erling Smørgrav * Reclaim a vnode
10419733a808SDag-Erling Smørgrav */
10429733a808SDag-Erling Smørgrav static int
pfs_reclaim(struct vop_reclaim_args * va)10439733a808SDag-Erling Smørgrav pfs_reclaim(struct vop_reclaim_args *va)
10449733a808SDag-Erling Smørgrav {
1045388596dfSDag-Erling Smørgrav struct vnode *vn = va->a_vp;
1046388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
1047388596dfSDag-Erling Smørgrav struct pfs_node *pn = pvd->pvd_pn;
1048388596dfSDag-Erling Smørgrav
1049388596dfSDag-Erling Smørgrav PFS_TRACE(("%s", pn->pn_name));
1050388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
1051198bc14bSDag-Erling Smørgrav
10529733a808SDag-Erling Smørgrav return (pfs_vncache_free(va->a_vp));
10539733a808SDag-Erling Smørgrav }
10549733a808SDag-Erling Smørgrav
10559733a808SDag-Erling Smørgrav /*
10569733a808SDag-Erling Smørgrav * Set attributes
10579733a808SDag-Erling Smørgrav */
10589733a808SDag-Erling Smørgrav static int
pfs_setattr(struct vop_setattr_args * va)10599733a808SDag-Erling Smørgrav pfs_setattr(struct vop_setattr_args *va)
10609733a808SDag-Erling Smørgrav {
1061388596dfSDag-Erling Smørgrav struct vnode *vn = va->a_vp;
1062388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
1063388596dfSDag-Erling Smørgrav struct pfs_node *pn = pvd->pvd_pn;
1064388596dfSDag-Erling Smørgrav
1065388596dfSDag-Erling Smørgrav PFS_TRACE(("%s", pn->pn_name));
1066388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
10677d8f809fSDag-Erling Smørgrav
10681e363d64SJohannes Lundberg /* Silently ignore unchangeable attributes. */
10691e363d64SJohannes Lundberg PFS_RETURN (0);
10709733a808SDag-Erling Smørgrav }
10719733a808SDag-Erling Smørgrav
10729733a808SDag-Erling Smørgrav /*
10734cd27a97SDag-Erling Smørgrav * Write to a file
10749733a808SDag-Erling Smørgrav */
10758712e867SDag-Erling Smørgrav static int
pfs_write(struct vop_write_args * va)1076aec0fb7bSPoul-Henning Kamp pfs_write(struct vop_write_args *va)
10778712e867SDag-Erling Smørgrav {
10788712e867SDag-Erling Smørgrav struct vnode *vn = va->a_vp;
1079388596dfSDag-Erling Smørgrav struct pfs_vdata *pvd = vn->v_data;
10808712e867SDag-Erling Smørgrav struct pfs_node *pn = pvd->pvd_pn;
10818712e867SDag-Erling Smørgrav struct uio *uio = va->a_uio;
1082f8e3eeb5SJohn Baldwin struct proc *proc;
108380a3cef8SDag-Erling Smørgrav struct sbuf sb;
10848712e867SDag-Erling Smørgrav int error;
10858712e867SDag-Erling Smørgrav
1086388596dfSDag-Erling Smørgrav PFS_TRACE(("%s", pn->pn_name));
1087388596dfSDag-Erling Smørgrav pfs_assert_not_owned(pn);
108880a3cef8SDag-Erling Smørgrav
10898712e867SDag-Erling Smørgrav if (vn->v_type != VREG)
10907d8f809fSDag-Erling Smørgrav PFS_RETURN (EINVAL);
109159fc1b06SDag-Erling Smørgrav KASSERT_PN_IS_FILE(pn);
10928712e867SDag-Erling Smørgrav
10937d8f809fSDag-Erling Smørgrav if (!(pn->pn_flags & PFS_WR))
10947d8f809fSDag-Erling Smørgrav PFS_RETURN (EBADF);
10958712e867SDag-Erling Smørgrav
1096388596dfSDag-Erling Smørgrav if (pn->pn_fill == NULL)
109718319000SDag-Erling Smørgrav PFS_RETURN (EIO);
109833802b9eSDag-Erling Smørgrav
10995edf7227SKonstantin Belousov if (uio->uio_resid > PFS_MAXBUFSIZ)
11005edf7227SKonstantin Belousov PFS_RETURN (EIO);
11015edf7227SKonstantin Belousov
1102198bc14bSDag-Erling Smørgrav /*
1103198bc14bSDag-Erling Smørgrav * This is necessary because either process' privileges may
1104198bc14bSDag-Erling Smørgrav * have changed since the open() call.
1105198bc14bSDag-Erling Smørgrav */
110653011553SMateusz Guzik if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
1107198bc14bSDag-Erling Smørgrav PFS_RETURN (EIO);
1108f8e3eeb5SJohn Baldwin if (proc != NULL) {
11098712e867SDag-Erling Smørgrav _PHOLD(proc);
11108712e867SDag-Erling Smørgrav PROC_UNLOCK(proc);
11118712e867SDag-Erling Smørgrav }
11128712e867SDag-Erling Smørgrav
11138712e867SDag-Erling Smørgrav if (pn->pn_flags & PFS_RAWWR) {
1114388596dfSDag-Erling Smørgrav error = pn_fill(curthread, proc, pn, NULL, uio);
11158712e867SDag-Erling Smørgrav if (proc != NULL)
11168712e867SDag-Erling Smørgrav PRELE(proc);
11177d8f809fSDag-Erling Smørgrav PFS_RETURN (error);
11188712e867SDag-Erling Smørgrav }
11198712e867SDag-Erling Smørgrav
112080a3cef8SDag-Erling Smørgrav sbuf_uionew(&sb, uio, &error);
1121388596dfSDag-Erling Smørgrav if (error) {
112280a3cef8SDag-Erling Smørgrav if (proc != NULL)
112380a3cef8SDag-Erling Smørgrav PRELE(proc);
1124388596dfSDag-Erling Smørgrav PFS_RETURN (error);
1125388596dfSDag-Erling Smørgrav }
1126388596dfSDag-Erling Smørgrav
1127388596dfSDag-Erling Smørgrav error = pn_fill(curthread, proc, pn, &sb, uio);
112880a3cef8SDag-Erling Smørgrav
112980a3cef8SDag-Erling Smørgrav sbuf_delete(&sb);
1130388596dfSDag-Erling Smørgrav if (proc != NULL)
1131388596dfSDag-Erling Smørgrav PRELE(proc);
11327d8f809fSDag-Erling Smørgrav PFS_RETURN (error);
11338712e867SDag-Erling Smørgrav }
11348712e867SDag-Erling Smørgrav
11358712e867SDag-Erling Smørgrav /*
11369733a808SDag-Erling Smørgrav * Vnode operations
11379733a808SDag-Erling Smørgrav */
1138aec0fb7bSPoul-Henning Kamp struct vop_vector pfs_vnodeops = {
1139aec0fb7bSPoul-Henning Kamp .vop_default = &default_vnodeops,
114083c64397SPoul-Henning Kamp
1141aec0fb7bSPoul-Henning Kamp .vop_access = pfs_access,
11420e3b5c73SDag-Erling Smørgrav .vop_cachedlookup = pfs_lookup,
1143aec0fb7bSPoul-Henning Kamp .vop_close = pfs_close,
1144aec0fb7bSPoul-Henning Kamp .vop_create = VOP_EOPNOTSUPP,
1145aec0fb7bSPoul-Henning Kamp .vop_getattr = pfs_getattr,
1146aec0fb7bSPoul-Henning Kamp .vop_getextattr = pfs_getextattr,
1147aec0fb7bSPoul-Henning Kamp .vop_ioctl = pfs_ioctl,
1148aec0fb7bSPoul-Henning Kamp .vop_link = VOP_EOPNOTSUPP,
11490e3b5c73SDag-Erling Smørgrav .vop_lookup = vfs_cache_lookup,
1150aec0fb7bSPoul-Henning Kamp .vop_mkdir = VOP_EOPNOTSUPP,
1151aec0fb7bSPoul-Henning Kamp .vop_mknod = VOP_EOPNOTSUPP,
1152aec0fb7bSPoul-Henning Kamp .vop_open = pfs_open,
1153aec0fb7bSPoul-Henning Kamp .vop_read = pfs_read,
1154aec0fb7bSPoul-Henning Kamp .vop_readdir = pfs_readdir,
1155aec0fb7bSPoul-Henning Kamp .vop_readlink = pfs_readlink,
1156aec0fb7bSPoul-Henning Kamp .vop_reclaim = pfs_reclaim,
1157aec0fb7bSPoul-Henning Kamp .vop_remove = VOP_EOPNOTSUPP,
1158aec0fb7bSPoul-Henning Kamp .vop_rename = VOP_EOPNOTSUPP,
1159aec0fb7bSPoul-Henning Kamp .vop_rmdir = VOP_EOPNOTSUPP,
1160aec0fb7bSPoul-Henning Kamp .vop_setattr = pfs_setattr,
1161aec0fb7bSPoul-Henning Kamp .vop_symlink = VOP_EOPNOTSUPP,
1162e7f54c1bSJoe Marcus Clarke .vop_vptocnp = pfs_vptocnp,
1163aec0fb7bSPoul-Henning Kamp .vop_write = pfs_write,
11643ffcfa59SMateusz Guzik .vop_add_writecount = vop_stdadd_writecount_nomsync,
1165aec0fb7bSPoul-Henning Kamp /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */
11669733a808SDag-Erling Smørgrav };
11676fa079fcSMateusz Guzik VFS_VOP_VECTOR_REGISTER(pfs_vnodeops);
1168